Merge branch 'caption-markdown'

This commit is contained in:
Ilya Laktyushin 2021-11-18 15:06:04 +04:00
commit be6adb3b06
33 changed files with 777 additions and 455 deletions

View File

@ -46,14 +46,13 @@ typedef enum {
@property (nonatomic, strong) id<TGPhotoPaintStickersContext> 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<TGMediaSelectableItem> 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<LegacyComponentsContext>)context saveEditedPhotos:(bool)saveEditedPhotos saveCapturedMedia:(bool)saveCapturedMedia intent:(TGCameraControllerIntent)intent;
- (instancetype)initWithContext:(id<LegacyComponentsContext>)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<TGMediaSelectableItem>)currentItem storeAssets:(bool)storeAssets saveEditedPhotos:(bool)saveEditedPhotos descriptionGenerator:(id (^)(id, NSString *, NSArray *, NSString *))descriptionGenerator;
+ (NSArray *)resultSignalsForSelectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext currentItem:(id<TGMediaSelectableItem>)currentItem storeAssets:(bool)storeAssets saveEditedPhotos:(bool)saveEditedPhotos descriptionGenerator:(id (^)(id, NSAttributedString *, NSString *))descriptionGenerator;
- (void)beginTransitionInFromRect:(CGRect)rect;
- (void)_dismissTransitionForResultController:(TGOverlayController *)resultController;

View File

@ -16,6 +16,7 @@
+ (TGMenuSheetController *)presentInParentController:(TGViewController *)parentController context:(id<LegacyComponentsContext>)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<TGPhotoPaintStickersContext>)stickersContext presentScheduleController:(void (^)(void(^)(int32_t)))presentScheduleController presentTimerController:(void (^)(void(^)(int32_t)))presentTimerController completed:(void (^)(TGMediaSelectionContext *selectionContext, TGMediaEditingContext *editingContext, id<TGMediaSelectableItem> 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<TGMediaSelectableItem>)currentItem descriptionGenerator:(id (^)(id, NSString *, NSArray *, NSString *))descriptionGenerator;
+ (NSArray *)resultSignalsForSelectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext currentItem:(id<TGMediaSelectableItem>)currentItem descriptionGenerator:(id (^)(id, NSAttributedString *,
NSString *))descriptionGenerator;
@end

View File

@ -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

View File

@ -62,14 +62,13 @@
- (SSignal *)fullSizeImageUrlForItem:(id<TGMediaEditableItem>)item;
- (NSString *)captionForItem:(NSObject<TGMediaEditableItem> *)item;
- (NSArray *)entitiesForItem:(NSObject<TGMediaEditableItem> *)item;
- (NSAttributedString *)captionForItem:(NSObject<TGMediaEditableItem> *)item;
- (SSignal *)captionSignalForItem:(NSObject<TGMediaEditableItem> *)item;
- (void)setCaption:(NSString *)caption entities:(NSArray *)entities forItem:(NSObject<TGMediaEditableItem> *)item;
- (void)setCaption:(NSAttributedString *)caption forItem:(NSObject<TGMediaEditableItem> *)item;
- (bool)isForcedCaption;
- (void)setForcedCaption:(NSString *)caption entities:(NSArray *)entities;
- (void)setForcedCaption:(NSAttributedString *)caption;
- (NSObject<TGMediaEditAdjustments> *)adjustmentsForItem:(NSObject<TGMediaEditableItem> *)item;
- (SSignal *)adjustmentsSignalForItem:(NSObject<TGMediaEditableItem> *)item;

View File

@ -5,6 +5,7 @@
#import <LegacyComponents/LegacyComponentsContext.h>
@protocol TGPhotoPaintStickersContext;
@class TGMediaSelectionContext;
@class TGMediaEditingContext;
@class TGSuggestionContext;
@ -12,7 +13,7 @@
@interface TGMediaPickerGalleryInterfaceView : UIView <TGModernGalleryInterfaceView>
@property (nonatomic, copy) void (^captionSet)(id<TGModernGalleryItem>, NSString *, NSArray *);
@property (nonatomic, copy) void (^captionSet)(id<TGModernGalleryItem>, NSAttributedString *);
@property (nonatomic, copy) void (^donePressed)(id<TGModernGalleryItem>);
@property (nonatomic, copy) void (^doneLongPressed)(id<TGModernGalleryItem>);
@ -37,7 +38,7 @@
@property (nonatomic, readonly) UIView *timerButton;
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context focusItem:(id<TGModernGalleryItem>)focusItem selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext hasSelectionPanel:(bool)hasSelectionPanel hasCameraButton:(bool)hasCameraButton recipientName:(NSString *)recipientName;
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context focusItem:(id<TGModernGalleryItem>)focusItem selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext stickersContext:(id<TGPhotoPaintStickersContext>)stickersContext hasSelectionPanel:(bool)hasSelectionPanel hasCameraButton:(bool)hasCameraButton recipientName:(NSString *)recipientName;
- (void)setSelectedItemsModel:(TGMediaPickerGallerySelectedItemsModel *)selectedItemsModel;
- (void)setEditorTabPressed:(void (^)(TGPhotoEditorTab tab))editorTabPressed;

View File

@ -25,7 +25,7 @@
@property (nonatomic, copy) void (^didFinishEditingItem)(id<TGMediaEditableItem>item, id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage);
@property (nonatomic, copy) void (^didFinishRenderingFullSizeImage)(id<TGMediaEditableItem> item, UIImage *fullSizeImage);
@property (nonatomic, copy) void (^saveItemCaption)(id<TGMediaEditableItem> item, NSString *caption, NSArray *entities);
@property (nonatomic, copy) void (^saveItemCaption)(id<TGMediaEditableItem> item, NSAttributedString *caption);
@property (nonatomic, copy) void (^storeOriginalImageForItem)(id<TGMediaEditableItem> item, UIImage *originalImage);

View File

@ -2,11 +2,14 @@
#import <LegacyComponents/TGMediaPickerCaptionInputPanel.h>
@class TGSuggestionContext;
@class TGKeyCommandController;
@protocol TGPhotoPaintStickersContext;
@protocol TGCaptionPanelView;
@interface TGPhotoCaptionInputMixin : NSObject
@property (nonatomic, readonly) TGMediaPickerCaptionInputPanel *inputPanel;
@property (nonatomic, strong) id<TGPhotoPaintStickersContext> stickersContext;
@property (nonatomic, readonly) id<TGCaptionPanelView> 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;

View File

@ -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<TGMediaEditAdjustments> adjustments, id temporaryRep, bool hasChanges);
@property (nonatomic, copy) void (^didFinishRenderingFullSizeImage)(UIImage *fullSizeImage);

