diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGCameraController.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGCameraController.h index 1841ea47ba..9f91255ed0 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGCameraController.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGCameraController.h @@ -46,14 +46,13 @@ typedef enum { @property (nonatomic, strong) id stickersContext; @property (nonatomic, assign) bool shortcut; -@property (nonatomic, strong) NSString *forcedCaption; -@property (nonatomic, strong) NSArray *forcedEntities; +@property (nonatomic, strong) NSAttributedString *forcedCaption; @property (nonatomic, strong) NSString *recipientName; @property (nonatomic, copy) void(^finishedWithResults)(TGOverlayController *controller, TGMediaSelectionContext *selectionContext, TGMediaEditingContext *editingContext, id currentItem, bool silentPosting, int32_t scheduleTime); -@property (nonatomic, copy) void(^finishedWithPhoto)(TGOverlayController *controller, UIImage *resultImage, NSString *caption, NSArray *entities, NSArray *stickers, NSNumber *timer); -@property (nonatomic, copy) void(^finishedWithVideo)(TGOverlayController *controller, NSURL *videoURL, UIImage *previewImage, NSTimeInterval duration, CGSize dimensions, TGVideoEditAdjustments *adjustments, NSString *caption, NSArray *entities, NSArray *stickers, NSNumber *timer); +@property (nonatomic, copy) void(^finishedWithPhoto)(TGOverlayController *controller, UIImage *resultImage, NSAttributedString *caption, NSArray *stickers, NSNumber *timer); +@property (nonatomic, copy) void(^finishedWithVideo)(TGOverlayController *controller, NSURL *videoURL, UIImage *previewImage, NSTimeInterval duration, CGSize dimensions, TGVideoEditAdjustments *adjustments, NSAttributedString *caption, NSArray *stickers, NSNumber *timer); @property (nonatomic, copy) void(^recognizedQRCode)(NSString *code); @@ -68,7 +67,7 @@ typedef enum { - (instancetype)initWithContext:(id)context saveEditedPhotos:(bool)saveEditedPhotos saveCapturedMedia:(bool)saveCapturedMedia intent:(TGCameraControllerIntent)intent; - (instancetype)initWithContext:(id)context saveEditedPhotos:(bool)saveEditedPhotos saveCapturedMedia:(bool)saveCapturedMedia camera:(PGCamera *)camera previewView:(TGCameraPreviewView *)previewView intent:(TGCameraControllerIntent)intent; -+ (NSArray *)resultSignalsForSelectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext currentItem:(id)currentItem storeAssets:(bool)storeAssets saveEditedPhotos:(bool)saveEditedPhotos descriptionGenerator:(id (^)(id, NSString *, NSArray *, NSString *))descriptionGenerator; ++ (NSArray *)resultSignalsForSelectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext currentItem:(id)currentItem storeAssets:(bool)storeAssets saveEditedPhotos:(bool)saveEditedPhotos descriptionGenerator:(id (^)(id, NSAttributedString *, NSString *))descriptionGenerator; - (void)beginTransitionInFromRect:(CGRect)rect; - (void)_dismissTransitionForResultController:(TGOverlayController *)resultController; diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGClipboardMenu.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGClipboardMenu.h index 57e5a6f90e..bca64ebf1f 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGClipboardMenu.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGClipboardMenu.h @@ -16,6 +16,7 @@ + (TGMenuSheetController *)presentInParentController:(TGViewController *)parentController context:(id)context images:(NSArray *)images allowGrouping:(bool)allowGrouping hasCaption:(bool)hasCaption hasTimer:(bool)hasTimer hasSilentPosting:(bool)hasSilentPosting hasSchedule:(bool)hasSchedule reminder:(bool)reminder recipientName:(NSString *)recipientName suggestionContext:(TGSuggestionContext *)suggestionContext stickersContext:(id)stickersContext presentScheduleController:(void (^)(void(^)(int32_t)))presentScheduleController presentTimerController:(void (^)(void(^)(int32_t)))presentTimerController completed:(void (^)(TGMediaSelectionContext *selectionContext, TGMediaEditingContext *editingContext, id currentItem, bool silentPosting, int32_t scheduleTime))completed dismissed:(void (^)(void))dismissed sourceView:(UIView *)sourceView sourceRect:(CGRect (^)(void))sourceRect; -+ (NSArray *)resultSignalsForSelectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext currentItem:(id)currentItem descriptionGenerator:(id (^)(id, NSString *, NSArray *, NSString *))descriptionGenerator; ++ (NSArray *)resultSignalsForSelectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext currentItem:(id)currentItem descriptionGenerator:(id (^)(id, NSAttributedString *, + NSString *))descriptionGenerator; @end diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaAssetsController.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaAssetsController.h index 91658ad331..82c3375396 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaAssetsController.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaAssetsController.h @@ -74,7 +74,7 @@ typedef enum @property (nonatomic, strong) NSString *recipientName; -@property (nonatomic, copy) NSDictionary *(^descriptionGenerator)(id, NSString *, NSArray *, NSString *, NSString *); +@property (nonatomic, copy) NSDictionary *(^descriptionGenerator)(id, NSAttributedString *, NSString *, NSString *); @property (nonatomic, copy) void (^avatarCompletionBlock)(UIImage *image); @property (nonatomic, copy) void (^completionBlock)(NSArray *signals, bool silentPosting, int32_t scheduleTime); @property (nonatomic, copy) void (^avatarVideoCompletionBlock)(UIImage *image, AVAsset *asset, TGVideoEditAdjustments *adjustments); @@ -92,7 +92,7 @@ typedef enum - (UIBarButtonItem *)rightBarButtonItem; -- (NSArray *)resultSignalsWithCurrentItem:(TGMediaAsset *)currentItem descriptionGenerator:(id (^)(id, NSString *, NSArray *, NSString *, NSString *))descriptionGenerator; +- (NSArray *)resultSignalsWithCurrentItem:(TGMediaAsset *)currentItem descriptionGenerator:(id (^)(id, NSAttributedString *, NSString *, NSString *))descriptionGenerator; - (void)completeWithAvatarImage:(UIImage *)image; - (void)completeWithAvatarVideo:(id)asset adjustments:(TGVideoEditAdjustments *)adjustments image:(UIImage *)image; @@ -105,6 +105,6 @@ typedef enum + (TGMediaAssetType)assetTypeForIntent:(TGMediaAssetsControllerIntent)intent; -+ (NSArray *)resultSignalsForSelectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext intent:(TGMediaAssetsControllerIntent)intent currentItem:(TGMediaAsset *)currentItem storeAssets:(bool)storeAssets convertToJpeg:(bool)convertToJpeg descriptionGenerator:(id (^)(id, NSString *, NSArray *, NSString *, NSString *))descriptionGenerator saveEditedPhotos:(bool)saveEditedPhotos; ++ (NSArray *)resultSignalsForSelectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext intent:(TGMediaAssetsControllerIntent)intent currentItem:(TGMediaAsset *)currentItem storeAssets:(bool)storeAssets convertToJpeg:(bool)convertToJpeg descriptionGenerator:(id (^)(id, NSAttributedString *, NSString *, NSString *))descriptionGenerator saveEditedPhotos:(bool)saveEditedPhotos; @end diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaEditingContext.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaEditingContext.h index bb8cefb64f..a23046d7a2 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaEditingContext.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaEditingContext.h @@ -62,14 +62,13 @@ - (SSignal *)fullSizeImageUrlForItem:(id)item; -- (NSString *)captionForItem:(NSObject *)item; -- (NSArray *)entitiesForItem:(NSObject *)item; +- (NSAttributedString *)captionForItem:(NSObject *)item; - (SSignal *)captionSignalForItem:(NSObject *)item; -- (void)setCaption:(NSString *)caption entities:(NSArray *)entities forItem:(NSObject *)item; +- (void)setCaption:(NSAttributedString *)caption forItem:(NSObject *)item; - (bool)isForcedCaption; -- (void)setForcedCaption:(NSString *)caption entities:(NSArray *)entities; +- (void)setForcedCaption:(NSAttributedString *)caption; - (NSObject *)adjustmentsForItem:(NSObject *)item; - (SSignal *)adjustmentsSignalForItem:(NSObject *)item; diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaPickerGalleryInterfaceView.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaPickerGalleryInterfaceView.h index 8c9bd087fe..3d972bd283 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaPickerGalleryInterfaceView.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaPickerGalleryInterfaceView.h @@ -5,6 +5,7 @@ #import +@protocol TGPhotoPaintStickersContext; @class TGMediaSelectionContext; @class TGMediaEditingContext; @class TGSuggestionContext; @@ -12,7 +13,7 @@ @interface TGMediaPickerGalleryInterfaceView : UIView -@property (nonatomic, copy) void (^captionSet)(id, NSString *, NSArray *); +@property (nonatomic, copy) void (^captionSet)(id, NSAttributedString *); @property (nonatomic, copy) void (^donePressed)(id); @property (nonatomic, copy) void (^doneLongPressed)(id); @@ -37,7 +38,7 @@ @property (nonatomic, readonly) UIView *timerButton; -- (instancetype)initWithContext:(id)context focusItem:(id)focusItem selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext hasSelectionPanel:(bool)hasSelectionPanel hasCameraButton:(bool)hasCameraButton recipientName:(NSString *)recipientName; +- (instancetype)initWithContext:(id)context focusItem:(id)focusItem selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext stickersContext:(id)stickersContext hasSelectionPanel:(bool)hasSelectionPanel hasCameraButton:(bool)hasCameraButton recipientName:(NSString *)recipientName; - (void)setSelectedItemsModel:(TGMediaPickerGallerySelectedItemsModel *)selectedItemsModel; - (void)setEditorTabPressed:(void (^)(TGPhotoEditorTab tab))editorTabPressed; diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaPickerGalleryModel.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaPickerGalleryModel.h index b127c421e4..3339a6dda2 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaPickerGalleryModel.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaPickerGalleryModel.h @@ -25,7 +25,7 @@ @property (nonatomic, copy) void (^didFinishEditingItem)(iditem, id adjustments, UIImage *resultImage, UIImage *thumbnailImage); @property (nonatomic, copy) void (^didFinishRenderingFullSizeImage)(id item, UIImage *fullSizeImage); -@property (nonatomic, copy) void (^saveItemCaption)(id item, NSString *caption, NSArray *entities); +@property (nonatomic, copy) void (^saveItemCaption)(id item, NSAttributedString *caption); @property (nonatomic, copy) void (^storeOriginalImageForItem)(id item, UIImage *originalImage); diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoCaptionInputMixin.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoCaptionInputMixin.h index 0f7dd6f6fe..283c719fd4 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoCaptionInputMixin.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoCaptionInputMixin.h @@ -2,11 +2,14 @@ #import @class TGSuggestionContext; -@class TGKeyCommandController; +@protocol TGPhotoPaintStickersContext; +@protocol TGCaptionPanelView; @interface TGPhotoCaptionInputMixin : NSObject -@property (nonatomic, readonly) TGMediaPickerCaptionInputPanel *inputPanel; +@property (nonatomic, strong) id stickersContext; +@property (nonatomic, readonly) id inputPanel; +@property (nonatomic, readonly) UIView *inputPanelView; @property (nonatomic, readonly) UIView *dismissView; @property (nonatomic, assign) UIInterfaceOrientation interfaceOrientation; @@ -19,19 +22,17 @@ @property (nonatomic, copy) UIView *(^panelParentView)(void); @property (nonatomic, copy) void (^panelFocused)(void); -@property (nonatomic, copy) void (^finishedWithCaption)(NSString *caption, NSArray *entities); +@property (nonatomic, copy) void (^finishedWithCaption)(NSAttributedString *caption); @property (nonatomic, copy) void (^keyboardHeightChanged)(CGFloat keyboardHeight, NSTimeInterval duration, NSInteger animationCurve); -- (instancetype)initWithKeyCommandController:(TGKeyCommandController *)keyCommandController; - - (void)createInputPanelIfNeeded; - (void)beginEditing; - (void)enableDismissal; - (void)destroy; -@property (nonatomic, strong) NSString *caption; -- (void)setCaption:(NSString *)caption entities:(NSArray *)entities animated:(bool)animated; +@property (nonatomic, strong) NSAttributedString *caption; +- (void)setCaption:(NSAttributedString *)caption animated:(bool)animated; - (void)setCaptionPanelHidden:(bool)hidden animated:(bool)animated; diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoEditorController.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoEditorController.h index a9f491c4cb..3235543022 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoEditorController.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoEditorController.h @@ -48,7 +48,7 @@ typedef enum { @property (nonatomic, copy) UIImage *(^requestImage)(void); @property (nonatomic, copy) void (^requestToolbarsHidden)(bool hidden, bool animated); -@property (nonatomic, copy) void (^captionSet)(NSString *caption, NSArray *entities); +@property (nonatomic, copy) void (^captionSet)(NSAttributedString *caption); @property (nonatomic, copy) void (^willFinishEditing)(id adjustments, id temporaryRep, bool hasChanges); @property (nonatomic, copy) void (^didFinishRenderingFullSizeImage)(UIImage *fullSizeImage); diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoPaintStickersContext.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoPaintStickersContext.h index 529d893be3..e5b85054ff 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoPaintStickersContext.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoPaintStickersContext.h @@ -35,6 +35,22 @@ @end +@protocol TGCaptionPanelView + +@property (nonatomic, readonly) UIView *view; + +- (void)setCaption:(NSAttributedString *)caption; +- (void)dismissInput; + +@property (nonatomic, copy) void(^sendPressed)(NSAttributedString *string); +@property (nonatomic, copy) void(^focusUpdated)(BOOL focused); +@property (nonatomic, copy) void(^heightUpdated)(BOOL animated); + +- (CGFloat)updateLayoutSize:(CGSize)size sideInset:(CGFloat)sideInset; +- (CGFloat)baseHeight; + +@end + @protocol TGPhotoPaintStickersContext - (int64_t)documentIdForDocument:(id)document; @@ -44,4 +60,6 @@ @property (nonatomic, copy) id(^presentStickersController)(void(^)(id, bool, UIView *, CGRect)); +@property (nonatomic, copy) id(^captionPanelView)(void); + @end diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoVideoEditor.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoVideoEditor.h index 5db73d5a2b..f1012f7edd 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoVideoEditor.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoVideoEditor.h @@ -4,6 +4,6 @@ + (void)presentWithContext:(id)context parentController:(TGViewController *)parentController image:(UIImage *)image video:(NSURL *)video didFinishWithImage:(void (^)(UIImage *image))didFinishWithImage didFinishWithVideo:(void (^)(UIImage *image, NSURL *url, TGVideoEditAdjustments *adjustments))didFinishWithVideo dismissed:(void (^)(void))dismissed; -+ (void)presentWithContext:(id)context controller:(TGViewController *)controller caption:(NSString *)caption entities:(NSArray *)entities withItem:(id)item paint:(bool)paint recipientName:(NSString *)recipientName stickersContext:(id)stickersContext snapshots:(NSArray *)snapshots immediate:(bool)immediate appeared:(void (^)(void))appeared completion:(void (^)(id, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed; ++ (void)presentWithContext:(id)context controller:(TGViewController *)controller caption:(NSAttributedString *)caption withItem:(id)item paint:(bool)paint recipientName:(NSString *)recipientName stickersContext:(id)stickersContext snapshots:(NSArray *)snapshots immediate:(bool)immediate appeared:(void (^)(void))appeared completion:(void (^)(id, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed; @end diff --git a/submodules/LegacyComponents/Sources/TGCameraController.m b/submodules/LegacyComponents/Sources/TGCameraController.m index 811813ec86..8e6f3bdd73 100644 --- a/submodules/LegacyComponents/Sources/TGCameraController.m +++ b/submodules/LegacyComponents/Sources/TGCameraController.m @@ -1439,7 +1439,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus { editingContext = [[TGMediaEditingContext alloc] init]; if (self.forcedCaption != nil) - [editingContext setForcedCaption:self.forcedCaption entities:self.forcedEntities]; + [editingContext setForcedCaption:self.forcedCaption]; _editingContext = editingContext; _interfaceView.editingContext = editingContext; } @@ -1711,11 +1711,11 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus [editingContext setImage:resultImage thumbnailImage:thumbnailImage forItem:editableItem synchronous:false]; }; - model.saveItemCaption = ^(id editableItem, NSString *caption, NSArray *entities) + model.saveItemCaption = ^(id editableItem, NSAttributedString *caption) { __strong TGCameraController *strongSelf = weakSelf; if (strongSelf != nil) - [strongSelf->_editingContext setCaption:caption entities:entities forItem:editableItem]; + [strongSelf->_editingContext setCaption:caption forItem:editableItem]; }; model.interfaceView.hasSwipeGesture = false; @@ -2048,10 +2048,10 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus } if (strongSelf.finishedWithVideo != nil) - strongSelf.finishedWithVideo(nil, [NSURL fileURLWithPath:filePath], previewImage, 0, CGSizeZero, adjustments, nil, nil, nil, nil); + strongSelf.finishedWithVideo(nil, [NSURL fileURLWithPath:filePath], previewImage, 0, CGSizeZero, adjustments, nil, nil, nil); } else { if (strongSelf.finishedWithPhoto != nil) - strongSelf.finishedWithPhoto(nil, resultImage, nil, nil, nil, nil); + strongSelf.finishedWithPhoto(nil, resultImage, nil, nil, nil); } if (strongSelf.shouldStoreCapturedAssets && [input isKindOfClass:[UIImage class]]) @@ -2079,7 +2079,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus TGDispatchOnMainThread(^ { if (strongSelf.finishedWithVideo != nil) - strongSelf.finishedWithVideo(nil, [(AVURLAsset *)asset URL], resultImage, 0, CGSizeZero, adjustments, nil, nil, nil, nil); + strongSelf.finishedWithVideo(nil, [(AVURLAsset *)asset URL], resultImage, 0, CGSizeZero, adjustments, nil, nil, nil); __strong TGPhotoEditorController *strongController = weakController; if (strongController != nil) @@ -2760,7 +2760,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus } } -+ (NSArray *)resultSignalsForSelectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext currentItem:(id)currentItem storeAssets:(bool)storeAssets saveEditedPhotos:(bool)saveEditedPhotos descriptionGenerator:(id (^)(id, NSString *, NSArray *, NSString *))descriptionGenerator ++ (NSArray *)resultSignalsForSelectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext currentItem:(id)currentItem storeAssets:(bool)storeAssets saveEditedPhotos:(bool)saveEditedPhotos descriptionGenerator:(id (^)(id, NSAttributedString *, NSString *))descriptionGenerator { NSMutableArray *signals = [[NSMutableArray alloc] init]; NSMutableArray *selectedItems = selectionContext.selectedItems != nil ? [selectionContext.selectedItems mutableCopy] : [[NSMutableArray alloc] init]; @@ -2887,8 +2887,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus { if ([asset isKindOfClass:[TGCameraCapturedPhoto class]]) { - NSString *caption = [editingContext captionForItem:asset]; - NSArray *entities = [editingContext entitiesForItem:asset]; + NSAttributedString *caption = [editingContext captionForItem:asset]; id adjustments = [editingContext adjustmentsForItem:asset]; NSNumber *timer = [editingContext timerForItem:asset]; @@ -2908,7 +2907,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus dict[@"caption"] = caption; return dict; } else { - id generatedItem = descriptionGenerator(dict, caption, entities, nil); + id generatedItem = descriptionGenerator(dict, caption, nil); return generatedItem; } }]; @@ -2994,7 +2993,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus dict[@"caption"] = caption; return dict; } else { - id generatedItem = descriptionGenerator(dict, caption, entities, nil); + id generatedItem = descriptionGenerator(dict, caption, nil); return generatedItem; } }] catch:^SSignal *(__unused id error) @@ -3011,8 +3010,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus TGCameraCapturedVideo *video = (TGCameraCapturedVideo *)asset; TGVideoEditAdjustments *adjustments = (TGVideoEditAdjustments *)[editingContext adjustmentsForItem:asset]; - NSString *caption = [editingContext captionForItem:asset]; - NSArray *entities = [editingContext entitiesForItem:asset]; + NSAttributedString *caption = [editingContext captionForItem:asset]; NSNumber *timer = [editingContext timerForItem:asset]; UIImage *(^cropVideoThumbnail)(UIImage *, CGSize, CGSize, bool) = ^UIImage *(UIImage *image, CGSize targetSize, CGSize sourceSize, bool resize) @@ -3070,7 +3068,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus else if (groupedId != nil && !hasAnyTimers) dict[@"groupedId"] = groupedId; - id generatedItem = descriptionGenerator(dict, caption, entities, nil); + id generatedItem = descriptionGenerator(dict, caption, nil); return generatedItem; }]; }]]; @@ -3126,7 +3124,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus dict[@"fileName"] = @"Document Scan.pdf"; dict[@"mimeType"] = @"application/pdf"; - id generatedItem = descriptionGenerator(dict, dict[@"caption"], nil, nil); + id generatedItem = descriptionGenerator(dict, dict[@"caption"], nil); return generatedItem; }]; signals = [NSMutableArray arrayWithObject:scanSignal]; diff --git a/submodules/LegacyComponents/Sources/TGClipboardGalleryMixin.m b/submodules/LegacyComponents/Sources/TGClipboardGalleryMixin.m index f0881f4d1d..4019384590 100644 --- a/submodules/LegacyComponents/Sources/TGClipboardGalleryMixin.m +++ b/submodules/LegacyComponents/Sources/TGClipboardGalleryMixin.m @@ -95,9 +95,9 @@ [editingContext setFullSizeImage:resultImage forItem:editableItem]; }; - model.saveItemCaption = ^(id editableItem, NSString *caption, NSArray *entities) + model.saveItemCaption = ^(id editableItem, NSAttributedString *caption) { - [editingContext setCaption:caption entities:entities forItem:editableItem]; + [editingContext setCaption:caption forItem:editableItem]; if (selectionContext != nil && caption.length > 0 && [editableItem conformsToProtocol:@protocol(TGMediaSelectableItem)]) [selectionContext setItem:(id)editableItem selected:true]; diff --git a/submodules/LegacyComponents/Sources/TGClipboardGalleryModel.h b/submodules/LegacyComponents/Sources/TGClipboardGalleryModel.h index 5a29e24ce2..17f9947efd 100644 --- a/submodules/LegacyComponents/Sources/TGClipboardGalleryModel.h +++ b/submodules/LegacyComponents/Sources/TGClipboardGalleryModel.h @@ -13,7 +13,7 @@ @property (nonatomic, copy) void (^didFinishEditingItem)(iditem, id adjustments, UIImage *resultImage, UIImage *thumbnailImage); @property (nonatomic, copy) void (^didFinishRenderingFullSizeImage)(id item, UIImage *fullSizeImage); -@property (nonatomic, copy) void (^saveItemCaption)(id item, NSString *caption, NSArray *entities); +@property (nonatomic, copy) void (^saveItemCaption)(id item, NSAttributedString *caption); @property (nonatomic, copy) void (^editorOpened)(void); @property (nonatomic, copy) void (^editorClosed)(void); diff --git a/submodules/LegacyComponents/Sources/TGClipboardGalleryModel.m b/submodules/LegacyComponents/Sources/TGClipboardGalleryModel.m index 4bd5a518f6..a66273db3a 100644 --- a/submodules/LegacyComponents/Sources/TGClipboardGalleryModel.m +++ b/submodules/LegacyComponents/Sources/TGClipboardGalleryModel.m @@ -79,7 +79,7 @@ }; } - _interfaceView = [[TGMediaPickerGalleryInterfaceView alloc] initWithContext:_context focusItem:focusItem selectionContext:selectionContext editingContext:editingContext hasSelectionPanel:hasSelectionPanel hasCameraButton:false recipientName:recipientName]; + _interfaceView = [[TGMediaPickerGalleryInterfaceView alloc] initWithContext:_context focusItem:focusItem selectionContext:selectionContext editingContext:editingContext stickersContext:stickersContext hasSelectionPanel:hasSelectionPanel hasCameraButton:false recipientName:recipientName]; _interfaceView.hasCaptions = hasCaptions; _interfaceView.hasTimer = hasTimer; [_interfaceView setEditorTabPressed:^(TGPhotoEditorTab tab) @@ -100,7 +100,7 @@ [strongSelf setCurrentItemWithIndex:index]; }; - _interfaceView.captionSet = ^(id item, NSString *caption, NSArray *entities) + _interfaceView.captionSet = ^(id item, NSAttributedString *caption) { __strong TGClipboardGalleryModel *strongSelf = weakSelf; if (strongSelf == nil || strongSelf.saveItemCaption == nil) @@ -108,7 +108,7 @@ __strong TGModernGalleryController *controller = strongSelf.controller; if ([controller.currentItem conformsToProtocol:@protocol(TGModernGalleryEditableItem)]) - strongSelf.saveItemCaption(((id)item).editableMediaItem, caption, entities); + strongSelf.saveItemCaption(((id)item).editableMediaItem, caption); }; _interfaceView.timerRequested = ^ { @@ -370,14 +370,14 @@ strongSelf.didFinishRenderingFullSizeImage(item.editableMediaItem, image); }; - controller.captionSet = ^(NSString *caption, NSArray *entities) + controller.captionSet = ^(NSAttributedString *caption) { __strong TGClipboardGalleryModel *strongSelf = weakSelf; if (strongSelf == nil) return; if (strongSelf.saveItemCaption != nil) - strongSelf.saveItemCaption(item.editableMediaItem, caption, entities); + strongSelf.saveItemCaption(item.editableMediaItem, caption); }; controller.requestToolbarsHidden = ^(bool hidden, bool animated) diff --git a/submodules/LegacyComponents/Sources/TGClipboardMenu.m b/submodules/LegacyComponents/Sources/TGClipboardMenu.m index edbe93514f..32ab5101dc 100644 --- a/submodules/LegacyComponents/Sources/TGClipboardMenu.m +++ b/submodules/LegacyComponents/Sources/TGClipboardMenu.m @@ -116,7 +116,7 @@ return value; } -+ (NSArray *)resultSignalsForSelectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext currentItem:(id)currentItem descriptionGenerator:(id (^)(id, NSString *, NSArray *, NSString *))descriptionGenerator ++ (NSArray *)resultSignalsForSelectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext currentItem:(id)currentItem descriptionGenerator:(id (^)(id, NSAttributedString *, NSString *))descriptionGenerator { NSMutableArray *signals = [[NSMutableArray alloc] init]; NSMutableArray *selectedItems = [selectionContext.selectedItems mutableCopy]; @@ -143,8 +143,7 @@ for (UIImage *asset in selectedItems) { - NSString *caption = [editingContext captionForItem:asset]; - NSArray *entities = [editingContext entitiesForItem:asset]; + NSAttributedString *caption = [editingContext captionForItem:asset]; id adjustments = [editingContext adjustmentsForItem:asset]; NSNumber *timer = [editingContext timerForItem:asset]; @@ -160,7 +159,7 @@ if (groupedId != nil) dict[@"groupedId"] = groupedId; - id generatedItem = descriptionGenerator(dict, caption, entities, nil); + id generatedItem = descriptionGenerator(dict, caption, nil); return generatedItem; }]; @@ -207,7 +206,7 @@ if (groupedId != nil) dict[@"groupedId"] = groupedId; - id generatedItem = descriptionGenerator(dict, caption, entities, nil); + id generatedItem = descriptionGenerator(dict, caption, nil); return generatedItem; }] catch:^SSignal *(__unused id error) { diff --git a/submodules/LegacyComponents/Sources/TGMediaAssetsController.m b/submodules/LegacyComponents/Sources/TGMediaAssetsController.m index 5869e53eb2..a46eaaf720 100644 --- a/submodules/LegacyComponents/Sources/TGMediaAssetsController.m +++ b/submodules/LegacyComponents/Sources/TGMediaAssetsController.m @@ -826,7 +826,7 @@ } } -- (NSArray *)resultSignalsWithCurrentItem:(TGMediaAsset *)currentItem descriptionGenerator:(id (^)(id, NSString *, NSArray *, NSString *, NSString *))descriptionGenerator +- (NSArray *)resultSignalsWithCurrentItem:(TGMediaAsset *)currentItem descriptionGenerator:(id (^)(id, NSAttributedString *, NSString *, NSString *))descriptionGenerator { bool storeAssets = (_editingContext != nil) && self.shouldStoreAssets; @@ -843,7 +843,7 @@ return value; } -+ (NSArray *)resultSignalsForSelectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext intent:(TGMediaAssetsControllerIntent)intent currentItem:(TGMediaAsset *)currentItem storeAssets:(bool)storeAssets convertToJpeg:(bool)convertToJpeg descriptionGenerator:(id (^)(id, NSString *, NSArray *, NSString *, NSString *))descriptionGenerator saveEditedPhotos:(bool)saveEditedPhotos ++ (NSArray *)resultSignalsForSelectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext intent:(TGMediaAssetsControllerIntent)intent currentItem:(TGMediaAsset *)currentItem storeAssets:(bool)storeAssets convertToJpeg:(bool)convertToJpeg descriptionGenerator:(id (^)(id, NSAttributedString *, NSString *, NSString *))descriptionGenerator saveEditedPhotos:(bool)saveEditedPhotos { NSMutableArray *signals = [[NSMutableArray alloc] init]; NSMutableArray *selectedItems = selectionContext.selectedItems ? [selectionContext.selectedItems mutableCopy] : [[NSMutableArray alloc] init]; @@ -939,12 +939,10 @@ asset = ((TGCameraCapturedVideo *)asset).originalAsset; } - NSString *caption = [editingContext captionForItem:asset]; - NSArray *entities = [editingContext entitiesForItem:asset]; + NSAttributedString *caption = [editingContext captionForItem:asset]; if (editingContext.isForcedCaption && num > 0) { caption = nil; - entities = nil; } switch (asset.type) @@ -967,7 +965,7 @@ if (groupedId != nil) dict[@"groupedId"] = groupedId; - id generatedItem = descriptionGenerator(dict, caption, entities, nil, asset.identifier); + id generatedItem = descriptionGenerator(dict, caption, nil, asset.identifier); return generatedItem; }] catch:^SSignal *(id error) { @@ -993,7 +991,7 @@ if (groupedId != nil) dict[@"groupedId"] = groupedId; - id generatedItem = descriptionGenerator(dict, caption, entities, nil, asset.identifier); + id generatedItem = descriptionGenerator(dict, caption, nil, asset.identifier); return generatedItem; }]; }]]; @@ -1019,7 +1017,7 @@ else if (groupedId != nil && !hasAnyTimers) dict[@"groupedId"] = groupedId; - id generatedItem = descriptionGenerator(dict, caption, entities, nil, asset.identifier); + id generatedItem = descriptionGenerator(dict, caption, nil, asset.identifier); return generatedItem; }]; @@ -1095,7 +1093,7 @@ else if (groupedId != nil && !hasAnyTimers) dict[@"groupedId"] = groupedId; - id generatedItem = descriptionGenerator(dict, caption, entities, nil, asset.identifier); + id generatedItem = descriptionGenerator(dict, caption, nil, asset.identifier); return generatedItem; }]; }]]; @@ -1178,7 +1176,7 @@ else if (groupedId != nil && !hasAnyTimers) dict[@"groupedId"] = groupedId; - id generatedItem = descriptionGenerator(dict, caption, entities, nil, asset.identifier); + id generatedItem = descriptionGenerator(dict, caption, nil, asset.identifier); return generatedItem; }] catch:^SSignal *(__unused id error) { @@ -1218,7 +1216,7 @@ if (groupedId != nil) dict[@"groupedId"] = groupedId; - id generatedItem = descriptionGenerator(dict, caption, entities, nil, asset.identifier); + id generatedItem = descriptionGenerator(dict, caption, nil, asset.identifier); return generatedItem; }]]; @@ -1287,7 +1285,7 @@ else if (groupedId != nil && !hasAnyTimers) dict[@"groupedId"] = groupedId; - id generatedItem = descriptionGenerator(dict, caption, entities, nil, asset.identifier); + id generatedItem = descriptionGenerator(dict, caption, nil, asset.identifier); return generatedItem; }]]; @@ -1364,7 +1362,7 @@ if (timer != nil) dict[@"timer"] = timer; - id generatedItem = descriptionGenerator(dict, caption, entities, nil, asset.identifier); + id generatedItem = descriptionGenerator(dict, caption, nil, asset.identifier); return generatedItem; }]]; diff --git a/submodules/LegacyComponents/Sources/TGMediaAvatarMenuMixin.m b/submodules/LegacyComponents/Sources/TGMediaAvatarMenuMixin.m index 191aac1ce9..a7d33bf0ff 100644 --- a/submodules/LegacyComponents/Sources/TGMediaAvatarMenuMixin.m +++ b/submodules/LegacyComponents/Sources/TGMediaAvatarMenuMixin.m @@ -340,7 +340,7 @@ [strongCameraView attachPreviewViewAnimated:true]; }; - controller.finishedWithPhoto = ^(__unused TGOverlayController *controller, UIImage *resultImage, __unused NSString *caption, __unused NSArray *entities, __unused NSArray *stickers, __unused NSNumber *timer) + controller.finishedWithPhoto = ^(__unused TGOverlayController *controller, UIImage *resultImage, __unused NSAttributedString *caption, __unused NSArray *stickers, __unused NSNumber *timer) { __strong TGMediaAvatarMenuMixin *strongSelf = weakSelf; if (strongSelf == nil) @@ -352,7 +352,7 @@ [menuController dismissAnimated:false]; }; - controller.finishedWithVideo = ^(__unused TGOverlayController *controller, NSURL *url, UIImage *previewImage, __unused NSTimeInterval duration, __unused CGSize dimensions, TGVideoEditAdjustments *adjustments, __unused NSString *caption, __unused NSArray *entities, __unused NSArray *stickers, __unused NSNumber *timer){ + controller.finishedWithVideo = ^(__unused TGOverlayController *controller, NSURL *url, UIImage *previewImage, __unused NSTimeInterval duration, __unused CGSize dimensions, TGVideoEditAdjustments *adjustments, __unused NSAttributedString *caption, __unused NSArray *stickers, __unused NSNumber *timer){ __strong TGMediaAvatarMenuMixin *strongSelf = weakSelf; if (strongSelf == nil) return; diff --git a/submodules/LegacyComponents/Sources/TGMediaEditingContext.m b/submodules/LegacyComponents/Sources/TGMediaEditingContext.m index cd39095d05..fd3e31d9fe 100644 --- a/submodules/LegacyComponents/Sources/TGMediaEditingContext.m +++ b/submodules/LegacyComponents/Sources/TGMediaEditingContext.m @@ -37,10 +37,9 @@ @interface TGMediaCaptionUpdate : NSObject @property (nonatomic, readonly, strong) id item; -@property (nonatomic, readonly, strong) NSString *caption; -@property (nonatomic, readonly, strong) NSArray *entities; +@property (nonatomic, readonly, strong) NSAttributedString *caption; -+ (instancetype)captionUpdateWithItem:(id)item caption:(NSString *)caption entities:(NSArray *)entities; ++ (instancetype)captionUpdateWithItem:(id)item caption:(NSAttributedString *)caption; @end @@ -67,7 +66,6 @@ NSString *_contextId; NSMutableDictionary *_captions; - NSMutableDictionary *_entities; NSMutableDictionary *_adjustments; NSMutableDictionary *_timers; NSNumber *_timer; @@ -104,8 +102,7 @@ SPipe *_fullSizePipe; SPipe *_cropPipe; - NSString *_forcedCaption; - NSArray *_forcedEntities; + NSAttributedString *_forcedCaption; } @end @@ -120,7 +117,6 @@ _queue = [[SQueue alloc] init]; _captions = [[NSMutableDictionary alloc] init]; - _entities = [[NSMutableDictionary alloc] init]; _adjustments = [[NSMutableDictionary alloc] init]; _timers = [[NSMutableDictionary alloc] init]; @@ -373,7 +369,7 @@ #pragma mark - Caption -- (NSString *)captionForItem:(id)item +- (NSAttributedString *)captionForItem:(id)item { if (_forcedCaption != nil) return _forcedCaption; @@ -385,25 +381,12 @@ return _captions[itemId]; } -- (NSArray *)entitiesForItem:(NSObject *)item -{ - if (_forcedCaption != nil) - return _forcedEntities; - - NSString *itemId = [self _contextualIdForItemId:item.uniqueIdentifier]; - if (itemId == nil) - return nil; - - return _entities[itemId]; -} - -- (void)setCaption:(NSString *)caption entities:(NSArray *)entities forItem:(id)item +- (void)setCaption:(NSAttributedString *)caption forItem:(id)item { if (_forcedCaption != nil) { _forcedCaption = caption; - _forcedEntities = entities; - _captionPipe.sink([TGMediaCaptionUpdate captionUpdateWithItem:item caption:caption entities:entities]); + _captionPipe.sink([TGMediaCaptionUpdate captionUpdateWithItem:item caption:caption]); return; } @@ -416,22 +399,16 @@ else [_captions removeObjectForKey:itemId]; - if (entities.count > 0) - _entities[itemId] = entities; - else - [_entities removeObjectForKey:itemId]; - - _captionPipe.sink([TGMediaCaptionUpdate captionUpdateWithItem:item caption:caption entities:entities]); + _captionPipe.sink([TGMediaCaptionUpdate captionUpdateWithItem:item caption:caption]); } - (bool)isForcedCaption { - return _forcedCaption.length > 0; + return _forcedCaption.string.length > 0; } -- (void)setForcedCaption:(NSString *)caption entities:(NSArray *)entities +- (void)setForcedCaption:(NSAttributedString *)caption { _forcedCaption = caption; - _forcedEntities = entities; } - (SSignal *)captionSignalForItem:(NSObject *)item @@ -440,30 +417,12 @@ SSignal *updateSignal = [[_captionPipe.signalProducer() filter:^bool(TGMediaCaptionUpdate *update) { return [update.item.uniqueIdentifier isEqualToString:uniqueIdentifier]; - }] map:^NSDictionary *(TGMediaCaptionUpdate *update) + }] map:^NSAttributedString *(TGMediaCaptionUpdate *update) { - return [self _dictionaryWithCaption:update.caption entities:update.entities];; + return update.caption; }]; - return [[SSignal single:[self _captionWithEntitiesForItem:item]] then:updateSignal]; -} - -- (NSDictionary *)_captionWithEntitiesForItem:(id)item -{ - return [self _dictionaryWithCaption:[self captionForItem:item] entities:[self entitiesForItem:item]]; -} - -- (NSDictionary *)_dictionaryWithCaption:(NSString *)caption entities:(NSArray *)entities -{ - NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; - if (caption.length == 0) - return nil; - - dict[@"caption"] = caption; - if (entities.count > 0) - dict[@"entities"] = entities; - - return dict; + return [[SSignal single:[self captionForItem:item]] then:updateSignal]; } #pragma mark - @@ -1052,12 +1011,11 @@ @implementation TGMediaCaptionUpdate -+ (instancetype)captionUpdateWithItem:(id)item caption:(NSString *)caption entities:(NSArray *)entities ++ (instancetype)captionUpdateWithItem:(id)item caption:(NSAttributedString *)caption { TGMediaCaptionUpdate *update = [[TGMediaCaptionUpdate alloc] init]; update->_item = item; update->_caption = caption; - update->_entities = entities; return update; } diff --git a/submodules/LegacyComponents/Sources/TGMediaPickerGalleryInterfaceView.m b/submodules/LegacyComponents/Sources/TGMediaPickerGalleryInterfaceView.m index d0b13eb90d..1218be3bdf 100644 --- a/submodules/LegacyComponents/Sources/TGMediaPickerGalleryInterfaceView.m +++ b/submodules/LegacyComponents/Sources/TGMediaPickerGalleryInterfaceView.m @@ -103,7 +103,7 @@ @synthesize safeAreaInset = _safeAreaInset; -- (instancetype)initWithContext:(id)context focusItem:(id)focusItem selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext hasSelectionPanel:(bool)hasSelectionPanel hasCameraButton:(bool)hasCameraButton recipientName:(NSString *)recipientName +- (instancetype)initWithContext:(id)context focusItem:(id)focusItem selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext stickersContext:(id)stickersContext hasSelectionPanel:(bool)hasSelectionPanel hasCameraButton:(bool)hasCameraButton recipientName:(NSString *)recipientName { self = [super initWithFrame:CGRectZero]; if (self != nil) @@ -277,7 +277,7 @@ _itemSelectedDisposable = [[SMetaDisposable alloc] init]; _itemAvailabilityDisposable = [[SMetaDisposable alloc] init]; - _captionMixin = [[TGPhotoCaptionInputMixin alloc] initWithKeyCommandController:[_context keyCommandController]]; + _captionMixin = [[TGPhotoCaptionInputMixin alloc] init]; _captionMixin.panelParentView = ^UIView * { __strong TGMediaPickerGalleryInterfaceView *strongSelf = weakSelf; @@ -301,7 +301,7 @@ [strongSelf setItemHeaderViewHidden:true animated:true]; }; - _captionMixin.finishedWithCaption = ^(NSString *caption, NSArray *entities) + _captionMixin.finishedWithCaption = ^(NSAttributedString *caption) { __strong TGMediaPickerGalleryInterfaceView *strongSelf = weakSelf; if (strongSelf == nil) @@ -318,7 +318,7 @@ [strongSelf setItemHeaderViewHidden:false animated:true]; if (strongSelf.captionSet != nil) - strongSelf.captionSet(strongSelf->_currentItem, caption, entities); + strongSelf.captionSet(strongSelf->_currentItem, caption); [strongSelf updateEditorButtonsForItem:strongSelf->_currentItem animated:false]; }; @@ -340,6 +340,7 @@ } completion:nil]; }; + _captionMixin.stickersContext = stickersContext; [_captionMixin createInputPanelIfNeeded]; _portraitToolbarView = [[TGPhotoToolbarView alloc] initWithBackButton:TGPhotoEditorBackButtonBack doneButton:TGPhotoEditorDoneButtonSend solidBackground:false]; @@ -718,15 +719,12 @@ if ([item conformsToProtocol:@protocol(TGModernGalleryEditableItem)]) { id editableMediaItem = [galleryEditableItem editableMediaItem]; - [_captionDisposable setDisposable:[[galleryEditableItem.editingContext captionSignalForItem:editableMediaItem] startWithNext:^(NSDictionary *captionWithEntities) + [_captionDisposable setDisposable:[[galleryEditableItem.editingContext captionSignalForItem:editableMediaItem] startWithNext:^(NSAttributedString *caption) { __strong TGMediaPickerGalleryInterfaceView *strongSelf = weakSelf; if (strongSelf == nil) return; - - NSString *caption = captionWithEntities[@"caption"]; - NSArray *entities = captionWithEntities[@"entities"]; - [strongSelf->_captionMixin setCaption:caption entities:entities animated:animated]; + [strongSelf->_captionMixin setCaption:caption animated:animated]; }]]; } @@ -817,7 +815,7 @@ [_adjustmentsDisposable setDisposable:nil]; [_captionDisposable setDisposable:nil]; [self updateEditorButtonsForAdjustments:nil dimensions:CGSizeZero timer:nil]; - [_captionMixin setCaption:nil entities:nil animated:animated]; + [_captionMixin setCaption:nil animated:animated]; } } @@ -1091,7 +1089,7 @@ _recipientLabel.alpha = alpha; _portraitToolbarView.alpha = alpha; _landscapeToolbarView.alpha = alpha; - _captionMixin.inputPanel.alpha = alpha; + _captionMixin.inputPanelView.alpha = alpha; } completion:^(BOOL finished) { if (finished) @@ -1100,7 +1098,7 @@ _muteButton.userInteractionEnabled = !hidden; _portraitToolbarView.userInteractionEnabled = !hidden; _landscapeToolbarView.userInteractionEnabled = !hidden; - _captionMixin.inputPanel.userInteractionEnabled = !hidden; + _captionMixin.inputPanelView.userInteractionEnabled = !hidden; } }]; @@ -1133,8 +1131,8 @@ _landscapeToolbarView.alpha = alpha; _landscapeToolbarView.userInteractionEnabled = !hidden; - _captionMixin.inputPanel.alpha = alpha; - _captionMixin.inputPanel.userInteractionEnabled = !hidden; + _captionMixin.inputPanelView.alpha = alpha; + _captionMixin.inputPanelView.userInteractionEnabled = !hidden; } if (hidden) @@ -1302,7 +1300,7 @@ - (void)immediateEditorTransitionIn { [self setSelectionInterfaceHidden:true animated:false]; - _captionMixin.inputPanel.alpha = 0.0f; + _captionMixin.inputPanelView.alpha = 0.0f; _portraitToolbarView.doneButton.alpha = 0.0f; _landscapeToolbarView.doneButton.alpha = 0.0f; @@ -1322,7 +1320,7 @@ [UIView animateWithDuration:0.2 animations:^ { - _captionMixin.inputPanel.alpha = 0.0f; + _captionMixin.inputPanelView.alpha = 0.0f; _portraitToolbarView.doneButton.alpha = 0.0f; _landscapeToolbarView.doneButton.alpha = 0.0f; }]; @@ -1334,7 +1332,7 @@ [UIView animateWithDuration:0.3 animations:^ { - _captionMixin.inputPanel.alpha = 1.0f; + _captionMixin.inputPanelView.alpha = 1.0f; _portraitToolbarView.doneButton.alpha = 1.0f; _landscapeToolbarView.doneButton.alpha = 1.0f; }]; @@ -1355,7 +1353,7 @@ || [view isDescendantOfView:_portraitToolbarView] || [view isDescendantOfView:_landscapeToolbarView] || [view isDescendantOfView:_selectedPhotosView] - || [view isDescendantOfView:_captionMixin.inputPanel] + || [view isDescendantOfView:_captionMixin.inputPanelView] || [view isDescendantOfView:_captionMixin.dismissView] || [view isKindOfClass:[TGMenuButtonView class]]) diff --git a/submodules/LegacyComponents/Sources/TGMediaPickerGalleryModel.m b/submodules/LegacyComponents/Sources/TGMediaPickerGalleryModel.m index 745859dc26..e648644334 100644 --- a/submodules/LegacyComponents/Sources/TGMediaPickerGalleryModel.m +++ b/submodules/LegacyComponents/Sources/TGMediaPickerGalleryModel.m @@ -184,7 +184,7 @@ if (_interfaceView == nil) { __weak TGMediaPickerGalleryModel *weakSelf = self; - _interfaceView = [[TGMediaPickerGalleryInterfaceView alloc] initWithContext:_context focusItem:_initialFocusItem selectionContext:_selectionContext editingContext:_editingContext hasSelectionPanel:_hasSelectionPanel hasCameraButton:_hasCamera recipientName:_recipientName]; + _interfaceView = [[TGMediaPickerGalleryInterfaceView alloc] initWithContext:_context focusItem:_initialFocusItem selectionContext:_selectionContext editingContext:_editingContext stickersContext:_stickersContext hasSelectionPanel:_hasSelectionPanel hasCameraButton:_hasCamera recipientName:_recipientName]; [_interfaceView setSuggestionContext:_suggestionContext]; _interfaceView.hasCaptions = _hasCaptions; _interfaceView.allowCaptionEntities = _allowCaptionEntities; @@ -210,7 +210,7 @@ [strongSelf setCurrentItemWithIndex:index]; }; - _interfaceView.captionSet = ^(id item, NSString *caption, NSArray *entities) + _interfaceView.captionSet = ^(id item, NSAttributedString *caption) { __strong TGMediaPickerGalleryModel *strongSelf = weakSelf; if (strongSelf == nil || strongSelf.saveItemCaption == nil) @@ -218,7 +218,7 @@ __strong TGModernGalleryController *controller = strongSelf.controller; if ([controller.currentItem conformsToProtocol:@protocol(TGModernGalleryEditableItem)]) - strongSelf.saveItemCaption(((id)item).editableMediaItem, caption, entities); + strongSelf.saveItemCaption(((id)item).editableMediaItem, caption); }; _interfaceView.timerRequested = ^ { @@ -360,7 +360,7 @@ id adjustments = [item.editingContext adjustmentsForItem:item.editableMediaItem]; - NSString *caption = [item.editingContext captionForItem:item.editableMediaItem]; + NSAttributedString *caption = [item.editingContext captionForItem:item.editableMediaItem]; CGRect refFrame = CGRectZero; UIView *editorReferenceView = [self referenceViewForItem:item frame:&refFrame]; @@ -461,14 +461,14 @@ strongSelf.didFinishRenderingFullSizeImage(editableMediaItem, image); }; - controller.captionSet = ^(NSString *caption, NSArray *entities) + controller.captionSet = ^(NSAttributedString *caption) { __strong TGMediaPickerGalleryModel *strongSelf = weakSelf; if (strongSelf == nil) return; if (strongSelf.saveItemCaption != nil) - strongSelf.saveItemCaption(item.editableMediaItem, caption, entities); + strongSelf.saveItemCaption(item.editableMediaItem, caption); }; controller.requestToolbarsHidden = ^(bool hidden, bool animated) diff --git a/submodules/LegacyComponents/Sources/TGMediaPickerModernGalleryMixin.m b/submodules/LegacyComponents/Sources/TGMediaPickerModernGalleryMixin.m index ed80d1c179..25b52f837a 100644 --- a/submodules/LegacyComponents/Sources/TGMediaPickerModernGalleryMixin.m +++ b/submodules/LegacyComponents/Sources/TGMediaPickerModernGalleryMixin.m @@ -118,9 +118,9 @@ [editingContext setFullSizeImage:resultImage forItem:editableItem]; }; - model.saveItemCaption = ^(id editableItem, NSString *caption, NSArray *entities) + model.saveItemCaption = ^(id editableItem, NSAttributedString *caption) { - [editingContext setCaption:caption entities:entities forItem:editableItem]; + [editingContext setCaption:caption forItem:editableItem]; if (selectionContext != nil && caption.length > 0 && [editableItem conformsToProtocol:@protocol(TGMediaSelectableItem)]) [selectionContext setItem:(id)editableItem selected:true]; diff --git a/submodules/LegacyComponents/Sources/TGPhotoCaptionInputMixin.m b/submodules/LegacyComponents/Sources/TGPhotoCaptionInputMixin.m index 18e2bb651c..72ec096d04 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoCaptionInputMixin.m +++ b/submodules/LegacyComponents/Sources/TGPhotoCaptionInputMixin.m @@ -5,30 +5,32 @@ #import #import "TGSuggestionContext.h" +#import "TGPhotoPaintStickersContext.h" #import "TGModernConversationMentionsAssociatedPanel.h" #import "TGModernConversationHashtagsAssociatedPanel.h" #import "TGModernConversationAlphacodeAssociatedPanel.h" -@interface TGPhotoCaptionInputMixin () +@interface TGPhotoCaptionInputMixin () { + UIView *_backgroundView; TGObserverProxy *_keyboardWillChangeFrameProxy; bool _editing; UIGestureRecognizer *_dismissTapRecognizer; - __weak TGKeyCommandController *_keyCommandController; + CGRect _currentFrame; + UIEdgeInsets _currentEdgeInsets; } @end @implementation TGPhotoCaptionInputMixin -- (instancetype)initWithKeyCommandController:(TGKeyCommandController *)keyCommandController +- (instancetype)init { self = [super init]; if (self != nil) { - _keyCommandController = keyCommandController; _keyboardWillChangeFrameProxy = [[TGObserverProxy alloc] initWithTarget:self targetSelector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification]; } return self; @@ -37,13 +39,13 @@ - (void)dealloc { [_dismissView removeFromSuperview]; - [_inputPanel removeFromSuperview]; + [_inputPanelView removeFromSuperview]; } - (void)setAllowEntities:(bool)allowEntities { _allowEntities = allowEntities; - _inputPanel.allowEntities = allowEntities; +// _inputPanel.allowEntities = allowEntities; } - (void)createInputPanelIfNeeded @@ -53,18 +55,50 @@ UIView *parentView = [self _parentView]; - CGSize screenSize = parentView.frame.size; - _inputPanel = [[TGMediaPickerCaptionInputPanel alloc] initWithKeyCommandController:_keyCommandController frame:CGRectMake(0, 0, screenSize.width, [_inputPanel heightForInputFieldHeight:0])]; - _inputPanel.allowEntities = _allowEntities; - _inputPanel.bottomMargin = 0; - _inputPanel.delegate = self; + id inputPanel = _stickersContext.captionPanelView(); + _inputPanel = inputPanel; - [parentView addSubview:self.inputPanel]; + __weak TGPhotoCaptionInputMixin *weakSelf = self; + _inputPanel.sendPressed = ^(NSAttributedString *string) { + __strong TGPhotoCaptionInputMixin *strongSelf = weakSelf; + [TGViewController enableAutorotation]; + strongSelf->_dismissView.hidden = true; + + if (strongSelf.finishedWithCaption != nil) + strongSelf.finishedWithCaption(string); + }; + _inputPanel.focusUpdated = ^(BOOL focused) { + __strong TGPhotoCaptionInputMixin *strongSelf = weakSelf; + if (focused) { + [TGViewController disableAutorotation]; + + [strongSelf beginEditing]; + + strongSelf->_dismissView.hidden = false; + + if (strongSelf.panelFocused != nil) + strongSelf.panelFocused(); + + [strongSelf enableDismissal]; + } + }; + + _inputPanel.heightUpdated = ^(BOOL animated) { + __strong TGPhotoCaptionInputMixin *strongSelf = weakSelf; + [strongSelf updateLayoutWithFrame:strongSelf->_currentFrame edgeInsets:strongSelf->_currentEdgeInsets]; + }; + + _inputPanelView = inputPanel.view; + + _backgroundView = [[UIView alloc] init]; + _backgroundView.backgroundColor = [TGPhotoEditorInterfaceAssets toolbarTransparentBackgroundColor]; + [parentView addSubview:_backgroundView]; + [parentView addSubview:_inputPanelView]; } - (void)destroy { - [self.inputPanel removeFromSuperview]; + [_inputPanelView removeFromSuperview]; } - (void)createDismissViewIfNeeded @@ -78,23 +112,23 @@ _dismissTapRecognizer.enabled = false; [_dismissView addGestureRecognizer:_dismissTapRecognizer]; - [parentView insertSubview:_dismissView belowSubview:_inputPanel]; + [parentView insertSubview:_dismissView belowSubview:_backgroundView]; } -- (void)setCaption:(NSString *)caption +- (void)setCaption:(NSAttributedString *)caption { - [self setCaption:caption entities:nil animated:false]; + [self setCaption:caption animated:false]; } -- (void)setCaption:(NSString *)caption entities:(NSArray *)entities animated:(bool)animated +- (void)setCaption:(NSAttributedString *)caption animated:(bool)animated { _caption = caption; - [self.inputPanel setCaption:caption entities:entities animated:animated]; + [_inputPanel setCaption:caption]; } - (void)setCaptionPanelHidden:(bool)hidden animated:(bool)__unused animated { - self.inputPanel.hidden = hidden; + _inputPanelView.hidden = hidden; } - (void)beginEditing @@ -103,9 +137,6 @@ [self createDismissViewIfNeeded]; [self createInputPanelIfNeeded]; - - [self.inputPanel adjustForOrientation:self.interfaceOrientation keyboardHeight:_keyboardHeight duration:0.0 animationCurve:0]; - [self.inputPanel layoutSubviews]; } - (void)enableDismissal @@ -120,206 +151,185 @@ if (gestureRecognizer.state != UIGestureRecognizerStateRecognized) return; - [self.inputPanel dismiss]; + [self.inputPanel dismissInput]; [_dismissView removeFromSuperview]; } #pragma mark - Input Panel Delegate -- (bool)inputPanelShouldBecomeFirstResponder:(TGMediaPickerCaptionInputPanel *)__unused inputPanel -{ - return true; -} - -- (void)inputPanelFocused:(TGMediaPickerCaptionInputPanel *)__unused inputPanel -{ - [TGViewController disableAutorotation]; - - [self beginEditing]; - - _dismissView.hidden = false; - - [self.inputPanel.window makeKeyWindow]; - - if (self.panelFocused != nil) - self.panelFocused(); - - [self enableDismissal]; -} - -- (void)inputPanelRequestedSetCaption:(TGMediaPickerCaptionInputPanel *)__unused inputPanel text:(NSString *)text entities:(NSArray *)entities -{ - [TGViewController enableAutorotation]; - - _dismissView.hidden = true; - - if (self.finishedWithCaption != nil) - self.finishedWithCaption(text, entities); -} - -- (void)inputPanelMentionEntered:(TGMediaPickerCaptionInputPanel *)__unused inputTextPanel mention:(NSString *)mention startOfLine:(bool)__unused startOfLine -{ - if (mention == nil) - { - if ([[inputTextPanel associatedPanel] isKindOfClass:[TGModernConversationMentionsAssociatedPanel class]]) - [inputTextPanel setAssociatedPanel:nil animated:true]; - } - else - { - TGModernConversationMentionsAssociatedPanel *panel = nil; - if ([[inputTextPanel associatedPanel] isKindOfClass:[TGModernConversationMentionsAssociatedPanel class]]) - panel = (TGModernConversationMentionsAssociatedPanel *)[inputTextPanel associatedPanel]; - else - { - panel = [[TGModernConversationMentionsAssociatedPanel alloc] initWithStyle:TGModernConversationAssociatedInputPanelDarkStyle]; - - __weak TGPhotoCaptionInputMixin *weakSelf = self; - panel.userSelected = ^(TGUser *user) - { - __strong TGPhotoCaptionInputMixin *strongSelf = weakSelf; - if (strongSelf != nil) - { - if ([[strongSelf->_inputPanel associatedPanel] isKindOfClass:[TGModernConversationMentionsAssociatedPanel class]]) - [strongSelf->_inputPanel setAssociatedPanel:nil animated:false]; - - if (user.userName.length == 0) { - [strongSelf->_inputPanel replaceMention:[[NSString alloc] initWithFormat:@"%@", user.displayFirstName] username:false userId:user.uid]; - } else { - [strongSelf->_inputPanel replaceMention:[[NSString alloc] initWithFormat:@"%@", user.userName] username:true userId:user.uid]; - } - } - }; - } - - SSignal *userListSignal = nil; - if (self.suggestionContext.userListSignal != nil) - userListSignal = self.suggestionContext.userListSignal(mention); - - [panel setUserListSignal:userListSignal]; - - [inputTextPanel setAssociatedPanel:panel animated:true]; - } -} - -- (void)inputPanelHashtagEntered:(TGMediaPickerCaptionInputPanel *)inputTextPanel hashtag:(NSString *)hashtag -{ - if (hashtag == nil) - { - if ([[inputTextPanel associatedPanel] isKindOfClass:[TGModernConversationHashtagsAssociatedPanel class]]) - [inputTextPanel setAssociatedPanel:nil animated:true]; - } - else - { - TGModernConversationHashtagsAssociatedPanel *panel = nil; - if ([[inputTextPanel associatedPanel] isKindOfClass:[TGModernConversationHashtagsAssociatedPanel class]]) - panel = (TGModernConversationHashtagsAssociatedPanel *)[inputTextPanel associatedPanel]; - else - { - panel = [[TGModernConversationHashtagsAssociatedPanel alloc] initWithStyle:TGModernConversationAssociatedInputPanelDarkStyle]; - - __weak TGPhotoCaptionInputMixin *weakSelf = self; - panel.hashtagSelected = ^(NSString *hashtag) - { - __strong TGPhotoCaptionInputMixin *strongSelf = weakSelf; - if (strongSelf != nil) - { - if ([[strongSelf->_inputPanel associatedPanel] isKindOfClass:[TGModernConversationHashtagsAssociatedPanel class]]) - [strongSelf->_inputPanel setAssociatedPanel:nil animated:false]; - - [strongSelf->_inputPanel replaceHashtag:hashtag]; - } - }; - [inputTextPanel setAssociatedPanel:panel animated:true]; - } - - SSignal *hashtagListSignal = nil; - if (self.suggestionContext.hashtagListSignal != nil) - hashtagListSignal = self.suggestionContext.hashtagListSignal(hashtag); - - [panel setHashtagListSignal:hashtagListSignal]; - } -} - -- (void)inputPanelAlphacodeEntered:(TGMediaPickerCaptionInputPanel *)inputTextPanel alphacode:(NSString *)alphacode -{ - if (alphacode == nil) - { - if ([[inputTextPanel associatedPanel] isKindOfClass:[TGModernConversationAlphacodeAssociatedPanel class]]) - [inputTextPanel setAssociatedPanel:nil animated:true]; - } - else - { - TGModernConversationAlphacodeAssociatedPanel *panel = nil; - if ([[inputTextPanel associatedPanel] isKindOfClass:[TGModernConversationAlphacodeAssociatedPanel class]]) - panel = ((TGModernConversationAlphacodeAssociatedPanel *)[inputTextPanel associatedPanel]); - else - { - panel = [[TGModernConversationAlphacodeAssociatedPanel alloc] initWithStyle:TGModernConversationAssociatedInputPanelDarkStyle]; - __weak TGPhotoCaptionInputMixin *weakSelf = self; - panel.alphacodeSelected = ^(TGAlphacodeEntry *entry) - { - __strong TGPhotoCaptionInputMixin *strongSelf = weakSelf; - if (strongSelf != nil) - { - if ([[strongSelf->_inputPanel associatedPanel] isKindOfClass:[TGModernConversationAlphacodeAssociatedPanel class]]) - { - [strongSelf->_inputPanel setAssociatedPanel:nil animated:false]; - } - - NSString *codeText = entry.emoji; - - [strongSelf appendAlphacode:[codeText stringByAppendingString:@" "]]; - } - }; - [inputTextPanel setAssociatedPanel:panel animated:true]; - } - - SSignal *alphacodeListSignal = nil; - if (self.suggestionContext.alphacodeSignal != nil) - alphacodeListSignal = self.suggestionContext.alphacodeSignal(alphacode, inputTextPanel.inputField.textInputMode.primaryLanguage); - - [panel setAlphacodeListSignal:alphacodeListSignal]; - } -} - -- (void)appendAlphacode:(NSString *)alphacode -{ - NSString *currentText = [_inputPanel inputField].text; - NSRange selectRange = NSMakeRange(0, 0); - - if (currentText.length == 0) - currentText = alphacode; - else - { - NSInteger caretIndex = [_inputPanel textCaretPosition]; - - for (NSInteger i = caretIndex - 1; i >= 0; i--) - { - if ([currentText characterAtIndex:i] == ':') { - currentText = [currentText stringByReplacingCharactersInRange:NSMakeRange(i, caretIndex - i) withString:alphacode]; - selectRange = NSMakeRange(i + alphacode.length, 0); - break; - } - } - } - - [[_inputPanel inputField] setAttributedText:[[NSAttributedString alloc] initWithString:currentText] animated:false]; - [[_inputPanel inputField] selectRange:selectRange force:true]; - - [_inputPanel inputField].internalTextView.enableFirstResponder = true; -} - -- (void)inputPanelWillChangeHeight:(TGMediaPickerCaptionInputPanel *)inputPanel height:(CGFloat)__unused height duration:(NSTimeInterval)duration animationCurve:(int)animationCurve -{ - [inputPanel adjustForOrientation:UIInterfaceOrientationPortrait keyboardHeight:_keyboardHeight duration:duration animationCurve:animationCurve]; -} +//- (void)inputPanelRequestedSetCaption:(TGMediaPickerCaptionInputPanel *)__unused inputPanel text:(NSString *)text entities:(NSArray *)entities +//{ +// [TGViewController enableAutorotation]; +// +// _dismissView.hidden = true; +// +// if (self.finishedWithCaption != nil) +// self.finishedWithCaption(text, entities); +//} +// +//- (void)inputPanelMentionEntered:(TGMediaPickerCaptionInputPanel *)__unused inputTextPanel mention:(NSString *)mention startOfLine:(bool)__unused startOfLine +//{ +// if (mention == nil) +// { +// if ([[inputTextPanel associatedPanel] isKindOfClass:[TGModernConversationMentionsAssociatedPanel class]]) +// [inputTextPanel setAssociatedPanel:nil animated:true]; +// } +// else +// { +// TGModernConversationMentionsAssociatedPanel *panel = nil; +// if ([[inputTextPanel associatedPanel] isKindOfClass:[TGModernConversationMentionsAssociatedPanel class]]) +// panel = (TGModernConversationMentionsAssociatedPanel *)[inputTextPanel associatedPanel]; +// else +// { +// panel = [[TGModernConversationMentionsAssociatedPanel alloc] initWithStyle:TGModernConversationAssociatedInputPanelDarkStyle]; +// +// __weak TGPhotoCaptionInputMixin *weakSelf = self; +// panel.userSelected = ^(TGUser *user) +// { +// __strong TGPhotoCaptionInputMixin *strongSelf = weakSelf; +// if (strongSelf != nil) +// { +// if ([[strongSelf->_inputPanel associatedPanel] isKindOfClass:[TGModernConversationMentionsAssociatedPanel class]]) +// [strongSelf->_inputPanel setAssociatedPanel:nil animated:false]; +// +// if (user.userName.length == 0) { +// [strongSelf->_inputPanel replaceMention:[[NSString alloc] initWithFormat:@"%@", user.displayFirstName] username:false userId:user.uid]; +// } else { +// [strongSelf->_inputPanel replaceMention:[[NSString alloc] initWithFormat:@"%@", user.userName] username:true userId:user.uid]; +// } +// } +// }; +// } +// +// SSignal *userListSignal = nil; +// if (self.suggestionContext.userListSignal != nil) +// userListSignal = self.suggestionContext.userListSignal(mention); +// +// [panel setUserListSignal:userListSignal]; +// +// [inputTextPanel setAssociatedPanel:panel animated:true]; +// } +//} +// +//- (void)inputPanelHashtagEntered:(TGMediaPickerCaptionInputPanel *)inputTextPanel hashtag:(NSString *)hashtag +//{ +// if (hashtag == nil) +// { +// if ([[inputTextPanel associatedPanel] isKindOfClass:[TGModernConversationHashtagsAssociatedPanel class]]) +// [inputTextPanel setAssociatedPanel:nil animated:true]; +// } +// else +// { +// TGModernConversationHashtagsAssociatedPanel *panel = nil; +// if ([[inputTextPanel associatedPanel] isKindOfClass:[TGModernConversationHashtagsAssociatedPanel class]]) +// panel = (TGModernConversationHashtagsAssociatedPanel *)[inputTextPanel associatedPanel]; +// else +// { +// panel = [[TGModernConversationHashtagsAssociatedPanel alloc] initWithStyle:TGModernConversationAssociatedInputPanelDarkStyle]; +// +// __weak TGPhotoCaptionInputMixin *weakSelf = self; +// panel.hashtagSelected = ^(NSString *hashtag) +// { +// __strong TGPhotoCaptionInputMixin *strongSelf = weakSelf; +// if (strongSelf != nil) +// { +// if ([[strongSelf->_inputPanel associatedPanel] isKindOfClass:[TGModernConversationHashtagsAssociatedPanel class]]) +// [strongSelf->_inputPanel setAssociatedPanel:nil animated:false]; +// +// [strongSelf->_inputPanel replaceHashtag:hashtag]; +// } +// }; +// [inputTextPanel setAssociatedPanel:panel animated:true]; +// } +// +// SSignal *hashtagListSignal = nil; +// if (self.suggestionContext.hashtagListSignal != nil) +// hashtagListSignal = self.suggestionContext.hashtagListSignal(hashtag); +// +// [panel setHashtagListSignal:hashtagListSignal]; +// } +//} +// +//- (void)inputPanelAlphacodeEntered:(TGMediaPickerCaptionInputPanel *)inputTextPanel alphacode:(NSString *)alphacode +//{ +// if (alphacode == nil) +// { +// if ([[inputTextPanel associatedPanel] isKindOfClass:[TGModernConversationAlphacodeAssociatedPanel class]]) +// [inputTextPanel setAssociatedPanel:nil animated:true]; +// } +// else +// { +// TGModernConversationAlphacodeAssociatedPanel *panel = nil; +// if ([[inputTextPanel associatedPanel] isKindOfClass:[TGModernConversationAlphacodeAssociatedPanel class]]) +// panel = ((TGModernConversationAlphacodeAssociatedPanel *)[inputTextPanel associatedPanel]); +// else +// { +// panel = [[TGModernConversationAlphacodeAssociatedPanel alloc] initWithStyle:TGModernConversationAssociatedInputPanelDarkStyle]; +// __weak TGPhotoCaptionInputMixin *weakSelf = self; +// panel.alphacodeSelected = ^(TGAlphacodeEntry *entry) +// { +// __strong TGPhotoCaptionInputMixin *strongSelf = weakSelf; +// if (strongSelf != nil) +// { +// if ([[strongSelf->_inputPanel associatedPanel] isKindOfClass:[TGModernConversationAlphacodeAssociatedPanel class]]) +// { +// [strongSelf->_inputPanel setAssociatedPanel:nil animated:false]; +// } +// +// NSString *codeText = entry.emoji; +// +// [strongSelf appendAlphacode:[codeText stringByAppendingString:@" "]]; +// } +// }; +// [inputTextPanel setAssociatedPanel:panel animated:true]; +// } +// +// SSignal *alphacodeListSignal = nil; +// if (self.suggestionContext.alphacodeSignal != nil) +// alphacodeListSignal = self.suggestionContext.alphacodeSignal(alphacode, inputTextPanel.inputField.textInputMode.primaryLanguage); +// +// [panel setAlphacodeListSignal:alphacodeListSignal]; +// } +//} +// +//- (void)appendAlphacode:(NSString *)alphacode +//{ +// NSString *currentText = [_inputPanel inputField].text; +// NSRange selectRange = NSMakeRange(0, 0); +// +// if (currentText.length == 0) +// currentText = alphacode; +// else +// { +// NSInteger caretIndex = [_inputPanel textCaretPosition]; +// +// for (NSInteger i = caretIndex - 1; i >= 0; i--) +// { +// if ([currentText characterAtIndex:i] == ':') { +// currentText = [currentText stringByReplacingCharactersInRange:NSMakeRange(i, caretIndex - i) withString:alphacode]; +// selectRange = NSMakeRange(i + alphacode.length, 0); +// break; +// } +// } +// } +// +// [[_inputPanel inputField] setAttributedText:[[NSAttributedString alloc] initWithString:currentText] animated:false]; +// [[_inputPanel inputField] selectRange:selectRange force:true]; +// +// [_inputPanel inputField].internalTextView.enableFirstResponder = true; +//} +// +//- (void)inputPanelWillChangeHeight:(TGMediaPickerCaptionInputPanel *)inputPanel height:(CGFloat)__unused height duration:(NSTimeInterval)duration animationCurve:(int)animationCurve +//{ +// [inputPanel adjustForOrientation:UIInterfaceOrientationPortrait keyboardHeight:_keyboardHeight duration:duration animationCurve:animationCurve]; +//} - (void)setContentAreaHeight:(CGFloat)contentAreaHeight { _contentAreaHeight = contentAreaHeight; CGFloat finalHeight = _contentAreaHeight - _keyboardHeight; - [_inputPanel setContentAreaHeight:finalHeight]; +// [_inputPanel setContentAreaHeight:finalHeight]; } - (UIView *)_parentView @@ -354,20 +364,26 @@ if (!UIInterfaceOrientationIsPortrait([[LegacyComponentsGlobals provider] applicationStatusBarOrientation]) && !TGIsPad()) return; - [_inputPanel adjustForOrientation:UIInterfaceOrientationPortrait keyboardHeight:keyboardHeight duration:duration animationCurve:curve]; - + CGRect frame = _currentFrame; + UIEdgeInsets edgeInsets = _currentEdgeInsets; + CGFloat panelHeight = [_inputPanel updateLayoutSize:frame.size sideInset:0.0]; + [UIView animateWithDuration:duration delay:0.0f options:curve animations:^{ + _inputPanelView.frame = CGRectMake(edgeInsets.left, frame.size.height - panelHeight - MAX(edgeInsets.bottom, _keyboardHeight), frame.size.width, panelHeight); + _backgroundView.frame = CGRectMake(edgeInsets.left, frame.size.height - panelHeight - MAX(edgeInsets.bottom, _keyboardHeight), frame.size.width, panelHeight); + } completion:nil]; + if (self.keyboardHeightChanged != nil) self.keyboardHeightChanged(keyboardHeight, duration, curve); - - CGFloat finalHeight = _contentAreaHeight - _keyboardHeight; - [_inputPanel setContentAreaHeight:finalHeight]; } - (void)updateLayoutWithFrame:(CGRect)frame edgeInsets:(UIEdgeInsets)edgeInsets { - _inputPanel.frame = CGRectMake(edgeInsets.left, _inputPanel.frame.origin.y, frame.size.width, _inputPanel.frame.size.height); - _inputPanel.bottomMargin = edgeInsets.bottom; - [_inputPanel adjustForOrientation:UIInterfaceOrientationPortrait keyboardHeight:_keyboardHeight duration:0.0 animationCurve:0]; + _currentFrame = frame; + _currentEdgeInsets = edgeInsets; + + CGFloat panelHeight = [_inputPanel updateLayoutSize:frame.size sideInset:0.0]; + _inputPanelView.frame = CGRectMake(edgeInsets.left, frame.size.height - panelHeight - MAX(edgeInsets.bottom, _keyboardHeight), frame.size.width, panelHeight); + _backgroundView.frame = CGRectMake(edgeInsets.left, frame.size.height - panelHeight - MAX(edgeInsets.bottom, _keyboardHeight), frame.size.width, panelHeight); } @end diff --git a/submodules/LegacyComponents/Sources/TGPhotoVideoEditor.m b/submodules/LegacyComponents/Sources/TGPhotoVideoEditor.m index 374470dac3..842ae7e663 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoVideoEditor.m +++ b/submodules/LegacyComponents/Sources/TGPhotoVideoEditor.m @@ -102,13 +102,13 @@ } } -+ (void)presentWithContext:(id)context controller:(TGViewController *)controller caption:(NSString *)caption entities:(NSArray *)entities withItem:(id)item paint:(bool)paint recipientName:(NSString *)recipientName stickersContext:(id)stickersContext snapshots:(NSArray *)snapshots immediate:(bool)immediate appeared:(void (^)(void))appeared completion:(void (^)(id, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed ++ (void)presentWithContext:(id)context controller:(TGViewController *)controller caption:(NSAttributedString *)caption withItem:(id)item paint:(bool)paint recipientName:(NSString *)recipientName stickersContext:(id)stickersContext snapshots:(NSArray *)snapshots immediate:(bool)immediate appeared:(void (^)(void))appeared completion:(void (^)(id, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed { id windowManager = [context makeOverlayWindowManager]; id windowContext = [windowManager context]; TGMediaEditingContext *editingContext = [[TGMediaEditingContext alloc] init]; - [editingContext setForcedCaption:caption entities:entities]; + [editingContext setForcedCaption:caption]; TGModernGalleryController *galleryController = [[TGModernGalleryController alloc] initWithContext:windowContext]; galleryController.adjustsStatusBarVisibility = true; @@ -145,9 +145,9 @@ [editingContext setImage:resultImage thumbnailImage:thumbnailImage forItem:editableItem synchronous:false]; }; - model.saveItemCaption = ^(id editableItem, NSString *caption, NSArray *entities) + model.saveItemCaption = ^(id editableItem, NSAttributedString *caption) { - [editingContext setCaption:caption entities:entities forItem:editableItem]; + [editingContext setCaption:caption forItem:editableItem]; }; model.interfaceView.hasSwipeGesture = false; diff --git a/submodules/LegacyMediaPickerUI/BUILD b/submodules/LegacyMediaPickerUI/BUILD index ddc196895b..18c9a09829 100644 --- a/submodules/LegacyMediaPickerUI/BUILD +++ b/submodules/LegacyMediaPickerUI/BUILD @@ -27,6 +27,7 @@ swift_library( "//submodules/AnimatedStickerNode:AnimatedStickerNode", "//submodules/TelegramAnimatedStickerNode:TelegramAnimatedStickerNode", "//submodules/StickerResources:StickerResources", + "//submodules/TextFormat:TextFormat", ], visibility = [ "//visibility:public", diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift index ad3ee8953d..1df5636265 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift @@ -58,7 +58,7 @@ public enum LegacyAttachmentMenuMediaEditing { case file } -public func legacyMediaEditor(context: AccountContext, peer: Peer, media: AnyMediaReference, initialCaption: String, snapshots: [UIView], transitionCompletion: (() -> Void)?, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, present: @escaping (ViewController, Any?) -> Void) { +public func legacyMediaEditor(context: AccountContext, peer: Peer, media: AnyMediaReference, initialCaption: NSAttributedString, snapshots: [UIView], transitionCompletion: (() -> Void)?, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, present: @escaping (ViewController, Any?) -> Void) { let _ = (fetchMediaData(context: context, postbox: context.account.postbox, mediaReference: media) |> deliverOnMainQueue).start(next: { (value, isImage) in guard case let .data(data) = value, data.complete else { @@ -73,6 +73,9 @@ public func legacyMediaEditor(context: AccountContext, peer: Peer, media: AnyMed } let paintStickersContext = LegacyPaintStickersContext(context: context) + paintStickersContext.captionPanelView = { + return getCaptionPanelView() + } paintStickersContext.presentStickersController = { completion in return presentStickers({ file, animated, view, rect in let coder = PostboxEncoder() @@ -102,7 +105,7 @@ public func legacyMediaEditor(context: AccountContext, peer: Peer, media: AnyMed present(legacyController, nil) - TGPhotoVideoEditor.present(with: legacyController.context, controller: emptyController, caption: initialCaption, entities: [], withItem: item, paint: true, recipientName: recipientName, stickersContext: paintStickersContext, snapshots: snapshots as [Any], immediate: transitionCompletion != nil, appeared: { + TGPhotoVideoEditor.present(with: legacyController.context, controller: emptyController, caption: initialCaption, withItem: item, paint: true, recipientName: recipientName, stickersContext: paintStickersContext, snapshots: snapshots as [Any], immediate: transitionCompletion != nil, appeared: { transitionCompletion?() }, completion: { result, editingContext in let nativeGenerator = legacyAssetPickerItemGenerator() @@ -110,8 +113,8 @@ public func legacyMediaEditor(context: AccountContext, peer: Peer, media: AnyMed if let result = result { selectableResult = unsafeDowncast(result, to: TGMediaSelectableItem.self) } - let signals = TGCameraController.resultSignals(for: nil, editingContext: editingContext, currentItem: selectableResult, storeAssets: false, saveEditedPhotos: false, descriptionGenerator: { _1, _2, _3, _4 in - nativeGenerator(_1, _2, _3, _4, nil) + let signals = TGCameraController.resultSignals(for: nil, editingContext: editingContext, currentItem: selectableResult, storeAssets: false, saveEditedPhotos: false, descriptionGenerator: { _1, _2, _3 in + nativeGenerator(_1, _2, _3, nil) }) sendMessagesWithSignals(signals, false, 0) }, dismissed: { [weak legacyController] in @@ -119,8 +122,8 @@ public func legacyMediaEditor(context: AccountContext, peer: Peer, media: AnyMed }) }) } - -public func legacyAttachmentMenu(context: AccountContext, peer: Peer, chatLocation: ChatLocation, editMediaOptions: LegacyAttachmentMenuMediaEditing?, saveEditedPhotos: Bool, allowGrouping: Bool, hasSchedule: Bool, canSendPolls: Bool, updatedPresentationData: (initial: PresentationData, signal: Signal), parentController: LegacyController, recentlyUsedInlineBots: [Peer], initialCaption: String, openGallery: @escaping () -> Void, openCamera: @escaping (TGAttachmentCameraView?, TGMenuSheetController?) -> Void, openFileGallery: @escaping () -> Void, openWebSearch: @escaping () -> Void, openMap: @escaping () -> Void, openContacts: @escaping () -> Void, openPoll: @escaping () -> Void, presentSelectionLimitExceeded: @escaping () -> Void, presentCantSendMultipleFiles: @escaping () -> Void, presentJpegConversionAlert: @escaping (@escaping (Bool) -> Void) -> Void, presentSchedulePicker: @escaping (@escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32, ((String) -> UIView?)?, @escaping () -> Void) -> Void, selectRecentlyUsedInlineBot: @escaping (Peer) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, present: @escaping (ViewController, Any?) -> Void) -> TGMenuSheetController { + +public func legacyAttachmentMenu(context: AccountContext, peer: Peer, chatLocation: ChatLocation, editMediaOptions: LegacyAttachmentMenuMediaEditing?, saveEditedPhotos: Bool, allowGrouping: Bool, hasSchedule: Bool, canSendPolls: Bool, updatedPresentationData: (initial: PresentationData, signal: Signal), parentController: LegacyController, recentlyUsedInlineBots: [Peer], initialCaption: NSAttributedString, openGallery: @escaping () -> Void, openCamera: @escaping (TGAttachmentCameraView?, TGMenuSheetController?) -> Void, openFileGallery: @escaping () -> Void, openWebSearch: @escaping () -> Void, openMap: @escaping () -> Void, openContacts: @escaping () -> Void, openPoll: @escaping () -> Void, presentSelectionLimitExceeded: @escaping () -> Void, presentCantSendMultipleFiles: @escaping () -> Void, presentJpegConversionAlert: @escaping (@escaping (Bool) -> Void) -> Void, presentSchedulePicker: @escaping (@escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32, ((String) -> UIView?)?, @escaping () -> Void) -> Void, selectRecentlyUsedInlineBot: @escaping (Peer) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, present: @escaping (ViewController, Any?) -> Void) -> TGMenuSheetController { let defaultVideoPreset = defaultVideoPresetForContext(context) UserDefaults.standard.set(defaultVideoPreset.rawValue as NSNumber, forKey: "TG_preferredVideoPreset_v0") @@ -169,6 +172,9 @@ public func legacyAttachmentMenu(context: AccountContext, peer: Peer, chatLocati } let paintStickersContext = LegacyPaintStickersContext(context: context) + paintStickersContext.captionPanelView = { + return getCaptionPanelView() + } paintStickersContext.presentStickersController = { completion in return presentStickers({ file, animated, view, rect in let coder = PostboxEncoder() @@ -266,8 +272,8 @@ public func legacyAttachmentMenu(context: AccountContext, peer: Peer, chatLocati } }; carouselItem.allowCaptions = true - if !initialCaption.isEmpty { - carouselItem.editingContext.setForcedCaption(initialCaption, entities: []) + if !initialCaption.string.isEmpty { + carouselItem.editingContext.setForcedCaption(initialCaption) } itemViews.append(carouselItem) @@ -353,15 +359,15 @@ public func legacyAttachmentMenu(context: AccountContext, peer: Peer, chatLocati present(legacyController, nil) - TGPhotoVideoEditor.present(with: legacyController.context, controller: emptyController, caption: "", entities: [], withItem: item, paint: false, recipientName: recipientName, stickersContext: paintStickersContext, snapshots: [], immediate: false, appeared: { + TGPhotoVideoEditor.present(with: legacyController.context, controller: emptyController, caption: NSAttributedString(), withItem: item, paint: false, recipientName: recipientName, stickersContext: paintStickersContext, snapshots: [], immediate: false, appeared: { }, completion: { result, editingContext in let nativeGenerator = legacyAssetPickerItemGenerator() var selectableResult: TGMediaSelectableItem? if let result = result { selectableResult = unsafeDowncast(result, to: TGMediaSelectableItem.self) } - let signals = TGCameraController.resultSignals(for: nil, editingContext: editingContext, currentItem: selectableResult, storeAssets: false, saveEditedPhotos: false, descriptionGenerator: { _1, _2, _3, _4 in - nativeGenerator(_1, _2, _3, _4, nil) + let signals = TGCameraController.resultSignals(for: nil, editingContext: editingContext, currentItem: selectableResult, storeAssets: false, saveEditedPhotos: false, descriptionGenerator: { _1, _2, _3 in + nativeGenerator(_1, _2, _3, nil) }) sendMessagesWithSignals(signals, false, 0, { _ in nil}, {}) }, dismissed: { [weak legacyController] in @@ -440,7 +446,7 @@ public func legacyMenuPaletteFromTheme(_ theme: PresentationTheme, forceDark: Bo return TGMenuSheetPallete(dark: forceDark || theme.overallDarkAppearance, backgroundColor: sheetTheme.opaqueItemBackgroundColor, selectionColor: sheetTheme.opaqueItemHighlightedBackgroundColor, separatorColor: sheetTheme.opaqueItemSeparatorColor, accentColor: sheetTheme.controlAccentColor, destructiveColor: sheetTheme.destructiveActionTextColor, textColor: sheetTheme.primaryTextColor, secondaryTextColor: sheetTheme.secondaryTextColor, spinnerColor: sheetTheme.secondaryTextColor, badgeTextColor: sheetTheme.controlAccentColor, badgeImage: nil, cornersImage: generateStretchableFilledCircleImage(diameter: 11.0, color: nil, strokeColor: nil, strokeWidth: nil, backgroundColor: sheetTheme.opaqueItemBackgroundColor)) } -public func presentLegacyPasteMenu(context: AccountContext, peer: Peer, chatLocation: ChatLocation, saveEditedPhotos: Bool, allowGrouping: Bool, hasSchedule: Bool, updatedPresentationData: (initial: PresentationData, signal: Signal), images: [UIImage], presentSchedulePicker: @escaping (@escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, present: (ViewController, Any?) -> Void, initialLayout: ContainerViewLayout? = nil) -> ViewController { +public func presentLegacyPasteMenu(context: AccountContext, peer: Peer, chatLocation: ChatLocation, saveEditedPhotos: Bool, allowGrouping: Bool, hasSchedule: Bool, updatedPresentationData: (initial: PresentationData, signal: Signal), images: [UIImage], presentSchedulePicker: @escaping (@escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, present: (ViewController, Any?) -> Void, initialLayout: ContainerViewLayout? = nil) -> ViewController { let defaultVideoPreset = defaultVideoPresetForContext(context) UserDefaults.standard.set(defaultVideoPreset.rawValue as NSNumber, forKey: "TG_preferredVideoPreset_v0") @@ -471,6 +477,9 @@ public func presentLegacyPasteMenu(context: AccountContext, peer: Peer, chatLoca let suggestionContext = legacySuggestionContext(context: context, peerId: peer.id, chatLocation: chatLocation) let paintStickersContext = LegacyPaintStickersContext(context: context) + paintStickersContext.captionPanelView = { + return getCaptionPanelView() + } paintStickersContext.presentStickersController = { completion in return presentStickers({ file, animated, view, rect in let coder = PostboxEncoder() @@ -489,8 +498,8 @@ public func presentLegacyPasteMenu(context: AccountContext, peer: Peer, chatLoca } }, completed: { selectionContext, editingContext, currentItem, silentPosting, scheduleTime in let nativeGenerator = legacyAssetPickerItemGenerator() - let signals = TGClipboardMenu.resultSignals(for: selectionContext, editingContext: editingContext, currentItem: currentItem, descriptionGenerator: { _1, _2, _3, _4 in - nativeGenerator(_1, _2, _3, _4, nil) + let signals = TGClipboardMenu.resultSignals(for: selectionContext, editingContext: editingContext, currentItem: currentItem, descriptionGenerator: { _1, _2, _3 in + nativeGenerator(_1, _2, _3, nil) }) sendMessagesWithSignals(signals, silentPosting, scheduleTime) }, dismissed: { [weak legacyController] in diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyMediaPickers.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyMediaPickers.swift index 22e5be3e65..f0ba3f1667 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyMediaPickers.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyMediaPickers.swift @@ -13,13 +13,17 @@ import ImageCompression import MimeTypes import LocalMediaResources import LegacyUI +import TextFormat public func guessMimeTypeByFileExtension(_ ext: String) -> String { return TGMimeTypeMap.mimeType(forExtension: ext) ?? "application/binary" } -public func configureLegacyAssetPicker(_ controller: TGMediaAssetsController, context: AccountContext, peer: Peer, chatLocation: ChatLocation, captionsEnabled: Bool = true, storeCreatedAssets: Bool = true, showFileTooltip: Bool = false, initialCaption: String, hasSchedule: Bool, presentWebSearch: (() -> Void)?, presentSelectionLimitExceeded: @escaping () -> Void, presentSchedulePicker: @escaping (@escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?) { +public func configureLegacyAssetPicker(_ controller: TGMediaAssetsController, context: AccountContext, peer: Peer, chatLocation: ChatLocation, captionsEnabled: Bool = true, storeCreatedAssets: Bool = true, showFileTooltip: Bool = false, initialCaption: NSAttributedString, hasSchedule: Bool, presentWebSearch: (() -> Void)?, presentSelectionLimitExceeded: @escaping () -> Void, presentSchedulePicker: @escaping (@escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, getCaptionPanelView: @escaping () -> TGCaptionPanelView?) { let paintStickersContext = LegacyPaintStickersContext(context: context) + paintStickersContext.captionPanelView = { + return getCaptionPanelView() + } paintStickersContext.presentStickersController = { completion in return presentStickers({ file, animated, view, rect in let coder = PostboxEncoder() @@ -60,8 +64,8 @@ public func configureLegacyAssetPicker(_ controller: TGMediaAssetsController, co controller.shouldShowFileTipIfNeeded = showFileTooltip controller.requestSearchController = presentWebSearch - if !initialCaption.isEmpty { - controller.editingContext.setForcedCaption(initialCaption, entities: []) + if !initialCaption.string.isEmpty { + controller.editingContext.setForcedCaption(initialCaption) } } @@ -120,9 +124,9 @@ private enum LegacyAssetVideoData { } private enum LegacyAssetItem { - case image(data: LegacyAssetImageData, thumbnail: UIImage?, caption: String?, stickers: [FileMediaReference]) - case file(data: LegacyAssetImageData, thumbnail: UIImage?, mimeType: String, name: String, caption: String?) - case video(data: LegacyAssetVideoData, thumbnail: UIImage?, adjustments: TGVideoEditAdjustments?, caption: String?, asFile: Bool, asAnimation: Bool, stickers: [FileMediaReference]) + case image(data: LegacyAssetImageData, thumbnail: UIImage?, caption: NSAttributedString?, stickers: [FileMediaReference]) + case file(data: LegacyAssetImageData, thumbnail: UIImage?, mimeType: String, name: String, caption: NSAttributedString?) + case video(data: LegacyAssetVideoData, thumbnail: UIImage?, adjustments: TGVideoEditAdjustments?, caption: NSAttributedString?, asFile: Bool, asAnimation: Bool, stickers: [FileMediaReference]) } private final class LegacyAssetItemWrapper: NSObject { @@ -141,8 +145,8 @@ private final class LegacyAssetItemWrapper: NSObject { } } -public func legacyAssetPickerItemGenerator() -> ((Any?, String?, [Any]?, String?, String?) -> [AnyHashable : Any]?) { - return { anyDict, caption, entities, hash, uniqueId in +public func legacyAssetPickerItemGenerator() -> ((Any?, NSAttributedString?, String?, String?) -> [AnyHashable : Any]?) { + return { anyDict, caption, hash, uniqueId in let dict = anyDict as! NSDictionary let stickers = (dict["stickers"] as? [Data])?.compactMap { data -> FileMediaReference? in let decoder = PostboxDecoder(buffer: MemoryBuffer(data: data)) @@ -395,9 +399,14 @@ public func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) - if let timer = item.timer, timer > 0 && timer <= 60 { attributes.append(AutoremoveTimeoutMessageAttribute(timeout: Int32(timer), countdownBeginTime: nil)) } + + let text = trimChatInputText(convertMarkdownToAttributes(caption ?? NSAttributedString())) + let entities = generateTextEntities(text.string, enabledTypes: .all, currentEntities: generateChatInputTextEntities(text)) + if !entities.isEmpty { + attributes.append(TextEntitiesMessageAttribute(entities: entities)) + } - let text = caption ?? "" - messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: text, attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: item.groupedId, correlationId: nil), uniqueId: item.uniqueId)) + messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: text.string, attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: item.groupedId, correlationId: nil), uniqueId: item.uniqueId)) } } case let .asset(asset): @@ -413,7 +422,14 @@ public func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) - if let timer = item.timer, timer > 0 && timer <= 60 { attributes.append(AutoremoveTimeoutMessageAttribute(timeout: Int32(timer), countdownBeginTime: nil)) } - messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: caption ?? "", attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: item.groupedId, correlationId: nil), uniqueId: item.uniqueId)) + + let text = trimChatInputText(convertMarkdownToAttributes(caption ?? NSAttributedString())) + let entities = generateTextEntities(text.string, enabledTypes: .all, currentEntities: generateChatInputTextEntities(text)) + if !entities.isEmpty { + attributes.append(TextEntitiesMessageAttribute(entities: entities)) + } + + messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: text.string, attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: item.groupedId, correlationId: nil), uniqueId: item.uniqueId)) case .tempFile: break } @@ -435,13 +451,29 @@ public func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) - arc4random_buf(&randomId, 8) let resource = LocalFileReferenceMediaResource(localFilePath: path, randomId: randomId) let media = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: randomId), partialReference: nil, resource: resource, previewRepresentations: previewRepresentations, videoThumbnails: [], immediateThumbnailData: nil, mimeType: mimeType, size: nil, attributes: [.FileName(fileName: name)]) - messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: caption ?? "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: item.groupedId, correlationId: nil), uniqueId: item.uniqueId)) + + var attributes: [MessageAttribute] = [] + let text = trimChatInputText(convertMarkdownToAttributes(caption ?? NSAttributedString())) + let entities = generateTextEntities(text.string, enabledTypes: .all, currentEntities: generateChatInputTextEntities(text)) + if !entities.isEmpty { + attributes.append(TextEntitiesMessageAttribute(entities: entities)) + } + + messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: text.string, attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: item.groupedId, correlationId: nil), uniqueId: item.uniqueId)) case let .asset(asset): var randomId: Int64 = 0 arc4random_buf(&randomId, 8) let resource = PhotoLibraryMediaResource(localIdentifier: asset.localIdentifier, uniqueId: Int64.random(in: Int64.min ... Int64.max)) let media = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: randomId), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: mimeType, size: nil, attributes: [.FileName(fileName: name)]) - messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: caption ?? "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: item.groupedId, correlationId: nil), uniqueId: item.uniqueId)) + + var attributes: [MessageAttribute] = [] + let text = trimChatInputText(convertMarkdownToAttributes(caption ?? NSAttributedString())) + let entities = generateTextEntities(text.string, enabledTypes: .all, currentEntities: generateChatInputTextEntities(text)) + if !entities.isEmpty { + attributes.append(TextEntitiesMessageAttribute(entities: entities)) + } + + messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: text.string, attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: item.groupedId, correlationId: nil), uniqueId: item.uniqueId)) default: break } @@ -569,7 +601,14 @@ public func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) - if let timer = item.timer, timer > 0 && timer <= 60 { attributes.append(AutoremoveTimeoutMessageAttribute(timeout: Int32(timer), countdownBeginTime: nil)) } - messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: caption ?? "", attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: item.groupedId, correlationId: nil), uniqueId: item.uniqueId)) + + let text = trimChatInputText(convertMarkdownToAttributes(caption ?? NSAttributedString())) + let entities = generateTextEntities(text.string, enabledTypes: .all, currentEntities: generateChatInputTextEntities(text)) + if !entities.isEmpty { + attributes.append(TextEntitiesMessageAttribute(entities: entities)) + } + + messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: text.string, attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: item.groupedId, correlationId: nil), uniqueId: item.uniqueId)) } } } diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyPaintStickersContext.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyPaintStickersContext.swift index 923718dfa5..2c6cfdf256 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyPaintStickersContext.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyPaintStickersContext.swift @@ -414,6 +414,7 @@ public final class LegacyPaintEntityRenderer: NSObject, TGPhotoPaintEntityRender } public final class LegacyPaintStickersContext: NSObject, TGPhotoPaintStickersContext { + public var captionPanelView: (() -> TGCaptionPanelView?)! public var presentStickersController: ((((Any?, Bool, UIView?, CGRect) -> Void)?) -> TGPhotoPaintStickersScreen?)! private let context: AccountContext diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index a90f47bbcc..eee414f612 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -885,7 +885,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } if let mediaReference = mediaReference, let peer = message.peers[message.id.peerId] { - legacyMediaEditor(context: strongSelf.context, peer: peer, media: mediaReference, initialCaption: "", snapshots: snapshots, transitionCompletion: { + legacyMediaEditor(context: strongSelf.context, peer: peer, media: mediaReference, initialCaption: NSAttributedString(), snapshots: snapshots, transitionCompletion: { transitionCompletion() }, presentStickers: { [weak self] completion in if let strongSelf = self { @@ -898,6 +898,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } else { return nil } + }, getCaptionPanelView: { [weak self] in + return self?.getCaptionPanelView() }, sendMessagesWithSignals: { [weak self] signals, _, _ in if let strongSelf = self { strongSelf.enqueueMediaMessages(signals: signals, silentPosting: false) @@ -2842,7 +2844,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } if let mediaReference = mediaReference, let peer = message.peers[message.id.peerId] { - legacyMediaEditor(context: strongSelf.context, peer: peer, media: mediaReference, initialCaption: message.text, snapshots: [], transitionCompletion: nil, presentStickers: { [weak self] completion in + legacyMediaEditor(context: strongSelf.context, peer: peer, media: mediaReference, initialCaption: NSAttributedString(string: message.text), snapshots: [], transitionCompletion: nil, presentStickers: { [weak self] completion in if let strongSelf = self { let controller = DrawingStickersScreen(context: strongSelf.context, selectSticker: { fileReference, node, rect in completion(fileReference.media, fileReference.media.isAnimatedSticker, node.view, rect) @@ -2853,6 +2855,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } else { return nil } + }, getCaptionPanelView: { [weak self] in + return self?.getCaptionPanelView() }, sendMessagesWithSignals: { [weak self] signals, _, _ in if let strongSelf = self { strongSelf.interfaceInteraction?.setupEditMessage(messageId, { _ in }) @@ -9533,6 +9537,84 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G }) } + private func getCaptionPanelView() -> TGCaptionPanelView { + let presentationData = self.presentationData.withUpdated(theme: defaultDarkColorPresentationTheme) + var presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: .builtin(WallpaperSettings()), theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, limitsConfiguration: self.context.currentLimitsConfiguration.with { $0 }, fontSize: presentationData.chatFontSize, bubbleCorners: presentationData.chatBubbleCorners, accountPeerId: self.context.account.peerId, mode: .standard(previewing: false), chatLocation: .peer(PeerId(0)), subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, importState: nil) + + var updateChatPresentationInterfaceStateImpl: (((ChatPresentationInterfaceState) -> ChatPresentationInterfaceState) -> Void)? + + let interfaceInteraction = ChatPanelInterfaceInteraction(updateTextInputStateAndMode: { f in + updateChatPresentationInterfaceStateImpl?({ + let (updatedState, updatedMode) = f($0.interfaceState.effectiveInputState, $0.inputMode) + return $0.updatedInterfaceState { interfaceState in + return interfaceState.withUpdatedEffectiveInputState(updatedState) + }.updatedInputMode({ _ in updatedMode }) + }) + }, updateInputModeAndDismissedButtonKeyboardMessageId: { f in + updateChatPresentationInterfaceStateImpl?({ + let (updatedInputMode, updatedClosedButtonKeyboardMessageId) = f($0) + return $0.updatedInputMode({ _ in return updatedInputMode }).updatedInterfaceState({ + $0.withUpdatedMessageActionsState({ value in + var value = value + value.closedButtonKeyboardMessageId = updatedClosedButtonKeyboardMessageId + return value + }) + }) + }) + }, openLinkEditing: { [weak self] in + if let strongSelf = self { + var selectionRange: Range? + var text: String? + var inputMode: ChatInputMode? + updateChatPresentationInterfaceStateImpl?({ state in + selectionRange = state.interfaceState.effectiveInputState.selectionRange + if let selectionRange = selectionRange { + text = state.interfaceState.effectiveInputState.inputText.attributedSubstring(from: NSRange(location: selectionRange.startIndex, length: selectionRange.count)).string + } + inputMode = state.inputMode + return state + }) + + let controller = chatTextLinkEditController(sharedContext: strongSelf.context.sharedContext, updatedPresentationData: (presentationData, .never()), account: strongSelf.context.account, text: text ?? "", link: nil, apply: { link in + if let inputMode = inputMode, let selectionRange = selectionRange { + if let link = link { + updateChatPresentationInterfaceStateImpl?({ + return $0.updatedInterfaceState({ + $0.withUpdatedComposeInputState(chatTextInputAddLinkAttribute($0.composeInputState, url: link)) + }) + }) + } + updateChatPresentationInterfaceStateImpl?({ + return $0.updatedInputMode({ _ in return inputMode }).updatedInterfaceState({ + $0.withUpdatedEffectiveInputState(ChatTextInputState(inputText: $0.effectiveInputState.inputText, selectionRange: selectionRange.endIndex ..< selectionRange.endIndex)) + }) + }) + } + }) + strongSelf.present(controller, in: .window(.root)) + } + }) + + let inputPanelNode = PeerSelectionTextInputPanelNode(presentationInterfaceState: presentationInterfaceState, isCaption: true, presentController: { _ in }) + inputPanelNode.interfaceInteraction = interfaceInteraction + inputPanelNode.effectivePresentationInterfaceState = { + return presentationInterfaceState + } + + updateChatPresentationInterfaceStateImpl = { [weak inputPanelNode] f in + let updatedPresentationInterfaceState = f(presentationInterfaceState) + let updateInputTextState = presentationInterfaceState.interfaceState.effectiveInputState != updatedPresentationInterfaceState.interfaceState.effectiveInputState + + presentationInterfaceState = updatedPresentationInterfaceState + + if let inputPanelNode = inputPanelNode, updateInputTextState { + inputPanelNode.updateInputTextState(updatedPresentationInterfaceState.interfaceState.effectiveInputState, animated: true) + } + } + + return inputPanelNode + } + private func presentAttachmentMenu(editMediaOptions: MessageMediaEditingOptions?, editMediaReference: AnyMediaReference?) { let _ = (self.context.sharedContext.accountManager.transaction { transaction -> GeneratedMediaStoreSettings in let entry = transaction.getSharedData(ApplicationSpecificSharedDataKeys.generatedMediaStoreSettings)?.get(GeneratedMediaStoreSettings.self) @@ -9628,7 +9710,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G slowModeEnabled = true } - let controller = legacyAttachmentMenu(context: strongSelf.context, peer: peer, chatLocation: strongSelf.chatLocation, editMediaOptions: menuEditMediaOptions, saveEditedPhotos: settings.storeEditedPhotos, allowGrouping: true, hasSchedule: strongSelf.presentationInterfaceState.subject != .scheduledMessages && peer.id.namespace != Namespaces.Peer.SecretChat, canSendPolls: canSendPolls, updatedPresentationData: strongSelf.updatedPresentationData, parentController: legacyController, recentlyUsedInlineBots: strongSelf.recentlyUsedInlineBotsValue, initialCaption: inputText.string, openGallery: { + let controller = legacyAttachmentMenu(context: strongSelf.context, peer: peer, chatLocation: strongSelf.chatLocation, editMediaOptions: menuEditMediaOptions, saveEditedPhotos: settings.storeEditedPhotos, allowGrouping: true, hasSchedule: strongSelf.presentationInterfaceState.subject != .scheduledMessages && peer.id.namespace != Namespaces.Peer.SecretChat, canSendPolls: canSendPolls, updatedPresentationData: strongSelf.updatedPresentationData, parentController: legacyController, recentlyUsedInlineBots: strongSelf.recentlyUsedInlineBotsValue, initialCaption: inputText, openGallery: { self?.presentMediaPicker(fileMode: false, editingMedia: editMediaOptions != nil, completion: { signals, silentPosting, scheduleTime in if !inputText.string.isEmpty { strongSelf.clearInputText() @@ -9691,6 +9773,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } else { return nil } + }, getCaptionPanelView: { [weak self] in + return self?.getCaptionPanelView() }) } }, openFileGallery: { @@ -9783,6 +9867,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } else { return nil } + }, getCaptionPanelView: { [weak self] in + return self?.getCaptionPanelView() }, present: { [weak self] c, a in self?.present(c, in: .window(.root), with: a) }) @@ -9948,7 +10034,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G legacyController.bind(controller: controller) legacyController.deferScreenEdgeGestures = [.top] - configureLegacyAssetPicker(controller, context: strongSelf.context, peer: peer, chatLocation: strongSelf.chatLocation, initialCaption: inputText.string, hasSchedule: strongSelf.presentationInterfaceState.subject != .scheduledMessages && peer.id.namespace != Namespaces.Peer.SecretChat, presentWebSearch: editingMedia ? nil : { [weak self, weak legacyController] in + configureLegacyAssetPicker(controller, context: strongSelf.context, peer: peer, chatLocation: strongSelf.chatLocation, initialCaption: inputText, hasSchedule: strongSelf.presentationInterfaceState.subject != .scheduledMessages && peer.id.namespace != Namespaces.Peer.SecretChat, presentWebSearch: editingMedia ? nil : { [weak self, weak legacyController] in if let strongSelf = self { let controller = WebSearchController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: EnginePeer(peer), chatLocation: strongSelf.chatLocation, configuration: searchBotsConfiguration, mode: .media(completion: { results, selectionState, editingState, silentPosting in if let legacyController = legacyController { @@ -10023,6 +10109,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } else { return nil } + }, getCaptionPanelView: { [weak self] in + return self?.getCaptionPanelView() }) controller.descriptionGenerator = legacyAssetPickerItemGenerator() controller.completionBlock = { [weak legacyController] signals, silentPosting, scheduleTime in @@ -10806,6 +10894,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } else { return nil } + }, getCaptionPanelView: { [weak self] in + return self?.getCaptionPanelView() }, present: { [weak self] controller, arguments in if let strongSelf = self { strongSelf.present(controller, in: .window(.root), with: arguments) diff --git a/submodules/TelegramUI/Sources/ChatPanelInterfaceInteraction.swift b/submodules/TelegramUI/Sources/ChatPanelInterfaceInteraction.swift index 53d3987852..f020bc06ab 100644 --- a/submodules/TelegramUI/Sources/ChatPanelInterfaceInteraction.swift +++ b/submodules/TelegramUI/Sources/ChatPanelInterfaceInteraction.swift @@ -314,4 +314,99 @@ final class ChatPanelInterfaceInteraction { self.openSendAsPeer = openSendAsPeer self.statuses = statuses } + + convenience init( + updateTextInputStateAndMode: @escaping ((ChatTextInputState, ChatInputMode) -> (ChatTextInputState, ChatInputMode)) -> Void, + updateInputModeAndDismissedButtonKeyboardMessageId: @escaping ((ChatPresentationInterfaceState) -> (ChatInputMode, MessageId?)) -> Void, + openLinkEditing: @escaping () -> Void + ) { + self.init(setupReplyMessage: { _, _ in + }, setupEditMessage: { _, _ in + }, beginMessageSelection: { _, _ in + }, deleteSelectedMessages: { + }, reportSelectedMessages: { + }, reportMessages: { _, _ in + }, blockMessageAuthor: { _, _ in + }, deleteMessages: { _, _, f in + f(.default) + }, forwardSelectedMessages: { + }, forwardCurrentForwardMessages: { + }, forwardMessages: { _ in + }, updateForwardOptionsState: { _ in + }, presentForwardOptions: { _ in + }, shareSelectedMessages: { + }, updateTextInputStateAndMode: updateTextInputStateAndMode, updateInputModeAndDismissedButtonKeyboardMessageId: updateInputModeAndDismissedButtonKeyboardMessageId, openStickers: { + }, editMessage: { + }, beginMessageSearch: { _, _ in + }, dismissMessageSearch: { + }, updateMessageSearch: { _ in + }, openSearchResults: { + }, navigateMessageSearch: { _ in + }, openCalendarSearch: { + }, toggleMembersSearch: { _ in + }, navigateToMessage: { _, _, _, _ in + }, navigateToChat: { _ in + }, navigateToProfile: { _ in + }, openPeerInfo: { + }, togglePeerNotifications: { + }, sendContextResult: { _, _, _, _ in + return false + }, sendBotCommand: { _, _ in + }, sendBotStart: { _ in + }, botSwitchChatWithPayload: { _, _ in + }, beginMediaRecording: { _ in + }, finishMediaRecording: { _ in + }, stopMediaRecording: { + }, lockMediaRecording: { + }, deleteRecordedMedia: { + }, sendRecordedMedia: { _ in + }, displayRestrictedInfo: { _, _ in + }, displayVideoUnmuteTip: { _ in + }, switchMediaRecordingMode: { + }, setupMessageAutoremoveTimeout: { + }, sendSticker: { _, _, _, _ in + return false + }, unblockPeer: { + }, pinMessage: { _, _ in + }, unpinMessage: { _, _, _ in + }, unpinAllMessages: { + }, openPinnedList: { _ in + }, shareAccountContact: { + }, reportPeer: { + }, presentPeerContact: { + }, dismissReportPeer: { + }, deleteChat: { + }, beginCall: { _ in + }, toggleMessageStickerStarred: { _ in + }, presentController: { _, _ in + }, getNavigationController: { + return nil + }, presentGlobalOverlayController: { _, _ in + }, navigateFeed: { + }, openGrouping: { + }, toggleSilentPost: { + }, requestUnvoteInMessage: { _ in + }, requestStopPollInMessage: { _ in + }, updateInputLanguage: { _ in + }, unarchiveChat: { + }, openLinkEditing: openLinkEditing, reportPeerIrrelevantGeoLocation: { + }, displaySlowmodeTooltip: { _, _ in + }, displaySendMessageOptions: { _, _ in + }, openScheduledMessages: { + }, openPeersNearby: { + }, displaySearchResultsTooltip: { _, _ in + }, unarchivePeer: { + }, scrollToTop: { + }, viewReplies: { _, _ in + }, activatePinnedListPreview: { _, _ in + }, joinGroupCall: { _ in + }, presentInviteMembers: { + }, presentGigagroupHelp: { + }, editMessageMedia: { _, _ in + }, updateShowCommands: { _ in + }, updateShowSendAsPeers: { _ in + }, openInviteRequests: { + }, openSendAsPeer: { _, _ in + }, statuses: nil) + } } diff --git a/submodules/TelegramUI/Sources/LegacyCamera.swift b/submodules/TelegramUI/Sources/LegacyCamera.swift index 6e2cfa28ea..b9e42eca07 100644 --- a/submodules/TelegramUI/Sources/LegacyCamera.swift +++ b/submodules/TelegramUI/Sources/LegacyCamera.swift @@ -10,7 +10,7 @@ import ShareController import LegacyUI import LegacyMediaPickerUI -func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: ChatLocation, cameraView: TGAttachmentCameraView?, menuController: TGMenuSheetController?, parentController: ViewController, editingMedia: Bool, saveCapturedPhotos: Bool, mediaGrouping: Bool, initialCaption: String, hasSchedule: Bool, photoOnly: Bool, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, recognizedQRCode: @escaping (String) -> Void = { _ in }, presentSchedulePicker: @escaping (@escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?) { +func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: ChatLocation, cameraView: TGAttachmentCameraView?, menuController: TGMenuSheetController?, parentController: ViewController, editingMedia: Bool, saveCapturedPhotos: Bool, mediaGrouping: Bool, initialCaption: String, hasSchedule: Bool, photoOnly: Bool, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, recognizedQRCode: @escaping (String) -> Void = { _ in }, presentSchedulePicker: @escaping (@escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, getCaptionPanelView: @escaping () -> TGCaptionPanelView?) { let presentationData = context.sharedContext.currentPresentationData.with { $0 } let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme) legacyController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .portrait, compactSize: .portrait) @@ -63,6 +63,9 @@ func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: Ch } let paintStickersContext = LegacyPaintStickersContext(context: context) + paintStickersContext.captionPanelView = { + return getCaptionPanelView() + } paintStickersContext.presentStickersController = { completion in return presentStickers({ file, animated, view, rect in let coder = PostboxEncoder() @@ -123,8 +126,8 @@ func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: Ch controller.finishedWithResults = { [weak menuController, weak legacyController] overlayController, selectionContext, editingContext, currentItem, silentPosting, scheduleTime in if let selectionContext = selectionContext, let editingContext = editingContext { let nativeGenerator = legacyAssetPickerItemGenerator() - let signals = TGCameraController.resultSignals(for: selectionContext, editingContext: editingContext, currentItem: currentItem, storeAssets: saveCapturedPhotos && !isSecretChat, saveEditedPhotos: saveCapturedPhotos && !isSecretChat, descriptionGenerator: { _1, _2, _3, _4 in - nativeGenerator(_1, _2, _3, _4, nil) + let signals = TGCameraController.resultSignals(for: selectionContext, editingContext: editingContext, currentItem: currentItem, storeAssets: saveCapturedPhotos && !isSecretChat, saveEditedPhotos: saveCapturedPhotos && !isSecretChat, descriptionGenerator: { _1, _2, _3 in + nativeGenerator(_1, _2, _3, nil) }) sendMessagesWithSignals(signals, silentPosting, scheduleTime) } @@ -133,7 +136,7 @@ func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: Ch legacyController?.dismissWithAnimation() } - controller.finishedWithPhoto = { [weak menuController, weak legacyController] overlayController, image, caption, entities, stickers, timer in + controller.finishedWithPhoto = { [weak menuController, weak legacyController] overlayController, image, caption, stickers, timer in if let image = image { let description = NSMutableDictionary() description["type"] = "capturedPhoto" @@ -141,7 +144,7 @@ func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: Ch if let timer = timer { description["timer"] = timer } - if let item = legacyAssetPickerItemGenerator()(description, caption, entities, nil, nil) { + if let item = legacyAssetPickerItemGenerator()(description, caption, nil, nil) { sendMessagesWithSignals([SSignal.single(item)], false, 0) } } @@ -150,7 +153,7 @@ func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: Ch legacyController?.dismissWithAnimation() } - controller.finishedWithVideo = { [weak menuController, weak legacyController] overlayController, videoURL, previewImage, duration, dimensions, adjustments, caption, entities, stickers, timer in + controller.finishedWithVideo = { [weak menuController, weak legacyController] overlayController, videoURL, previewImage, duration, dimensions, adjustments, caption, stickers, timer in if let videoURL = videoURL { let description = NSMutableDictionary() description["type"] = "video" @@ -166,7 +169,7 @@ func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: Ch if let timer = timer { description["timer"] = timer } - if let item = legacyAssetPickerItemGenerator()(description, caption, entities, nil, nil) { + if let item = legacyAssetPickerItemGenerator()(description, caption, nil, nil) { sendMessagesWithSignals([SSignal.single(item)], false, 0) } } @@ -220,8 +223,8 @@ func presentedLegacyShortcutCamera(context: AccountContext, saveCapturedMedia: B controller.finishedWithResults = { [weak parentController] overlayController, selectionContext, editingContext, currentItem, _, _ in if let selectionContext = selectionContext, let editingContext = editingContext { let nativeGenerator = legacyAssetPickerItemGenerator() - let signals = TGCameraController.resultSignals(for: selectionContext, editingContext: editingContext, currentItem: currentItem, storeAssets: saveCapturedMedia, saveEditedPhotos: saveEditedPhotos, descriptionGenerator: { _1, _2, _3, _4 in - nativeGenerator(_1, _2, _3, _4, nil) + let signals = TGCameraController.resultSignals(for: selectionContext, editingContext: editingContext, currentItem: currentItem, storeAssets: saveCapturedMedia, saveEditedPhotos: saveEditedPhotos, descriptionGenerator: { _1, _2, _3 in + nativeGenerator(_1, _2, _3, nil) }) if let parentController = parentController { parentController.present(ShareController(context: context, subject: .fromExternal({ peerIds, text, account in diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 077f4fde8f..245740a8f6 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -3096,7 +3096,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } if let mediaReference = mediaReference, let peer = message.peers[message.id.peerId] { - legacyMediaEditor(context: strongSelf.context, peer: peer, media: mediaReference, initialCaption: "", snapshots: snapshots, transitionCompletion: { + legacyMediaEditor(context: strongSelf.context, peer: peer, media: mediaReference, initialCaption: NSAttributedString(), snapshots: snapshots, transitionCompletion: { transitionCompletion() }, presentStickers: { [weak self] completion in if let strongSelf = self { @@ -3109,6 +3109,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } else { return nil } + }, getCaptionPanelView: { + return nil }, sendMessagesWithSignals: { [weak self] signals, _, _ in if let strongSelf = self { strongSelf.enqueueMediaMessageDisposable.set((legacyAssetPickerEnqueueMessages(account: strongSelf.context.account, signals: signals!) diff --git a/submodules/TelegramUI/Sources/PeerSelectionTextInputPanelNode.swift b/submodules/TelegramUI/Sources/PeerSelectionTextInputPanelNode.swift index a3fd61e1bd..9b44d162f9 100644 --- a/submodules/TelegramUI/Sources/PeerSelectionTextInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/PeerSelectionTextInputPanelNode.swift @@ -13,6 +13,7 @@ import TouchDownGesture import ActivityIndicator import Speak import ObjCRuntimeUtils +import LegacyComponents private let counterFont = Font.with(size: 14.0, design: .regular, traits: [.monospacedNumbers]) private let minInputFontSize = chatTextInputMinFontSize @@ -62,7 +63,7 @@ private func calculateTextFieldRealInsets(_ presentationInterfaceState: ChatPres } private var currentTextInputBackgroundImage: (UIColor, UIColor, CGFloat, UIImage)? -private func textInputBackgroundImage(backgroundColor: UIColor?, inputBackgroundColor: UIColor?, strokeColor: UIColor, diameter: CGFloat) -> UIImage? { +private func textInputBackgroundImage(backgroundColor: UIColor?, inputBackgroundColor: UIColor?, strokeColor: UIColor, diameter: CGFloat, caption: Bool) -> UIImage? { if let backgroundColor = backgroundColor, let current = currentTextInputBackgroundImage { if current.0.isEqual(backgroundColor) && current.1.isEqual(strokeColor) && current.2.isEqual(to: diameter) { return current.3 @@ -72,7 +73,10 @@ private func textInputBackgroundImage(backgroundColor: UIColor?, inputBackground let image = generateImage(CGSize(width: diameter, height: diameter), rotatedContext: { size, context in context.clear(CGRect(x: 0.0, y: 0.0, width: diameter, height: diameter)) - if let inputBackgroundColor = inputBackgroundColor { + if caption { + context.setBlendMode(.normal) + context.setFillColor(strokeColor.cgColor) + } else if let inputBackgroundColor = inputBackgroundColor { context.setBlendMode(.normal) context.setFillColor(inputBackgroundColor.cgColor) } else { @@ -81,11 +85,13 @@ private func textInputBackgroundImage(backgroundColor: UIColor?, inputBackground } context.fillEllipse(in: CGRect(x: 0.0, y: 0.0, width: diameter, height: diameter)) - context.setBlendMode(.normal) - context.setStrokeColor(strokeColor.cgColor) - let strokeWidth: CGFloat = 1.0 - context.setLineWidth(strokeWidth) - context.strokeEllipse(in: CGRect(x: strokeWidth / 2.0, y: strokeWidth / 2.0, width: diameter - strokeWidth, height: diameter - strokeWidth)) + if !caption { + context.setBlendMode(.normal) + context.setStrokeColor(strokeColor.cgColor) + let strokeWidth: CGFloat = 1.0 + context.setLineWidth(strokeWidth) + context.strokeEllipse(in: CGRect(x: strokeWidth / 2.0, y: strokeWidth / 2.0, width: diameter - strokeWidth, height: diameter - strokeWidth)) + } })?.stretchableImage(withLeftCapWidth: Int(diameter) / 2, topCapHeight: Int(diameter) / 2) if let image = image { if let backgroundColor = backgroundColor { @@ -97,13 +103,16 @@ private func textInputBackgroundImage(backgroundColor: UIColor?, inputBackground } } -class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { +class PeerSelectionTextInputPanelNode: ChatInputPanelNode, TGCaptionPanelView, ASEditableTextNodeDelegate { + private let isCaption: Bool + var textPlaceholderNode: ImmediateTextNode let textInputContainerBackgroundNode: ASImageNode let textInputContainer: ASDisplayNode var textInputNode: EditableTextNode? - let textInputBackgroundNode: ASImageNode + let textInputBackgroundNode: ASDisplayNode + let textInputBackgroundImageNode: ASImageNode private var transparentTextInputBackgroundImage: UIImage? let actionButtons: ChatTextInputActionButtonsNode private let counterTextNode: ImmediateTextNode @@ -117,6 +126,7 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel private var currentPlaceholder: String? + var effectivePresentationInterfaceState: (() -> ChatPresentationInterfaceState?)? private var presentationInterfaceState: ChatPresentationInterfaceState? private var initializedPlaceholder = false @@ -212,18 +222,24 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel private let textInputViewInternalInsets = UIEdgeInsets(top: 1.0, left: 13.0, bottom: 1.0, right: 13.0) - init(presentationInterfaceState: ChatPresentationInterfaceState, presentController: @escaping (ViewController) -> Void) { + init(presentationInterfaceState: ChatPresentationInterfaceState, isCaption: Bool = false, presentController: @escaping (ViewController) -> Void) { + self.presentationInterfaceState = presentationInterfaceState + self.isCaption = isCaption + self.textInputContainerBackgroundNode = ASImageNode() self.textInputContainerBackgroundNode.isUserInteractionEnabled = false self.textInputContainerBackgroundNode.displaysAsynchronously = false self.textInputContainer = ASDisplayNode() - self.textInputContainer.addSubnode(self.textInputContainerBackgroundNode) + if !isCaption { + self.textInputContainer.addSubnode(self.textInputContainerBackgroundNode) + } self.textInputContainer.clipsToBounds = true - self.textInputBackgroundNode = ASImageNode() - self.textInputBackgroundNode.displaysAsynchronously = false - self.textInputBackgroundNode.displayWithoutProcessing = true + self.textInputBackgroundNode = ASDisplayNode() + self.textInputBackgroundImageNode = ASImageNode() + self.textInputBackgroundImageNode.displaysAsynchronously = false + self.textInputBackgroundImageNode.displayWithoutProcessing = true self.textPlaceholderNode = ImmediateTextNode() self.textPlaceholderNode.maximumNumberOfLines = 1 self.textPlaceholderNode.isUserInteractionEnabled = false @@ -246,23 +262,48 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel self.addSubnode(self.textInputContainer) self.addSubnode(self.textInputBackgroundNode) + self.textInputBackgroundNode.addSubnode(self.textInputBackgroundImageNode) self.addSubnode(self.textPlaceholderNode) self.addSubnode(self.actionButtons) self.addSubnode(self.counterTextNode) - self.textInputBackgroundNode.clipsToBounds = true + self.textInputBackgroundImageNode.clipsToBounds = true let recognizer = TouchDownGestureRecognizer(target: self, action: #selector(self.textInputBackgroundViewTap(_:))) recognizer.touchDown = { [weak self] in if let strongSelf = self { strongSelf.ensureFocused() } } - self.textInputBackgroundNode.isUserInteractionEnabled = true self.textInputBackgroundNode.view.addGestureRecognizer(recognizer) - self.updateSendButtonEnabled(false, animated: false) + self.updateSendButtonEnabled(isCaption, animated: false) + } + + var sendPressed: ((NSAttributedString?) -> Void)? + var focusUpdated: ((Bool) -> Void)? + var heightUpdated: ((Bool) -> Void)? + + public func updateLayoutSize(_ size: CGSize, sideInset: CGFloat) -> CGFloat { + guard let presentationInterfaceState = self.presentationInterfaceState else { + return 0.0 + } + return self.updateLayout(width: size.width, leftInset: sideInset, rightInset: sideInset, additionalSideInsets: UIEdgeInsets(), maxHeight: size.height, isSecondary: false, transition: .immediate, interfaceState: presentationInterfaceState, metrics: LayoutMetrics(widthClass: .compact, heightClass: .compact)) + } + + public func setCaption(_ caption: NSAttributedString?) { + self.interfaceInteraction?.updateTextInputStateAndMode { state, inputMode in + return (ChatTextInputState(inputText: caption ?? NSAttributedString()), inputMode) + } + } + + public func dismissInput() { + self.view.window?.endEditing(true) + } + + public func baseHeight() -> CGFloat { + return 45.0 } required init?(coder aDecoder: NSCoder) { @@ -391,18 +432,18 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel } override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { + let hadLayout = self.validLayout != nil let previousAdditionalSideInsets = self.validLayout?.3 self.validLayout = (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, isSecondary) var transition = transition if let previousAdditionalSideInsets = previousAdditionalSideInsets, previousAdditionalSideInsets.right != additionalSideInsets.right { - if case .animated = transition { transition = .animated(duration: 0.2, curve: .easeInOut) } } - if self.presentationInterfaceState != interfaceState { + if self.presentationInterfaceState != interfaceState || !hadLayout { let previousState = self.presentationInterfaceState self.presentationInterfaceState = interfaceState @@ -418,12 +459,17 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel if self.theme == nil || !self.theme!.chat.inputPanel.inputTextColor.isEqual(interfaceState.theme.chat.inputPanel.inputTextColor) { let textColor = interfaceState.theme.chat.inputPanel.inputTextColor let baseFontSize = max(minInputFontSize, interfaceState.fontSize.baseDisplaySize) - + if let textInputNode = self.textInputNode { - if let text = textInputNode.attributedText?.string { - let range = textInputNode.selectedRange - textInputNode.attributedText = NSAttributedString(string: text, font: Font.regular(baseFontSize), textColor: textColor) - textInputNode.selectedRange = range + if let text = textInputNode.attributedText { + let selectedRange = textInputNode.selectedRange + let textRange = NSMakeRange(0, (text.string as NSString).length) + let updatedText = NSMutableAttributedString(attributedString: text) + updatedText.removeAttribute(.foregroundColor, range: textRange) + updatedText.addAttribute(.foregroundColor, value: textColor, range: textRange) + + textInputNode.attributedText = updatedText + textInputNode.selectedRange = selectedRange } textInputNode.typingAttributes = [NSAttributedString.Key.font.rawValue: Font.regular(baseFontSize), NSAttributedString.Key.foregroundColor.rawValue: textColor] } @@ -452,8 +498,8 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel backgroundColor = interfaceState.theme.chat.inputPanel.panelBackgroundColor } - self.textInputBackgroundNode.image = textInputBackgroundImage(backgroundColor: backgroundColor, inputBackgroundColor: nil, strokeColor: interfaceState.theme.chat.inputPanel.inputStrokeColor, diameter: minimalInputHeight) - self.transparentTextInputBackgroundImage = textInputBackgroundImage(backgroundColor: nil, inputBackgroundColor: interfaceState.theme.chat.inputPanel.inputBackgroundColor, strokeColor: interfaceState.theme.chat.inputPanel.inputStrokeColor, diameter: minimalInputHeight) + self.textInputBackgroundImageNode.image = textInputBackgroundImage(backgroundColor: backgroundColor, inputBackgroundColor: nil, strokeColor: interfaceState.theme.chat.inputPanel.inputStrokeColor, diameter: minimalInputHeight, caption: self.isCaption) + self.transparentTextInputBackgroundImage = textInputBackgroundImage(backgroundColor: nil, inputBackgroundColor: interfaceState.theme.chat.inputPanel.inputBackgroundColor, strokeColor: interfaceState.theme.chat.inputPanel.inputStrokeColor, diameter: minimalInputHeight, caption: self.isCaption) self.textInputContainerBackgroundNode.image = generateStretchableFilledCircleImage(diameter: minimalInputHeight, color: interfaceState.theme.chat.inputPanel.inputBackgroundColor) } else { if self.strings !== interfaceState.strings { @@ -465,7 +511,7 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel if themeUpdated || !self.initializedPlaceholder { self.initializedPlaceholder = true - let placeholder = interfaceState.strings.Conversation_InputTextPlaceholder + let placeholder = self.isCaption ? interfaceState.strings.MediaPicker_AddCaption : interfaceState.strings.Conversation_InputTextPlaceholder if self.currentPlaceholder != placeholder || themeUpdated { self.currentPlaceholder = placeholder @@ -486,7 +532,7 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel self.actionButtons.sendButtonLongPressEnabled = true } - let sendButtonHasApplyIcon = interfaceState.interfaceState.editMessage != nil + let sendButtonHasApplyIcon = self.isCaption || interfaceState.interfaceState.editMessage != nil if updateSendButtonIcon { if !self.actionButtons.animatingSendButton { @@ -524,10 +570,31 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel let (_, textFieldHeight) = self.calculateTextFieldMetrics(width: baseWidth, maxHeight: maxHeight, metrics: metrics) let panelHeight = self.panelHeight(textFieldHeight: textFieldHeight, metrics: metrics) - let composeButtonsOffset: CGFloat = 0.0 + var composeButtonsOffset: CGFloat = 0.0 let textInputBackgroundWidthOffset: CGFloat = 0.0 self.updateCounterTextNode(transition: transition) + + var inputHasText = false + if let textInputNode = self.textInputNode, let attributedText = textInputNode.attributedText, attributedText.length != 0 { + inputHasText = true + } + + if self.isCaption { + if self.isFocused { + transition.updateAlpha(node: self.actionButtons, alpha: 1.0) + transition.updateTransformScale(node: self.actionButtons, scale: 1.0) + composeButtonsOffset = 0.0 + + transition.updateAlpha(node: self.textInputBackgroundImageNode, alpha: 1.0) + } else { + transition.updateAlpha(node: self.actionButtons, alpha: 0.0) + transition.updateTransformScale(node: self.actionButtons, scale: 0.001) + composeButtonsOffset = 36.0 + + transition.updateAlpha(node: self.textInputBackgroundImageNode, alpha: inputHasText ? 1.0 : 0.0) + } + } let actionButtonsFrame = CGRect(origin: CGPoint(x: width - rightInset - 43.0 - UIScreenPixel + composeButtonsOffset, y: panelHeight - minimalHeight), size: CGSize(width: 44.0, height: minimalHeight)) transition.updateFrame(node: self.actionButtons, frame: actionButtonsFrame) @@ -547,8 +614,9 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel } let textInputFrame = CGRect(x: leftInset + textFieldInsets.left, y: textFieldInsets.top, width: baseWidth - textFieldInsets.left - textFieldInsets.right + textInputBackgroundWidthOffset, height: panelHeight - textFieldInsets.top - textFieldInsets.bottom) + let textInputBackgroundFrame = CGRect(origin: CGPoint(), size: CGSize(width: textInputFrame.size.width + composeButtonsOffset, height: textInputFrame.size.height)) transition.updateFrame(node: self.textInputContainer, frame: textInputFrame) - transition.updateFrame(node: self.textInputContainerBackgroundNode, frame: CGRect(origin: CGPoint(), size: textInputFrame.size)) + transition.updateFrame(node: self.textInputContainerBackgroundNode, frame: textInputBackgroundFrame) if let textInputNode = self.textInputNode { let textFieldFrame = CGRect(origin: CGPoint(x: self.textInputViewInternalInsets.left, y: self.textInputViewInternalInsets.top), size: CGSize(width: textInputFrame.size.width - (self.textInputViewInternalInsets.left + self.textInputViewInternalInsets.right), height: textInputFrame.size.height - self.textInputViewInternalInsets.top - textInputViewInternalInsets.bottom)) @@ -559,15 +627,18 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel } } - var inputHasText = false - if let textInputNode = self.textInputNode, let attributedText = textInputNode.attributedText, attributedText.length != 0 { - inputHasText = true + self.textPlaceholderNode.isHidden = inputHasText + + let placeholderFrame: CGRect + if self.isCaption && !self.isFocused { + placeholderFrame = CGRect(origin: CGPoint(x: textInputFrame.minX + floorToScreenPixels((textInputBackgroundFrame.width - self.textPlaceholderNode.frame.width) / 2.0), y: textFieldInsets.top + self.textInputViewInternalInsets.top + textInputViewRealInsets.top + UIScreenPixel), size: self.textPlaceholderNode.frame.size) + } else { + placeholderFrame = CGRect(origin: CGPoint(x: leftInset + textFieldInsets.left + self.textInputViewInternalInsets.left, y: textFieldInsets.top + self.textInputViewInternalInsets.top + textInputViewRealInsets.top + UIScreenPixel), size: self.textPlaceholderNode.frame.size) } - self.textPlaceholderNode.isHidden = inputHasText - - transition.updateFrame(node: self.textPlaceholderNode, frame: CGRect(origin: CGPoint(x: leftInset + textFieldInsets.left + self.textInputViewInternalInsets.left, y: textFieldInsets.top + self.textInputViewInternalInsets.top + textInputViewRealInsets.top + UIScreenPixel), size: self.textPlaceholderNode.frame.size)) - transition.updateFrame(layer: self.textInputBackgroundNode.layer, frame: CGRect(x: leftInset + textFieldInsets.left, y: textFieldInsets.top, width: baseWidth - textFieldInsets.left - textFieldInsets.right + textInputBackgroundWidthOffset, height: panelHeight - textFieldInsets.top - textFieldInsets.bottom)) + transition.updateFrame(node: self.textPlaceholderNode, frame: placeholderFrame) + transition.updateFrame(layer: self.textInputBackgroundNode.layer, frame: CGRect(x: leftInset + textFieldInsets.left, y: textFieldInsets.top, width: baseWidth - textFieldInsets.left - textFieldInsets.right + textInputBackgroundWidthOffset + composeButtonsOffset, height: panelHeight - textFieldInsets.top - textFieldInsets.bottom)) + transition.updateFrame(layer: self.textInputBackgroundImageNode.layer, frame: CGRect(x: 0.0, y: 0.0, width: baseWidth - textFieldInsets.left - textFieldInsets.right + textInputBackgroundWidthOffset + composeButtonsOffset, height: panelHeight - textFieldInsets.top - textFieldInsets.bottom)) self.actionButtons.updateAccessibility() @@ -592,6 +663,12 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel self.interfaceInteraction?.updateTextInputStateAndMode({ _, inputMode in return (inputTextState, inputMode) }) self.interfaceInteraction?.updateInputLanguage({ _ in return textInputNode.textInputMode.primaryLanguage }) + if self.isCaption, let presentationInterfaceState = self.presentationInterfaceState { + self.presentationInterfaceState = presentationInterfaceState.updatedInterfaceState({ + return $0.withUpdatedComposeInputState(inputTextState) + }) + + } self.updateTextNodeText(animated: true) self.updateCounterTextNode(transition: .immediate) @@ -647,6 +724,7 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel let panelHeight = self.panelHeight(textFieldHeight: textFieldHeight, metrics: metrics) if !self.bounds.size.height.isEqual(to: panelHeight) { self.updateHeight(animated) + self.heightUpdated?(animated) } } } @@ -699,11 +777,23 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel return (.text, state.keyboardButtonsMessage?.id) }) self.inputMenu.activate() + + self.focusUpdated?(true) + + if self.isCaption, let (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, isSecondary) = self.validLayout, let presentationInterfaceState = self.presentationInterfaceState { + let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: .animated(duration: 0.3, curve: .easeInOut), interfaceState: presentationInterfaceState, metrics: metrics) + } } func editableTextNodeDidFinishEditing(_ editableTextNode: ASEditableTextNode) { self.storedInputLanguage = editableTextNode.textInputMode.primaryLanguage self.inputMenu.deactivate() + + self.focusUpdated?(false) + + if self.isCaption, let (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, isSecondary) = self.validLayout, let presentationInterfaceState = self.presentationInterfaceState { + let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: .animated(duration: 0.3, curve: .easeInOut), interfaceState: presentationInterfaceState, metrics: metrics) + } } func editableTextNodeTarget(forAction action: Selector) -> ASEditableTextNodeTargetForAction? { @@ -877,6 +967,12 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel } @objc func sendButtonPressed() { + if let sendPressed = self.sendPressed, let presentationInterfaceState = self.effectivePresentationInterfaceState?() { + self.dismissInput() + let effectiveInputText = presentationInterfaceState.interfaceState.composeInputState.inputText + sendPressed(effectiveInputText) + return + } if let textInputNode = self.textInputNode, let presentationInterfaceState = self.presentationInterfaceState, let editMessage = presentationInterfaceState.interfaceState.editMessage, let inputTextMaxLength = editMessage.inputTextMaxLength { let textCount = Int32(textInputNode.textView.text.count) let remainingCount = inputTextMaxLength - textCount diff --git a/submodules/WebSearchUI/Sources/LegacyWebSearchGallery.swift b/submodules/WebSearchUI/Sources/LegacyWebSearchGallery.swift index d41f41da01..ba3e9c36dc 100644 --- a/submodules/WebSearchUI/Sources/LegacyWebSearchGallery.swift +++ b/submodules/WebSearchUI/Sources/LegacyWebSearchGallery.swift @@ -358,9 +358,9 @@ func presentLegacyWebSearchGallery(context: AccountContext, peer: EnginePeer?, c model.didFinishEditingItem = { item, adjustments, result, thumbnail in editingContext.setImage(result, thumbnailImage: thumbnail, for: item, synchronous: true) } - model.saveItemCaption = { item, caption, entities in - editingContext.setCaption(caption, entities: entities, for: item) - if let selectionContext = selectionContext, let caption = caption, caption.count > 0, let item = item as? TGMediaSelectableItem { + model.saveItemCaption = { item, caption in + editingContext.setCaption(caption, for: item) + if let selectionContext = selectionContext, let caption = caption, caption.length > 0, let item = item as? TGMediaSelectableItem { selectionContext.setItem(item, selected: true) } } @@ -465,7 +465,7 @@ public func legacyEnqueueWebSearchMessages(_ selectionState: TGMediaSelectionCon } } - return legacyAssetPickerItemGenerator()(dict, nil, nil, nil, nil) as Any + return legacyAssetPickerItemGenerator()(dict, nil, nil, nil) as Any } else { return SSignal.complete() }