View File

@ -35,6 +35,22 @@
@end
@protocol TGCaptionPanelView <NSObject>
@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 <NSObject>
- (int64_t)documentIdForDocument:(id)document;
@ -44,4 +60,6 @@
@property (nonatomic, copy) id<TGPhotoPaintStickersScreen>(^presentStickersController)(void(^)(id, bool, UIView *, CGRect));
@property (nonatomic, copy) id<TGCaptionPanelView>(^captionPanelView)(void);
@end

View File

@ -4,6 +4,6 @@
+ (void)presentWithContext:(id<LegacyComponentsContext>)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<LegacyComponentsContext>)context controller:(TGViewController *)controller caption:(NSString *)caption entities:(NSArray *)entities withItem:(id<TGMediaEditableItem, TGMediaSelectableItem>)item paint:(bool)paint recipientName:(NSString *)recipientName stickersContext:(id<TGPhotoPaintStickersContext>)stickersContext snapshots:(NSArray *)snapshots immediate:(bool)immediate appeared:(void (^)(void))appeared completion:(void (^)(id<TGMediaEditableItem>, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed;
+ (void)presentWithContext:(id<LegacyComponentsContext>)context controller:(TGViewController *)controller caption:(NSAttributedString *)caption withItem:(id<TGMediaEditableItem, TGMediaSelectableItem>)item paint:(bool)paint recipientName:(NSString *)recipientName stickersContext:(id<TGPhotoPaintStickersContext>)stickersContext snapshots:(NSArray *)snapshots immediate:(bool)immediate appeared:(void (^)(void))appeared completion:(void (^)(id<TGMediaEditableItem>, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed;
@end

View File

@ -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<TGMediaEditableItem> editableItem, NSString *caption, NSArray *entities)
model.saveItemCaption = ^(id<TGMediaEditableItem> 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<TGMediaSelectableItem>)currentItem storeAssets:(bool)storeAssets saveEditedPhotos:(bool)saveEditedPhotos descriptionGenerator:(id (^)(id, NSString *, NSArray *, NSString *))descriptionGenerator
+ (NSArray *)resultSignalsForSelectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext currentItem:(id<TGMediaSelectableItem>)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<TGMediaEditAdjustments> 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];

View File

@ -95,9 +95,9 @@
[editingContext setFullSizeImage:resultImage forItem:editableItem];
};
model.saveItemCaption = ^(id<TGMediaEditableItem> editableItem, NSString *caption, NSArray *entities)
model.saveItemCaption = ^(id<TGMediaEditableItem> 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<TGMediaSelectableItem>)editableItem selected:true];

View File

@ -13,7 +13,7 @@
@property (nonatomic, copy) void (^didFinishEditingItem)(id<TGMediaEditableItem>item, id<TGMediaEditAdjustments> adjustments, UIImage *resultImage, UIImage *thumbnailImage);
@property (nonatomic, copy) void (^didFinishRenderingFullSizeImage)(id<TGMediaEditableItem> item, UIImage *fullSizeImage);
@property (nonatomic, copy) void (^saveItemCaption)(id<TGMediaEditableItem> item, NSString *caption, NSArray *entities);
@property (nonatomic, copy) void (^saveItemCaption)(id<TGMediaEditableItem> item, NSAttributedString *caption);
@property (nonatomic, copy) void (^editorOpened)(void);
@property (nonatomic, copy) void (^editorClosed)(void);

View File

@ -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<TGModernGalleryItem> item, NSString *caption, NSArray *entities)
_interfaceView.captionSet = ^(id<TGModernGalleryItem> 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<TGModernGalleryEditableItem>)item).editableMediaItem, caption, entities);
strongSelf.saveItemCaption(((id<TGModernGalleryEditableItem>)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)

View File

@ -116,7 +116,7 @@
return value;
}
+ (NSArray *)resultSignalsForSelectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext currentItem:(id<TGMediaSelectableItem>)currentItem descriptionGenerator:(id (^)(id, NSString *, NSArray *, NSString *))descriptionGenerator
+ (NSArray *)resultSignalsForSelectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext currentItem:(id<TGMediaSelectableItem>)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<TGMediaEditAdjustments> 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)
{

View File

@ -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;
}]];

View File

@ -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;

View File

@ -37,10 +37,9 @@
@interface TGMediaCaptionUpdate : NSObject
@property (nonatomic, readonly, strong) id<TGMediaEditableItem> item;
@property (nonatomic, readonly, strong) NSString *caption;
@property (nonatomic, readonly, strong) NSArray *entities;
@property (nonatomic, readonly, strong) NSAttributedString *caption;
+ (instancetype)captionUpdateWithItem:(id<TGMediaEditableItem>)item caption:(NSString *)caption entities:(NSArray *)entities;
+ (instancetype)captionUpdateWithItem:(id<TGMediaEditableItem>)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<TGMediaEditableItem>)item
- (NSAttributedString *)captionForItem:(id<TGMediaEditableItem>)item
{
if (_forcedCaption != nil)
return _forcedCaption;
@ -385,25 +381,12 @@
return _captions[itemId];
}
- (NSArray *)entitiesForItem:(NSObject<TGMediaEditableItem> *)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<TGMediaEditableItem>)item
- (void)setCaption:(NSAttributedString *)caption forItem:(id<TGMediaEditableItem>)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<TGMediaEditableItem> *)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<TGMediaEditableItem>)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<TGMediaEditableItem>)item caption:(NSString *)caption entities:(NSArray *)entities
+ (instancetype)captionUpdateWithItem:(id<TGMediaEditableItem>)item caption:(NSAttributedString *)caption
{
TGMediaCaptionUpdate *update = [[TGMediaCaptionUpdate alloc] init];
update->_item = item;
update->_caption = caption;
update->_entities = entities;
return update;
}

View File

@ -103,7 +103,7 @@
@synthesize safeAreaInset = _safeAreaInset;
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context focusItem:(id<TGModernGalleryItem>)focusItem selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext hasSelectionPanel:(bool)hasSelectionPanel hasCameraButton:(bool)hasCameraButton recipientName:(NSString *)recipientName
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context focusItem:(id<TGModernGalleryItem>)focusItem selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext stickersContext:(id<TGPhotoPaintStickersContext>)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<TGMediaEditableItem> 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]])

View File

@ -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<TGModernGalleryItem> item, NSString *caption, NSArray *entities)
_interfaceView.captionSet = ^(id<TGModernGalleryItem> 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<TGModernGalleryEditableItem>)item).editableMediaItem, caption, entities);
strongSelf.saveItemCaption(((id<TGModernGalleryEditableItem>)item).editableMediaItem, caption);
};
_interfaceView.timerRequested = ^
{
@ -360,7 +360,7 @@
id<TGMediaEditAdjustments> 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)

View File

@ -118,9 +118,9 @@
[editingContext setFullSizeImage:resultImage forItem:editableItem];
};
model.saveItemCaption = ^(id<TGMediaEditableItem> editableItem, NSString *caption, NSArray *entities)
model.saveItemCaption = ^(id<TGMediaEditableItem> 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<TGMediaSelectableItem>)editableItem selected:true];

View File

@ -5,30 +5,32 @@
#import <LegacyComponents/TGObserverProxy.h>
#import "TGSuggestionContext.h"
#import "TGPhotoPaintStickersContext.h"
#import "TGModernConversationMentionsAssociatedPanel.h"
#import "TGModernConversationHashtagsAssociatedPanel.h"
#import "TGModernConversationAlphacodeAssociatedPanel.h"
@interface TGPhotoCaptionInputMixin () <TGMediaPickerCaptionInputPanelDelegate>
@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<TGCaptionPanelView> 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

View File

@ -102,13 +102,13 @@
}
}
+ (void)presentWithContext:(id<LegacyComponentsContext>)context controller:(TGViewController *)controller caption:(NSString *)caption entities:(NSArray *)entities withItem:(id<TGMediaEditableItem, TGMediaSelectableItem>)item paint:(bool)paint recipientName:(NSString *)recipientName stickersContext:(id<TGPhotoPaintStickersContext>)stickersContext snapshots:(NSArray *)snapshots immediate:(bool)immediate appeared:(void (^)(void))appeared completion:(void (^)(id<TGMediaEditableItem>, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed
+ (void)presentWithContext:(id<LegacyComponentsContext>)context controller:(TGViewController *)controller caption:(NSAttributedString *)caption withItem:(id<TGMediaEditableItem, TGMediaSelectableItem>)item paint:(bool)paint recipientName:(NSString *)recipientName stickersContext:(id<TGPhotoPaintStickersContext>)stickersContext snapshots:(NSArray *)snapshots immediate:(bool)immediate appeared:(void (^)(void))appeared completion:(void (^)(id<TGMediaEditableItem>, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed
{
id<LegacyComponentsOverlayWindowManager> windowManager = [context makeOverlayWindowManager];
id<LegacyComponentsContext> 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<TGMediaEditableItem> editableItem, NSString *caption, NSArray *entities)
model.saveItemCaption = ^(id<TGMediaEditableItem> editableItem, NSAttributedString *caption)
{
[editingContext setCaption:caption entities:entities forItem:editableItem];
[editingContext setCaption:caption forItem:editableItem];
};
model.interfaceView.hasSwipeGesture = false;

View File

@ -27,6 +27,7 @@ swift_library(
"//submodules/AnimatedStickerNode:AnimatedStickerNode",
"//submodules/TelegramAnimatedStickerNode:TelegramAnimatedStickerNode",
"//submodules/StickerResources:StickerResources",
"//submodules/TextFormat:TextFormat",
],
visibility = [
"//visibility:public",

View File

@ -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<PresentationData, NoError>), 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<PresentationData, NoError>), 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<PresentationData, NoError>), 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<PresentationData, NoError>), 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

View File

@ -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))
}
}
}

View File

@ -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

View File

@ -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<Int>?
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)

View File

@ -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)
}
}

View File

@ -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

View File

@ -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!)

View File

@ -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

View File

@ -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()
}