mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Merge commit 'de6f737bc106c29f9c0478d9456dd0d0bcee2d33'
This commit is contained in:
commit
acf5f3cd9f
@ -1244,7 +1244,7 @@ private final class FeaturedPaneSearchContentNode: ASDisplayNode {
|
|||||||
|
|
||||||
let query = text.trimmingCharacters(in: .whitespacesAndNewlines)
|
let query = text.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
if query.isSingleEmoji {
|
if query.isSingleEmoji {
|
||||||
signals = .single([context.engine.stickers.searchStickers(query: [text.basicEmoji.0])
|
signals = .single([context.engine.stickers.searchStickers(query: nil, emoticon: [text.basicEmoji.0], inputLanguageCode: "")
|
||||||
|> map { (nil, $0.items) }])
|
|> map { (nil, $0.items) }])
|
||||||
} else if query.count > 1, let languageCode = languageCode, !languageCode.isEmpty && languageCode != "emoji" {
|
} else if query.count > 1, let languageCode = languageCode, !languageCode.isEmpty && languageCode != "emoji" {
|
||||||
var signal = context.engine.stickers.searchEmojiKeywords(inputLanguageCode: languageCode, query: query.lowercased(), completeMatch: query.count < 3)
|
var signal = context.engine.stickers.searchEmojiKeywords(inputLanguageCode: languageCode, query: query.lowercased(), completeMatch: query.count < 3)
|
||||||
@ -1260,17 +1260,11 @@ private final class FeaturedPaneSearchContentNode: ASDisplayNode {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
signals = signal
|
signals = signal
|
||||||
|> map { keywords -> [Signal<(String?, [FoundStickerItem]), NoError>] in
|
|> map { keywords -> [Signal<(String?, [FoundStickerItem]), NoError>] in
|
||||||
var signals: [Signal<(String?, [FoundStickerItem]), NoError>] = []
|
let emoticon = keywords.flatMap { $0.emoticons }.map { $0.basicEmoji.0 }
|
||||||
let emoticons = keywords.flatMap { $0.emoticons }
|
return [context.engine.stickers.searchStickers(query: query, emoticon: emoticon, inputLanguageCode: languageCode)
|
||||||
for emoji in emoticons {
|
|> map { (nil, $0.items) }]
|
||||||
signals.append(context.engine.stickers.searchStickers(query: [emoji.basicEmoji.0])
|
|
||||||
|> take(1)
|
|
||||||
|> map { (emoji, $0.items) })
|
|
||||||
}
|
|
||||||
return signals
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,8 +26,11 @@
|
|||||||
@property (nonatomic, copy) void (^timerUpdated)(NSNumber *timeout);
|
@property (nonatomic, copy) void (^timerUpdated)(NSNumber *timeout);
|
||||||
@property (nonatomic, copy) void (^captionIsAboveUpdated)(bool captionIsAbove);
|
@property (nonatomic, copy) void (^captionIsAboveUpdated)(bool captionIsAbove);
|
||||||
|
|
||||||
|
@property (nonatomic, readonly) bool editing;
|
||||||
|
|
||||||
- (void)createInputPanelIfNeeded;
|
- (void)createInputPanelIfNeeded;
|
||||||
- (void)beginEditing;
|
- (void)beginEditing;
|
||||||
|
- (void)finishEditing;
|
||||||
- (void)enableDismissal;
|
- (void)enableDismissal;
|
||||||
|
|
||||||
- (void)onAnimateOut;
|
- (void)onAnimateOut;
|
||||||
|
@ -175,7 +175,15 @@
|
|||||||
[strongSelf.window endEditing:true];
|
[strongSelf.window endEditing:true];
|
||||||
strongSelf->_portraitToolbarView.doneButton.userInteractionEnabled = false;
|
strongSelf->_portraitToolbarView.doneButton.userInteractionEnabled = false;
|
||||||
strongSelf->_landscapeToolbarView.doneButton.userInteractionEnabled = false;
|
strongSelf->_landscapeToolbarView.doneButton.userInteractionEnabled = false;
|
||||||
strongSelf->_donePressed(strongSelf->_currentItem);
|
|
||||||
|
if (strongSelf->_captionMixin.editing) {
|
||||||
|
[strongSelf->_captionMixin finishEditing];
|
||||||
|
TGDispatchAfter(0.1, dispatch_get_main_queue(), ^{
|
||||||
|
strongSelf->_donePressed(strongSelf->_currentItem);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
strongSelf->_donePressed(strongSelf->_currentItem);
|
||||||
|
}
|
||||||
|
|
||||||
[strongSelf->_captionMixin onAnimateOut];
|
[strongSelf->_captionMixin onAnimateOut];
|
||||||
};
|
};
|
||||||
@ -1428,7 +1436,7 @@
|
|||||||
|| [view isDescendantOfView:_landscapeToolbarView]
|
|| [view isDescendantOfView:_landscapeToolbarView]
|
||||||
|| [view isDescendantOfView:_selectedPhotosView]
|
|| [view isDescendantOfView:_selectedPhotosView]
|
||||||
|| [view isDescendantOfView:_captionMixin.inputPanelView]
|
|| [view isDescendantOfView:_captionMixin.inputPanelView]
|
||||||
|| [view isDescendantOfView:_captionMixin.dismissView]
|
|| ([view isDescendantOfView:_captionMixin.dismissView] && _captionMixin.dismissView.alpha > 0.0)
|
||||||
|| [view isKindOfClass:[TGMenuButtonView class]])
|
|| [view isKindOfClass:[TGMenuButtonView class]])
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -100,9 +100,9 @@ typedef enum
|
|||||||
_currentTimeLabel.text = @"0:00";
|
_currentTimeLabel.text = @"0:00";
|
||||||
_currentTimeLabel.textColor = [UIColor whiteColor];
|
_currentTimeLabel.textColor = [UIColor whiteColor];
|
||||||
_currentTimeLabel.layer.shadowOffset = CGSizeMake(0.0, 0.0);
|
_currentTimeLabel.layer.shadowOffset = CGSizeMake(0.0, 0.0);
|
||||||
_currentTimeLabel.layer.shadowRadius = 2.0;
|
_currentTimeLabel.layer.shadowRadius = 4.0;
|
||||||
_currentTimeLabel.layer.shadowColor = [UIColor blackColor].CGColor;
|
_currentTimeLabel.layer.shadowColor = [UIColor blackColor].CGColor;
|
||||||
_currentTimeLabel.layer.shadowOpacity = 0.4;
|
_currentTimeLabel.layer.shadowOpacity = 0.6;
|
||||||
_currentTimeLabel.layer.rasterizationScale = TGScreenScaling();
|
_currentTimeLabel.layer.rasterizationScale = TGScreenScaling();
|
||||||
_currentTimeLabel.layer.shouldRasterize = true;
|
_currentTimeLabel.layer.shouldRasterize = true;
|
||||||
[self addSubview:_currentTimeLabel];
|
[self addSubview:_currentTimeLabel];
|
||||||
@ -115,9 +115,9 @@ typedef enum
|
|||||||
_inverseTimeLabel.textAlignment = NSTextAlignmentRight;
|
_inverseTimeLabel.textAlignment = NSTextAlignmentRight;
|
||||||
_inverseTimeLabel.textColor = [UIColor whiteColor];
|
_inverseTimeLabel.textColor = [UIColor whiteColor];
|
||||||
_inverseTimeLabel.layer.shadowOffset = CGSizeMake(0.0, 0.0);
|
_inverseTimeLabel.layer.shadowOffset = CGSizeMake(0.0, 0.0);
|
||||||
_inverseTimeLabel.layer.shadowRadius = 2.0;
|
_inverseTimeLabel.layer.shadowRadius = 4.0;
|
||||||
_inverseTimeLabel.layer.shadowColor = [UIColor blackColor].CGColor;
|
_inverseTimeLabel.layer.shadowColor = [UIColor blackColor].CGColor;
|
||||||
_inverseTimeLabel.layer.shadowOpacity = 0.4;
|
_inverseTimeLabel.layer.shadowOpacity = 0.6;
|
||||||
_inverseTimeLabel.layer.rasterizationScale = TGScreenScaling();
|
_inverseTimeLabel.layer.rasterizationScale = TGScreenScaling();
|
||||||
_inverseTimeLabel.layer.shouldRasterize = true;
|
_inverseTimeLabel.layer.shouldRasterize = true;
|
||||||
[self addSubview:_inverseTimeLabel];
|
[self addSubview:_inverseTimeLabel];
|
||||||
|
@ -61,7 +61,6 @@
|
|||||||
_inputPanel.sendPressed = ^(NSAttributedString *string) {
|
_inputPanel.sendPressed = ^(NSAttributedString *string) {
|
||||||
__strong TGPhotoCaptionInputMixin *strongSelf = weakSelf;
|
__strong TGPhotoCaptionInputMixin *strongSelf = weakSelf;
|
||||||
[TGViewController enableAutorotation];
|
[TGViewController enableAutorotation];
|
||||||
strongSelf->_dismissView.hidden = true;
|
|
||||||
|
|
||||||
strongSelf->_editing = false;
|
strongSelf->_editing = false;
|
||||||
|
|
||||||
@ -74,9 +73,7 @@
|
|||||||
[TGViewController disableAutorotation];
|
[TGViewController disableAutorotation];
|
||||||
|
|
||||||
[strongSelf beginEditing];
|
[strongSelf beginEditing];
|
||||||
|
|
||||||
strongSelf->_dismissView.hidden = false;
|
|
||||||
|
|
||||||
if (strongSelf.panelFocused != nil)
|
if (strongSelf.panelFocused != nil)
|
||||||
strongSelf.panelFocused();
|
strongSelf.panelFocused();
|
||||||
|
|
||||||
@ -129,12 +126,13 @@
|
|||||||
|
|
||||||
_dismissView = [[UIView alloc] initWithFrame:parentView.bounds];
|
_dismissView = [[UIView alloc] initWithFrame:parentView.bounds];
|
||||||
_dismissView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
_dismissView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||||
|
_dismissView.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.4];
|
||||||
|
|
||||||
_dismissTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDismissTap:)];
|
_dismissTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDismissTap:)];
|
||||||
_dismissTapRecognizer.enabled = false;
|
_dismissTapRecognizer.enabled = false;
|
||||||
[_dismissView addGestureRecognizer:_dismissTapRecognizer];
|
[_dismissView addGestureRecognizer:_dismissTapRecognizer];
|
||||||
|
|
||||||
//[parentView insertSubview:_dismissView belowSubview:_backgroundView];
|
[parentView insertSubview:_dismissView belowSubview:_inputPanelView];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setCaption:(NSAttributedString *)caption
|
- (void)setCaption:(NSAttributedString *)caption
|
||||||
@ -168,6 +166,12 @@
|
|||||||
|
|
||||||
[self createDismissViewIfNeeded];
|
[self createDismissViewIfNeeded];
|
||||||
[self createInputPanelIfNeeded];
|
[self createInputPanelIfNeeded];
|
||||||
|
|
||||||
|
_dismissView.alpha = 0.0;
|
||||||
|
[UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||||
|
_dismissView.alpha = 1.0f;
|
||||||
|
} completion:^(BOOL finished) {
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)enableDismissal
|
- (void)enableDismissal
|
||||||
@ -177,19 +181,21 @@
|
|||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
|
|
||||||
|
- (void)finishEditing {
|
||||||
|
if ([self.inputPanel dismissInput]) {
|
||||||
|
_editing = false;
|
||||||
|
|
||||||
|
if (self.finishedWithCaption != nil)
|
||||||
|
self.finishedWithCaption([_inputPanel caption]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)handleDismissTap:(UITapGestureRecognizer *)gestureRecognizer
|
- (void)handleDismissTap:(UITapGestureRecognizer *)gestureRecognizer
|
||||||
{
|
{
|
||||||
if (gestureRecognizer.state != UIGestureRecognizerStateRecognized)
|
if (gestureRecognizer.state != UIGestureRecognizerStateRecognized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ([self.inputPanel dismissInput]) {
|
[self finishEditing];
|
||||||
_editing = false;
|
|
||||||
|
|
||||||
[_dismissView removeFromSuperview];
|
|
||||||
|
|
||||||
if (self.finishedWithCaption != nil)
|
|
||||||
self.finishedWithCaption([_inputPanel caption]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Input Panel Delegate
|
#pragma mark - Input Panel Delegate
|
||||||
@ -228,6 +234,19 @@
|
|||||||
|
|
||||||
_keyboardHeight = keyboardHeight;
|
_keyboardHeight = keyboardHeight;
|
||||||
|
|
||||||
|
CGFloat fadeAlpha = 1.0;
|
||||||
|
if (keyboardHeight < FLT_EPSILON) {
|
||||||
|
fadeAlpha = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ABS(_dismissView.alpha - fadeAlpha) > FLT_EPSILON) {
|
||||||
|
[UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||||
|
_dismissView.alpha = fadeAlpha;
|
||||||
|
} completion:^(BOOL finished) {
|
||||||
|
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
if (!UIInterfaceOrientationIsPortrait([[LegacyComponentsGlobals provider] applicationStatusBarOrientation]) && !TGIsPad())
|
if (!UIInterfaceOrientationIsPortrait([[LegacyComponentsGlobals provider] applicationStatusBarOrientation]) && !TGIsPad())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ public func legacyStoryMediaEditor(context: AccountContext, item: TGMediaEditabl
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public func legacyMediaEditor(context: AccountContext, peer: Peer, threadTitle: String?, media: AnyMediaReference, mode: LegacyMediaEditorMode, initialCaption: NSAttributedString, snapshots: [UIView], transitionCompletion: (() -> Void)?, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, present: @escaping (ViewController, Any?) -> Void) {
|
public func legacyMediaEditor(context: AccountContext, peer: Peer, threadTitle: String?, media: AnyMediaReference, mode: LegacyMediaEditorMode, initialCaption: NSAttributedString, snapshots: [UIView], transitionCompletion: (() -> Void)?, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32, Bool) -> Void, present: @escaping (ViewController, Any?) -> Void) {
|
||||||
let _ = (fetchMediaData(context: context, postbox: context.account.postbox, userLocation: .other, mediaReference: media)
|
let _ = (fetchMediaData(context: context, postbox: context.account.postbox, userLocation: .other, mediaReference: media)
|
||||||
|> deliverOnMainQueue).start(next: { (value, isImage) in
|
|> deliverOnMainQueue).start(next: { (value, isImage) in
|
||||||
guard case let .data(data) = value, data.complete else {
|
guard case let .data(data) = value, data.complete else {
|
||||||
@ -215,7 +215,8 @@ public func legacyMediaEditor(context: AccountContext, peer: Peer, threadTitle:
|
|||||||
let signals = TGCameraController.resultSignals(for: nil, editingContext: editingContext, currentItem: selectableResult, storeAssets: false, saveEditedPhotos: false, descriptionGenerator: { _1, _2, _3 in
|
let signals = TGCameraController.resultSignals(for: nil, editingContext: editingContext, currentItem: selectableResult, storeAssets: false, saveEditedPhotos: false, descriptionGenerator: { _1, _2, _3 in
|
||||||
nativeGenerator(_1, _2, _3, nil)
|
nativeGenerator(_1, _2, _3, nil)
|
||||||
})
|
})
|
||||||
sendMessagesWithSignals(signals, false, 0)
|
let isCaptionAbove = editingContext?.isCaptionAbove() ?? false
|
||||||
|
sendMessagesWithSignals(signals, false, 0, isCaptionAbove)
|
||||||
}, dismissed: { [weak legacyController] in
|
}, dismissed: { [weak legacyController] in
|
||||||
legacyController?.dismiss()
|
legacyController?.dismiss()
|
||||||
})
|
})
|
||||||
|
@ -2028,7 +2028,7 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
|
|||||||
))
|
))
|
||||||
return .single(resultGroups)
|
return .single(resultGroups)
|
||||||
} else {
|
} else {
|
||||||
let remoteSignal = context.engine.stickers.searchEmoji(emojiString: Array(allEmoticons.keys))
|
let remoteSignal = context.engine.stickers.searchEmoji(query: query, emoticon: Array(allEmoticons.keys), inputLanguageCode: languageCode)
|
||||||
|
|
||||||
return combineLatest(
|
return combineLatest(
|
||||||
context.account.postbox.itemCollectionsView(orderedItemListCollectionIds: [], namespaces: [Namespaces.ItemCollection.CloudEmojiPacks], aroundIndex: nil, count: 10000000) |> take(1),
|
context.account.postbox.itemCollectionsView(orderedItemListCollectionIds: [], namespaces: [Namespaces.ItemCollection.CloudEmojiPacks], aroundIndex: nil, count: 10000000) |> take(1),
|
||||||
|
@ -1628,9 +1628,9 @@ private func monetizationEntries(
|
|||||||
|
|
||||||
if canViewRevenue {
|
if canViewRevenue {
|
||||||
entries.append(.adsTonBalanceTitle(presentationData.theme, isBot ? presentationData.strings.Monetization_Bot_BalanceTitle : presentationData.strings.Monetization_TonBalanceTitle))
|
entries.append(.adsTonBalanceTitle(presentationData.theme, isBot ? presentationData.strings.Monetization_Bot_BalanceTitle : presentationData.strings.Monetization_TonBalanceTitle))
|
||||||
entries.append(.adsTonBalance(presentationData.theme, data, isCreator && data.balances.availableBalance > 0, data.balances.withdrawEnabled))
|
entries.append(.adsTonBalance(presentationData.theme, data, (isCreator || isBot) && data.balances.availableBalance > 0, data.balances.withdrawEnabled))
|
||||||
|
|
||||||
if isCreator {
|
if isCreator || isBot {
|
||||||
let withdrawalInfoText: String
|
let withdrawalInfoText: String
|
||||||
if data.balances.availableBalance == 0 {
|
if data.balances.availableBalance == 0 {
|
||||||
withdrawalInfoText = presentationData.strings.Monetization_Balance_ZeroInfo
|
withdrawalInfoText = presentationData.strings.Monetization_Balance_ZeroInfo
|
||||||
|
@ -81,13 +81,20 @@ func _internal_randomGreetingSticker(account: Account) -> Signal<FoundStickerIte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func _internal_searchStickers(account: Account, query: [String], scope: SearchStickersScope = [.installed, .remote]) -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> {
|
func _internal_searchStickers(account: Account, query: String?, emoticon: [String], inputLanguageCode: String, scope: SearchStickersScope = [.installed, .remote]) -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> {
|
||||||
if scope.isEmpty {
|
if scope.isEmpty {
|
||||||
return .single(([], true))
|
return .single(([], true))
|
||||||
}
|
}
|
||||||
var query = query
|
var emoticon = emoticon
|
||||||
if query == ["\u{2764}"] {
|
if emoticon == ["\u{2764}"] {
|
||||||
query = ["\u{2764}\u{FE0F}"]
|
emoticon = ["\u{2764}\u{FE0F}"]
|
||||||
|
}
|
||||||
|
|
||||||
|
let cacheKey: String
|
||||||
|
if let query, !query.isEmpty {
|
||||||
|
cacheKey = query
|
||||||
|
} else {
|
||||||
|
cacheKey = emoticon.sorted().joined()
|
||||||
}
|
}
|
||||||
|
|
||||||
return account.postbox.transaction { transaction -> ([FoundStickerItem], CachedStickerQueryResult?, Bool, SearchStickersConfiguration) in
|
return account.postbox.transaction { transaction -> ([FoundStickerItem], CachedStickerQueryResult?, Bool, SearchStickersConfiguration) in
|
||||||
@ -98,7 +105,7 @@ func _internal_searchStickers(account: Account, query: [String], scope: SearchSt
|
|||||||
for entry in transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudSavedStickers) {
|
for entry in transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudSavedStickers) {
|
||||||
if let item = entry.contents.get(SavedStickerItem.self) {
|
if let item = entry.contents.get(SavedStickerItem.self) {
|
||||||
for representation in item.stringRepresentations {
|
for representation in item.stringRepresentations {
|
||||||
for queryItem in query {
|
for queryItem in emoticon {
|
||||||
if representation.hasPrefix(queryItem) {
|
if representation.hasPrefix(queryItem) {
|
||||||
result.append(FoundStickerItem(file: item.file, stringRepresentations: item.stringRepresentations))
|
result.append(FoundStickerItem(file: item.file, stringRepresentations: item.stringRepresentations))
|
||||||
break
|
break
|
||||||
@ -125,7 +132,7 @@ func _internal_searchStickers(account: Account, query: [String], scope: SearchSt
|
|||||||
currentItems.insert(file.fileId)
|
currentItems.insert(file.fileId)
|
||||||
|
|
||||||
for case let .Sticker(displayText, _, _) in file.attributes {
|
for case let .Sticker(displayText, _, _) in file.attributes {
|
||||||
for queryItem in query {
|
for queryItem in emoticon {
|
||||||
if displayText.hasPrefix(queryItem) {
|
if displayText.hasPrefix(queryItem) {
|
||||||
matchingRecentItemsIds.insert(file.fileId)
|
matchingRecentItemsIds.insert(file.fileId)
|
||||||
break
|
break
|
||||||
@ -143,12 +150,9 @@ func _internal_searchStickers(account: Account, query: [String], scope: SearchSt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var searchQueries: [ItemCollectionSearchQuery] = query.map { queryItem -> ItemCollectionSearchQuery in
|
let searchQueries: [ItemCollectionSearchQuery] = emoticon.map { queryItem -> ItemCollectionSearchQuery in
|
||||||
return .exact(ValueBoxKey(queryItem))
|
return .exact(ValueBoxKey(queryItem))
|
||||||
}
|
}
|
||||||
if query == ["\u{2764}"] {
|
|
||||||
searchQueries = [.any([ValueBoxKey("\u{2764}"), ValueBoxKey("\u{2764}\u{FE0F}")])]
|
|
||||||
}
|
|
||||||
|
|
||||||
var installedItems: [FoundStickerItem] = []
|
var installedItems: [FoundStickerItem] = []
|
||||||
var installedAnimatedItems: [FoundStickerItem] = []
|
var installedAnimatedItems: [FoundStickerItem] = []
|
||||||
@ -187,7 +191,7 @@ func _internal_searchStickers(account: Account, query: [String], scope: SearchSt
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if matchingRecentItemsIds.contains(file.fileId) {
|
if matchingRecentItemsIds.contains(file.fileId) {
|
||||||
result.append(FoundStickerItem(file: file, stringRepresentations: query))
|
result.append(FoundStickerItem(file: file, stringRepresentations: emoticon))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +200,7 @@ func _internal_searchStickers(account: Account, query: [String], scope: SearchSt
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if matchingRecentItemsIds.contains(file.fileId) {
|
if matchingRecentItemsIds.contains(file.fileId) {
|
||||||
result.append(FoundStickerItem(file: file, stringRepresentations: query))
|
result.append(FoundStickerItem(file: file, stringRepresentations: emoticon))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,8 +209,7 @@ func _internal_searchStickers(account: Account, query: [String], scope: SearchSt
|
|||||||
result.append(contentsOf: installedItems)
|
result.append(contentsOf: installedItems)
|
||||||
}
|
}
|
||||||
|
|
||||||
let combinedQuery = query.joined(separator: "")
|
var cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(cacheKey)))?.get(CachedStickerQueryResult.self)
|
||||||
var cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(combinedQuery)))?.get(CachedStickerQueryResult.self)
|
|
||||||
|
|
||||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||||
let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue
|
let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue
|
||||||
@ -292,14 +295,17 @@ func _internal_searchStickers(account: Account, query: [String], scope: SearchSt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let remote = account.network.request(Api.functions.messages.getStickers(emoticon: query.joined(separator: ""), hash: cached?.hash ?? 0))
|
let remote: Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError>
|
||||||
|> `catch` { _ -> Signal<Api.messages.Stickers, NoError> in
|
if let query, !query.isEmpty {
|
||||||
return .single(.stickersNotModified)
|
let flags: Int32 = 0
|
||||||
}
|
remote = account.network.request(Api.functions.messages.searchStickers(flags: flags, q: query, emoticon: emoticon.joined(separator: ""), langCode: [inputLanguageCode], offset: 0, limit: 128, hash: cached?.hash ?? 0))
|
||||||
|> mapToSignal { result -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> in
|
|> `catch` { _ -> Signal<Api.messages.FoundStickers, NoError> in
|
||||||
return account.postbox.transaction { transaction -> (items: [FoundStickerItem], isFinalResult: Bool) in
|
return .single(.foundStickersNotModified(flags: 0, nextOffset: nil))
|
||||||
switch result {
|
}
|
||||||
case let .stickers(hash, stickers):
|
|> mapToSignal { result -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> in
|
||||||
|
return account.postbox.transaction { transaction -> (items: [FoundStickerItem], isFinalResult: Bool) in
|
||||||
|
switch result {
|
||||||
|
case let .foundStickers(_, _, hash, stickers):
|
||||||
var result: [FoundStickerItem] = []
|
var result: [FoundStickerItem] = []
|
||||||
let currentItemIds = Set<MediaId>(localItems.map { $0.file.fileId })
|
let currentItemIds = Set<MediaId>(localItems.map { $0.file.fileId })
|
||||||
|
|
||||||
@ -369,19 +375,113 @@ func _internal_searchStickers(account: Account, query: [String], scope: SearchSt
|
|||||||
}
|
}
|
||||||
|
|
||||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||||
if let entry = CodableEntry(CachedStickerQueryResult(items: files, hash: hash, timestamp: currentTime)) {
|
if hash != 0, let entry = CodableEntry(CachedStickerQueryResult(items: files, hash: hash, timestamp: currentTime)) {
|
||||||
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(query.joined(separator: ""))), entry: entry)
|
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(cacheKey)), entry: entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (result, true)
|
return (result, true)
|
||||||
case .stickersNotModified:
|
case .foundStickersNotModified:
|
||||||
break
|
break
|
||||||
|
}
|
||||||
|
return (tempResult, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
remote = account.network.request(Api.functions.messages.getStickers(emoticon: emoticon.joined(separator: ""), hash: cached?.hash ?? 0))
|
||||||
|
|> `catch` { _ -> Signal<Api.messages.Stickers, NoError> in
|
||||||
|
return .single(.stickersNotModified)
|
||||||
|
}
|
||||||
|
|> mapToSignal { result -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> in
|
||||||
|
return account.postbox.transaction { transaction -> (items: [FoundStickerItem], isFinalResult: Bool) in
|
||||||
|
switch result {
|
||||||
|
case let .stickers(hash, stickers):
|
||||||
|
var result: [FoundStickerItem] = []
|
||||||
|
let currentItemIds = Set<MediaId>(localItems.map { $0.file.fileId })
|
||||||
|
|
||||||
|
var premiumItems: [FoundStickerItem] = []
|
||||||
|
var otherItems: [FoundStickerItem] = []
|
||||||
|
|
||||||
|
for item in localItems {
|
||||||
|
if item.file.isPremiumSticker {
|
||||||
|
premiumItems.append(item)
|
||||||
|
} else {
|
||||||
|
otherItems.append(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var foundItems: [FoundStickerItem] = []
|
||||||
|
var foundAnimatedItems: [FoundStickerItem] = []
|
||||||
|
var foundPremiumItems: [FoundStickerItem] = []
|
||||||
|
|
||||||
|
var files: [TelegramMediaFile] = []
|
||||||
|
for sticker in stickers {
|
||||||
|
if let file = telegramMediaFileFromApiDocument(sticker, altDocuments: []), let id = file.id {
|
||||||
|
files.append(file)
|
||||||
|
if !currentItemIds.contains(id) {
|
||||||
|
if file.isPremiumSticker {
|
||||||
|
foundPremiumItems.append(FoundStickerItem(file: file, stringRepresentations: []))
|
||||||
|
} else if file.isAnimatedSticker || file.isVideoSticker {
|
||||||
|
foundAnimatedItems.append(FoundStickerItem(file: file, stringRepresentations: []))
|
||||||
|
} else {
|
||||||
|
foundItems.append(FoundStickerItem(file: file, stringRepresentations: []))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let allPremiumItems = premiumItems + foundPremiumItems
|
||||||
|
let allOtherItems = otherItems + foundAnimatedItems + foundItems
|
||||||
|
|
||||||
|
if isPremium {
|
||||||
|
let batchCount = Int(searchStickersConfiguration.normalStickersPerPremiumCount)
|
||||||
|
if batchCount == 0 {
|
||||||
|
result.append(contentsOf: allPremiumItems)
|
||||||
|
result.append(contentsOf: allOtherItems)
|
||||||
|
} else {
|
||||||
|
if allPremiumItems.isEmpty {
|
||||||
|
result.append(contentsOf: allOtherItems)
|
||||||
|
} else {
|
||||||
|
var i = 0
|
||||||
|
for premiumItem in allPremiumItems {
|
||||||
|
if i < allOtherItems.count {
|
||||||
|
for j in i ..< min(i + batchCount, allOtherItems.count) {
|
||||||
|
result.append(allOtherItems[j])
|
||||||
|
}
|
||||||
|
i += batchCount
|
||||||
|
}
|
||||||
|
result.append(premiumItem)
|
||||||
|
}
|
||||||
|
if i < allOtherItems.count {
|
||||||
|
for j in i ..< allOtherItems.count {
|
||||||
|
result.append(allOtherItems[j])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.append(contentsOf: allOtherItems)
|
||||||
|
result.append(contentsOf: allPremiumItems.prefix(max(0, Int(searchStickersConfiguration.premiumStickersCount))))
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||||
|
if let entry = CodableEntry(CachedStickerQueryResult(items: files, hash: hash, timestamp: currentTime)) {
|
||||||
|
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(cacheKey)), entry: entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (result, true)
|
||||||
|
case .stickersNotModified:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return (tempResult, true)
|
||||||
}
|
}
|
||||||
return (tempResult, true)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return .single((tempResult, false))
|
return .single((tempResult, false))
|
||||||
|> then(remote)
|
|> then(
|
||||||
|
remote
|
||||||
|
|> delay(0.2, queue: Queue.concurrentDefaultQueue())
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -770,16 +870,24 @@ func _internal_searchStickers(account: Account, category: EmojiSearchCategories.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func _internal_searchEmoji(account: Account, query: [String], scope: SearchStickersScope = [.installed, .remote]) -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> {
|
func _internal_searchEmoji(account: Account, query: String?, emoticon: [String], inputLanguageCode: String, scope: SearchStickersScope = [.installed, .remote]) -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> {
|
||||||
if scope.isEmpty {
|
if scope.isEmpty {
|
||||||
return .single(([], true))
|
return .single(([], true))
|
||||||
}
|
}
|
||||||
var query = query
|
var emoticon = emoticon
|
||||||
if query == ["\u{2764}"] {
|
if emoticon == ["\u{2764}"] {
|
||||||
query = ["\u{2764}\u{FE0F}"]
|
emoticon = ["\u{2764}\u{FE0F}"]
|
||||||
}
|
}
|
||||||
let combinedQuery = query.sorted().joined(separator: "")
|
|
||||||
let querySet = Set(query)
|
let cacheKey: String
|
||||||
|
if let query, !query.isEmpty {
|
||||||
|
cacheKey = query
|
||||||
|
} else {
|
||||||
|
cacheKey = emoticon.sorted().joined()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let querySet = Set(emoticon)
|
||||||
return account.postbox.transaction { transaction -> ([FoundStickerItem], CachedStickerQueryResult?, Bool, SearchStickersConfiguration) in
|
return account.postbox.transaction { transaction -> ([FoundStickerItem], CachedStickerQueryResult?, Bool, SearchStickersConfiguration) in
|
||||||
let isPremium = transaction.getPeer(account.peerId)?.isPremium ?? false
|
let isPremium = transaction.getPeer(account.peerId)?.isPremium ?? false
|
||||||
|
|
||||||
@ -812,7 +920,7 @@ func _internal_searchEmoji(account: Account, query: [String], scope: SearchStick
|
|||||||
result.append(contentsOf: installedItems)
|
result.append(contentsOf: installedItems)
|
||||||
}
|
}
|
||||||
|
|
||||||
var cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedEmojiQueryResults, key: CachedStickerQueryResult.cacheKey(combinedQuery)))?.get(CachedStickerQueryResult.self)
|
var cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedEmojiQueryResults, key: CachedStickerQueryResult.cacheKey(cacheKey)))?.get(CachedStickerQueryResult.self)
|
||||||
|
|
||||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||||
let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue
|
let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue
|
||||||
@ -839,54 +947,99 @@ func _internal_searchEmoji(account: Account, query: [String], scope: SearchStick
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let remote = account.network.request(Api.functions.messages.searchCustomEmoji(emoticon: query.joined(separator: ""), hash: cached?.hash ?? 0))
|
|
||||||
|> `catch` { _ -> Signal<Api.EmojiList, NoError> in
|
let remote: Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError>
|
||||||
return .single(.emojiListNotModified)
|
if let query, !query.isEmpty {
|
||||||
}
|
let flags: Int32 = 1 << 0
|
||||||
|> mapToSignal { result -> Signal<(files: [TelegramMediaFile], hash: Int64)?, NoError> in
|
remote = account.network.request(Api.functions.messages.searchStickers(flags: flags, q: query, emoticon: emoticon.joined(separator: ""), langCode: [inputLanguageCode], offset: 0, limit: 128, hash: cached?.hash ?? 0))
|
||||||
switch result {
|
|> `catch` { _ -> Signal<Api.messages.FoundStickers, NoError> in
|
||||||
case .emojiListNotModified:
|
return .single(.foundStickersNotModified(flags: 0, nextOffset: nil))
|
||||||
return .single(nil)
|
|
||||||
case let .emojiList(hash, documentIds):
|
|
||||||
return TelegramEngine(account: account).stickers.resolveInlineStickers(fileIds: documentIds)
|
|
||||||
|> map { fileMap -> (files: [TelegramMediaFile], hash: Int64)? in
|
|
||||||
var files: [TelegramMediaFile] = []
|
|
||||||
for documentId in documentIds {
|
|
||||||
if let file = fileMap[documentId] {
|
|
||||||
files.append(file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (files, hash)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|> mapToSignal { result -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> in
|
||||||
|> mapToSignal { result -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> in
|
return account.postbox.transaction { transaction -> (items: [FoundStickerItem], isFinalResult: Bool) in
|
||||||
return account.postbox.transaction { transaction -> (items: [FoundStickerItem], isFinalResult: Bool) in
|
switch result {
|
||||||
if let (fileItems, hash) = result {
|
case let .foundStickers(_, _, hash, stickers):
|
||||||
var result: [FoundStickerItem] = localItems
|
var result: [FoundStickerItem] = localItems
|
||||||
var currentItemIds = Set<MediaId>(localItems.map { $0.file.fileId })
|
var currentItemIds = Set<MediaId>(localItems.map { $0.file.fileId })
|
||||||
|
|
||||||
var files: [TelegramMediaFile] = []
|
var files: [TelegramMediaFile] = []
|
||||||
for file in fileItems {
|
for sticker in stickers {
|
||||||
files.append(file)
|
guard let file = telegramMediaFileFromApiDocument(sticker, altDocuments: nil) else {
|
||||||
if !currentItemIds.contains(file.fileId) {
|
continue
|
||||||
currentItemIds.insert(file.fileId)
|
}
|
||||||
result.append(FoundStickerItem(file: file, stringRepresentations: []))
|
files.append(file)
|
||||||
|
if !currentItemIds.contains(file.fileId) {
|
||||||
|
currentItemIds.insert(file.fileId)
|
||||||
|
result.append(FoundStickerItem(file: file, stringRepresentations: []))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||||
|
if let entry = CodableEntry(CachedStickerQueryResult(items: files, hash: hash, timestamp: currentTime)) {
|
||||||
|
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedEmojiQueryResults, key: CachedStickerQueryResult.cacheKey(cacheKey)), entry: entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (result, true)
|
||||||
|
case .foundStickersNotModified:
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
return (intermediateResult, true)
|
||||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
}
|
||||||
if let entry = CodableEntry(CachedStickerQueryResult(items: files, hash: hash, timestamp: currentTime)) {
|
}
|
||||||
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedEmojiQueryResults, key: CachedStickerQueryResult.cacheKey(combinedQuery)), entry: entry)
|
} else {
|
||||||
}
|
remote = account.network.request(Api.functions.messages.searchCustomEmoji(emoticon: emoticon.joined(separator: ""), hash: cached?.hash ?? 0))
|
||||||
|
|> `catch` { _ -> Signal<Api.EmojiList, NoError> in
|
||||||
return (result, true)
|
return .single(.emojiListNotModified)
|
||||||
|
}
|
||||||
|
|> mapToSignal { result -> Signal<(files: [TelegramMediaFile], hash: Int64)?, NoError> in
|
||||||
|
switch result {
|
||||||
|
case .emojiListNotModified:
|
||||||
|
return .single(nil)
|
||||||
|
case let .emojiList(hash, documentIds):
|
||||||
|
return TelegramEngine(account: account).stickers.resolveInlineStickers(fileIds: documentIds)
|
||||||
|
|> map { fileMap -> (files: [TelegramMediaFile], hash: Int64)? in
|
||||||
|
var files: [TelegramMediaFile] = []
|
||||||
|
for documentId in documentIds {
|
||||||
|
if let file = fileMap[documentId] {
|
||||||
|
files.append(file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (files, hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> mapToSignal { result -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> in
|
||||||
|
return account.postbox.transaction { transaction -> (items: [FoundStickerItem], isFinalResult: Bool) in
|
||||||
|
if let (fileItems, hash) = result {
|
||||||
|
var result: [FoundStickerItem] = localItems
|
||||||
|
var currentItemIds = Set<MediaId>(localItems.map { $0.file.fileId })
|
||||||
|
|
||||||
|
var files: [TelegramMediaFile] = []
|
||||||
|
for file in fileItems {
|
||||||
|
files.append(file)
|
||||||
|
if !currentItemIds.contains(file.fileId) {
|
||||||
|
currentItemIds.insert(file.fileId)
|
||||||
|
result.append(FoundStickerItem(file: file, stringRepresentations: []))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||||
|
if let entry = CodableEntry(CachedStickerQueryResult(items: files, hash: hash, timestamp: currentTime)) {
|
||||||
|
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedEmojiQueryResults, key: CachedStickerQueryResult.cacheKey(cacheKey)), entry: entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (result, true)
|
||||||
|
}
|
||||||
|
return (intermediateResult, true)
|
||||||
}
|
}
|
||||||
return (intermediateResult, true)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return .single((intermediateResult, false))
|
return .single((intermediateResult, false))
|
||||||
|> then(remote)
|
|> then(
|
||||||
|
remote
|
||||||
|
|> delay(0.2, queue: Queue.concurrentDefaultQueue())
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ public extension TelegramEngine {
|
|||||||
return _internal_randomGreetingSticker(account: self.account)
|
return _internal_randomGreetingSticker(account: self.account)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func searchStickers(query: [String], scope: SearchStickersScope = [.installed, .remote]) -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> {
|
public func searchStickers(query: String?, emoticon: [String], inputLanguageCode: String = "", scope: SearchStickersScope = [.installed, .remote]) -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> {
|
||||||
return _internal_searchStickers(account: self.account, query: query, scope: scope)
|
return _internal_searchStickers(account: self.account, query: query, emoticon: emoticon, inputLanguageCode: inputLanguageCode, scope: scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func searchStickers(category: EmojiSearchCategories.Group, scope: SearchStickersScope = [.installed, .remote]) -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> {
|
public func searchStickers(category: EmojiSearchCategories.Group, scope: SearchStickersScope = [.installed, .remote]) -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> {
|
||||||
@ -287,15 +287,15 @@ public extension TelegramEngine {
|
|||||||
return _internal_resolveInlineStickersLocal(postbox: self.account.postbox, fileIds: fileIds)
|
return _internal_resolveInlineStickersLocal(postbox: self.account.postbox, fileIds: fileIds)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func searchEmoji(emojiString: [String]) -> Signal<(items: [TelegramMediaFile], isFinalResult: Bool), NoError> {
|
public func searchEmoji(query: String?, emoticon: [String], inputLanguageCode: String = "") -> Signal<(items: [TelegramMediaFile], isFinalResult: Bool), NoError> {
|
||||||
return _internal_searchEmoji(account: self.account, query: emojiString)
|
return _internal_searchEmoji(account: self.account, query: query, emoticon: emoticon, inputLanguageCode: inputLanguageCode)
|
||||||
|> map { items, isFinalResult -> (items: [TelegramMediaFile], isFinalResult: Bool) in
|
|> map { items, isFinalResult -> (items: [TelegramMediaFile], isFinalResult: Bool) in
|
||||||
return (items.map(\.file), isFinalResult)
|
return (items.map(\.file), isFinalResult)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func searchEmoji(category: EmojiSearchCategories.Group) -> Signal<(items: [TelegramMediaFile], isFinalResult: Bool), NoError> {
|
public func searchEmoji(category: EmojiSearchCategories.Group) -> Signal<(items: [TelegramMediaFile], isFinalResult: Bool), NoError> {
|
||||||
return _internal_searchEmoji(account: self.account, query: category.identifiers)
|
return _internal_searchEmoji(account: self.account, query: nil, emoticon: category.identifiers, inputLanguageCode: "")
|
||||||
|> map { items, isFinalResult -> (items: [TelegramMediaFile], isFinalResult: Bool) in
|
|> map { items, isFinalResult -> (items: [TelegramMediaFile], isFinalResult: Bool) in
|
||||||
return (items.map(\.file), isFinalResult)
|
return (items.map(\.file), isFinalResult)
|
||||||
}
|
}
|
||||||
|
@ -338,7 +338,7 @@ final class AvatarEditorScreenComponent: Component {
|
|||||||
|> mapToSignal { keywords -> Signal<[EmojiPagerContentComponent.ItemGroup], NoError> in
|
|> mapToSignal { keywords -> Signal<[EmojiPagerContentComponent.ItemGroup], NoError> in
|
||||||
return combineLatest(
|
return combineLatest(
|
||||||
context.account.postbox.itemCollectionsView(orderedItemListCollectionIds: [], namespaces: [Namespaces.ItemCollection.CloudEmojiPacks], aroundIndex: nil, count: 10000000) |> take(1),
|
context.account.postbox.itemCollectionsView(orderedItemListCollectionIds: [], namespaces: [Namespaces.ItemCollection.CloudEmojiPacks], aroundIndex: nil, count: 10000000) |> take(1),
|
||||||
combineLatest(keywords.map { context.engine.stickers.searchStickers(query: $0.emoticons)
|
combineLatest(keywords.map { context.engine.stickers.searchStickers(query: query, emoticon: $0.emoticons, inputLanguageCode: languageCode)
|
||||||
|> map { items -> [FoundStickerItem] in
|
|> map { items -> [FoundStickerItem] in
|
||||||
return items.items
|
return items.items
|
||||||
}
|
}
|
||||||
|
@ -1020,6 +1020,7 @@ private final class CameraScreenComponent: CombinedComponent {
|
|||||||
hasAccess: hasAllRequiredAccess,
|
hasAccess: hasAllRequiredAccess,
|
||||||
hideControls: component.cameraState.collageProgress > 1.0 - .ulpOfOne,
|
hideControls: component.cameraState.collageProgress > 1.0 - .ulpOfOne,
|
||||||
collageProgress: component.cameraState.collageProgress,
|
collageProgress: component.cameraState.collageProgress,
|
||||||
|
collageCount: component.cameraState.isCollageEnabled ? component.cameraState.collageGrid.count : nil,
|
||||||
tintColor: controlsTintColor,
|
tintColor: controlsTintColor,
|
||||||
shutterState: shutterState,
|
shutterState: shutterState,
|
||||||
lastGalleryAsset: state.lastGalleryAsset,
|
lastGalleryAsset: state.lastGalleryAsset,
|
||||||
@ -1683,6 +1684,7 @@ public class CameraScreenImpl: ViewController, CameraScreen {
|
|||||||
fileprivate var additionalPreviewView: CameraSimplePreviewView
|
fileprivate var additionalPreviewView: CameraSimplePreviewView
|
||||||
|
|
||||||
fileprivate let previewBlurView: BlurView
|
fileprivate let previewBlurView: BlurView
|
||||||
|
fileprivate let mainPreviewBlurView: BlurView
|
||||||
private var mainPreviewSnapshotView: UIView?
|
private var mainPreviewSnapshotView: UIView?
|
||||||
private var additionalPreviewSnapshotView: UIView?
|
private var additionalPreviewSnapshotView: UIView?
|
||||||
fileprivate let previewFrameLeftDimView: UIView
|
fileprivate let previewFrameLeftDimView: UIView
|
||||||
@ -1795,6 +1797,9 @@ public class CameraScreenImpl: ViewController, CameraScreen {
|
|||||||
self.previewBlurView = BlurView()
|
self.previewBlurView = BlurView()
|
||||||
self.previewBlurView.isUserInteractionEnabled = false
|
self.previewBlurView.isUserInteractionEnabled = false
|
||||||
|
|
||||||
|
self.mainPreviewBlurView = BlurView()
|
||||||
|
self.mainPreviewBlurView.isUserInteractionEnabled = false
|
||||||
|
|
||||||
var isDualCameraEnabled = Camera.isDualCameraSupported(forRoundVideo: false)
|
var isDualCameraEnabled = Camera.isDualCameraSupported(forRoundVideo: false)
|
||||||
if isDualCameraEnabled {
|
if isDualCameraEnabled {
|
||||||
if let isDualCameraEnabledValue = UserDefaults.standard.object(forKey: "TelegramStoryCameraIsDualEnabled") as? NSNumber {
|
if let isDualCameraEnabledValue = UserDefaults.standard.object(forKey: "TelegramStoryCameraIsDualEnabled") as? NSNumber {
|
||||||
@ -2122,9 +2127,17 @@ public class CameraScreenImpl: ViewController, CameraScreen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if case .position = modeChange {
|
if case .position = modeChange {
|
||||||
UIView.transition(with: self.previewContainerView, duration: 0.4, options: [.transitionFlipFromLeft, .curveEaseOut], animations: {
|
if self.cameraState.isCollageEnabled {
|
||||||
self.previewBlurView.effect = UIBlurEffect(style: .dark)
|
self.mainPreviewBlurView.frame = self.mainPreviewContainerView.bounds
|
||||||
})
|
self.mainPreviewContainerView.addSubview(self.mainPreviewBlurView)
|
||||||
|
UIView.transition(with: self.mainPreviewContainerView, duration: 0.4, options: [.transitionFlipFromLeft, .curveEaseOut], animations: {
|
||||||
|
self.mainPreviewBlurView.effect = UIBlurEffect(style: .dark)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
UIView.transition(with: self.previewContainerView, duration: 0.4, options: [.transitionFlipFromLeft, .curveEaseOut], animations: {
|
||||||
|
self.previewBlurView.effect = UIBlurEffect(style: .dark)
|
||||||
|
})
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.previewContainerView.insertSubview(self.previewBlurView, belowSubview: self.additionalPreviewContainerView)
|
self.previewContainerView.insertSubview(self.previewBlurView, belowSubview: self.additionalPreviewContainerView)
|
||||||
|
|
||||||
@ -2137,6 +2150,13 @@ public class CameraScreenImpl: ViewController, CameraScreen {
|
|||||||
self.previewBlurView.effect = UIBlurEffect(style: .dark)
|
self.previewBlurView.effect = UIBlurEffect(style: .dark)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if self.mainPreviewBlurView.effect != nil {
|
||||||
|
UIView.animate(withDuration: 0.4, animations: {
|
||||||
|
self.mainPreviewBlurView.effect = nil
|
||||||
|
}, completion: { _ in
|
||||||
|
self.mainPreviewBlurView.removeFromSuperview()
|
||||||
|
})
|
||||||
|
}
|
||||||
if self.previewBlurView.effect != nil {
|
if self.previewBlurView.effect != nil {
|
||||||
UIView.animate(withDuration: 0.4, animations: {
|
UIView.animate(withDuration: 0.4, animations: {
|
||||||
self.previewBlurView.effect = nil
|
self.previewBlurView.effect = nil
|
||||||
@ -2971,7 +2991,7 @@ public class CameraScreenImpl: ViewController, CameraScreen {
|
|||||||
}
|
}
|
||||||
self.updatingCollageProgress = true
|
self.updatingCollageProgress = true
|
||||||
self.controller?.updateCameraState({ state in
|
self.controller?.updateCameraState({ state in
|
||||||
return state.updatedCollageProgress(collageState.progress)
|
return state.updatedCollageProgress(collageState.innerProgress)
|
||||||
}, transition: .spring(duration: 0.3))
|
}, transition: .spring(duration: 0.3))
|
||||||
self.updatingCollageProgress = false
|
self.updatingCollageProgress = false
|
||||||
})
|
})
|
||||||
|
@ -36,6 +36,7 @@ private final class ShutterButtonContentComponent: Component {
|
|||||||
let shutterState: ShutterButtonState
|
let shutterState: ShutterButtonState
|
||||||
let blobState: ShutterBlobView.BlobState
|
let blobState: ShutterBlobView.BlobState
|
||||||
let collageProgress: Float
|
let collageProgress: Float
|
||||||
|
let collageCount: Int?
|
||||||
let highlightedAction: ActionSlot<Bool>
|
let highlightedAction: ActionSlot<Bool>
|
||||||
let updateOffsetX: ActionSlot<(CGFloat, ComponentTransition)>
|
let updateOffsetX: ActionSlot<(CGFloat, ComponentTransition)>
|
||||||
let updateOffsetY: ActionSlot<(CGFloat, ComponentTransition)>
|
let updateOffsetY: ActionSlot<(CGFloat, ComponentTransition)>
|
||||||
@ -47,6 +48,7 @@ private final class ShutterButtonContentComponent: Component {
|
|||||||
shutterState: ShutterButtonState,
|
shutterState: ShutterButtonState,
|
||||||
blobState: ShutterBlobView.BlobState,
|
blobState: ShutterBlobView.BlobState,
|
||||||
collageProgress: Float,
|
collageProgress: Float,
|
||||||
|
collageCount: Int?,
|
||||||
highlightedAction: ActionSlot<Bool>,
|
highlightedAction: ActionSlot<Bool>,
|
||||||
updateOffsetX: ActionSlot<(CGFloat, ComponentTransition)>,
|
updateOffsetX: ActionSlot<(CGFloat, ComponentTransition)>,
|
||||||
updateOffsetY: ActionSlot<(CGFloat, ComponentTransition)>
|
updateOffsetY: ActionSlot<(CGFloat, ComponentTransition)>
|
||||||
@ -57,6 +59,7 @@ private final class ShutterButtonContentComponent: Component {
|
|||||||
self.shutterState = shutterState
|
self.shutterState = shutterState
|
||||||
self.blobState = blobState
|
self.blobState = blobState
|
||||||
self.collageProgress = collageProgress
|
self.collageProgress = collageProgress
|
||||||
|
self.collageCount = collageCount
|
||||||
self.highlightedAction = highlightedAction
|
self.highlightedAction = highlightedAction
|
||||||
self.updateOffsetX = updateOffsetX
|
self.updateOffsetX = updateOffsetX
|
||||||
self.updateOffsetY = updateOffsetY
|
self.updateOffsetY = updateOffsetY
|
||||||
@ -81,6 +84,9 @@ private final class ShutterButtonContentComponent: Component {
|
|||||||
if lhs.collageProgress != rhs.collageProgress {
|
if lhs.collageProgress != rhs.collageProgress {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.collageCount != rhs.collageCount {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,6 +320,8 @@ private final class ShutterButtonContentComponent: Component {
|
|||||||
self.innerLayer.bounds = CGRect(origin: .zero, size: innerSize)
|
self.innerLayer.bounds = CGRect(origin: .zero, size: innerSize)
|
||||||
self.innerLayer.position = CGPoint(x: maximumShutterSize.width / 2.0, y: maximumShutterSize.height / 2.0)
|
self.innerLayer.position = CGPoint(x: maximumShutterSize.width / 2.0, y: maximumShutterSize.height / 2.0)
|
||||||
|
|
||||||
|
let totalProgress = component.collageCount.flatMap { 1.0 / Double($0) } ?? 1.0
|
||||||
|
|
||||||
self.progressLayer.bounds = CGRect(origin: .zero, size: maximumShutterSize)
|
self.progressLayer.bounds = CGRect(origin: .zero, size: maximumShutterSize)
|
||||||
self.progressLayer.position = CGPoint(x: maximumShutterSize.width / 2.0, y: maximumShutterSize.height / 2.0)
|
self.progressLayer.position = CGPoint(x: maximumShutterSize.width / 2.0, y: maximumShutterSize.height / 2.0)
|
||||||
transition.setShapeLayerPath(layer: self.progressLayer, path: ringPath)
|
transition.setShapeLayerPath(layer: self.progressLayer, path: ringPath)
|
||||||
@ -321,10 +329,14 @@ private final class ShutterButtonContentComponent: Component {
|
|||||||
self.progressLayer.strokeColor = videoRedColor.cgColor
|
self.progressLayer.strokeColor = videoRedColor.cgColor
|
||||||
self.progressLayer.lineWidth = ringWidth + UIScreenPixel
|
self.progressLayer.lineWidth = ringWidth + UIScreenPixel
|
||||||
self.progressLayer.lineCap = .round
|
self.progressLayer.lineCap = .round
|
||||||
self.progressLayer.transform = CATransform3DMakeRotation(-.pi / 2.0, 0.0, 0.0, 1.0)
|
if totalProgress < 1.0 {
|
||||||
|
self.progressLayer.transform = CATransform3DMakeRotation(-.pi / 2.0 + CGFloat(component.collageProgress) * 2.0 * .pi, 0.0, 0.0, 1.0)
|
||||||
|
} else {
|
||||||
|
self.progressLayer.transform = CATransform3DMakeRotation(-.pi / 2.0, 0.0, 0.0, 1.0)
|
||||||
|
}
|
||||||
|
|
||||||
let previousValue = self.progressLayer.strokeEnd
|
let previousValue = self.progressLayer.strokeEnd
|
||||||
self.progressLayer.strokeEnd = CGFloat(recordingProgress ?? 0.0)
|
self.progressLayer.strokeEnd = CGFloat(recordingProgress ?? 0.0) * totalProgress
|
||||||
self.progressLayer.animateStrokeEnd(from: previousValue, to: self.progressLayer.strokeEnd, duration: 0.33)
|
self.progressLayer.animateStrokeEnd(from: previousValue, to: self.progressLayer.strokeEnd, duration: 0.33)
|
||||||
|
|
||||||
return maximumShutterSize
|
return maximumShutterSize
|
||||||
@ -554,6 +566,7 @@ final class CaptureControlsComponent: Component {
|
|||||||
let hasAccess: Bool
|
let hasAccess: Bool
|
||||||
let hideControls: Bool
|
let hideControls: Bool
|
||||||
let collageProgress: Float
|
let collageProgress: Float
|
||||||
|
let collageCount: Int?
|
||||||
let tintColor: UIColor
|
let tintColor: UIColor
|
||||||
let shutterState: ShutterButtonState
|
let shutterState: ShutterButtonState
|
||||||
let lastGalleryAsset: PHAsset?
|
let lastGalleryAsset: PHAsset?
|
||||||
@ -576,6 +589,7 @@ final class CaptureControlsComponent: Component {
|
|||||||
hasAccess: Bool,
|
hasAccess: Bool,
|
||||||
hideControls: Bool,
|
hideControls: Bool,
|
||||||
collageProgress: Float,
|
collageProgress: Float,
|
||||||
|
collageCount: Int?,
|
||||||
tintColor: UIColor,
|
tintColor: UIColor,
|
||||||
shutterState: ShutterButtonState,
|
shutterState: ShutterButtonState,
|
||||||
lastGalleryAsset: PHAsset?,
|
lastGalleryAsset: PHAsset?,
|
||||||
@ -597,6 +611,7 @@ final class CaptureControlsComponent: Component {
|
|||||||
self.hasAccess = hasAccess
|
self.hasAccess = hasAccess
|
||||||
self.hideControls = hideControls
|
self.hideControls = hideControls
|
||||||
self.collageProgress = collageProgress
|
self.collageProgress = collageProgress
|
||||||
|
self.collageCount = collageCount
|
||||||
self.tintColor = tintColor
|
self.tintColor = tintColor
|
||||||
self.shutterState = shutterState
|
self.shutterState = shutterState
|
||||||
self.lastGalleryAsset = lastGalleryAsset
|
self.lastGalleryAsset = lastGalleryAsset
|
||||||
@ -632,6 +647,9 @@ final class CaptureControlsComponent: Component {
|
|||||||
if lhs.collageProgress != rhs.collageProgress {
|
if lhs.collageProgress != rhs.collageProgress {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.collageCount != rhs.collageCount {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.tintColor != rhs.tintColor {
|
if lhs.tintColor != rhs.tintColor {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -1152,6 +1170,7 @@ final class CaptureControlsComponent: Component {
|
|||||||
shutterState: component.shutterState,
|
shutterState: component.shutterState,
|
||||||
blobState: blobState,
|
blobState: blobState,
|
||||||
collageProgress: component.collageProgress,
|
collageProgress: component.collageProgress,
|
||||||
|
collageCount: component.collageCount,
|
||||||
highlightedAction: self.shutterHightlightedAction,
|
highlightedAction: self.shutterHightlightedAction,
|
||||||
updateOffsetX: self.shutterUpdateOffsetX,
|
updateOffsetX: self.shutterUpdateOffsetX,
|
||||||
updateOffsetY: self.shutterUpdateOffsetY
|
updateOffsetY: self.shutterUpdateOffsetY
|
||||||
|
@ -938,7 +938,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||||||
let remoteSignal: Signal<(items: [TelegramMediaFile], isFinalResult: Bool), NoError>
|
let remoteSignal: Signal<(items: [TelegramMediaFile], isFinalResult: Bool), NoError>
|
||||||
let remotePacksSignal: Signal<(sets: FoundStickerSets, isFinalResult: Bool), NoError>
|
let remotePacksSignal: Signal<(sets: FoundStickerSets, isFinalResult: Bool), NoError>
|
||||||
if hasPremium {
|
if hasPremium {
|
||||||
remoteSignal = context.engine.stickers.searchEmoji(emojiString: Array(allEmoticons.keys))
|
remoteSignal = context.engine.stickers.searchEmoji(query: query, emoticon: Array(allEmoticons.keys), inputLanguageCode: languageCode)
|
||||||
remotePacksSignal = context.engine.stickers.searchEmojiSets(query: query)
|
remotePacksSignal = context.engine.stickers.searchEmojiSets(query: query)
|
||||||
|> mapToSignal { localResult in
|
|> mapToSignal { localResult in
|
||||||
return .single((localResult, false))
|
return .single((localResult, false))
|
||||||
|
@ -348,7 +348,7 @@ final class StickerPaneSearchContentNode: ASDisplayNode, PaneSearchContentNode {
|
|||||||
|
|
||||||
let query = text.trimmingCharacters(in: .whitespacesAndNewlines)
|
let query = text.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
if query.isSingleEmoji {
|
if query.isSingleEmoji {
|
||||||
signals = .single([context.engine.stickers.searchStickers(query: [text.basicEmoji.0])
|
signals = .single([context.engine.stickers.searchStickers(query: nil, emoticon: [text.basicEmoji.0])
|
||||||
|> map { (nil, $0.items) }])
|
|> map { (nil, $0.items) }])
|
||||||
} else if query.count > 1, let languageCode = languageCode, !languageCode.isEmpty && languageCode != "emoji" {
|
} else if query.count > 1, let languageCode = languageCode, !languageCode.isEmpty && languageCode != "emoji" {
|
||||||
var signal = context.engine.stickers.searchEmojiKeywords(inputLanguageCode: languageCode, query: query.lowercased(), completeMatch: query.count < 3)
|
var signal = context.engine.stickers.searchEmojiKeywords(inputLanguageCode: languageCode, query: query.lowercased(), completeMatch: query.count < 3)
|
||||||
@ -364,17 +364,11 @@ final class StickerPaneSearchContentNode: ASDisplayNode, PaneSearchContentNode {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
signals = signal
|
signals = signal
|
||||||
|> map { keywords -> [Signal<(String?, [FoundStickerItem]), NoError>] in
|
|> map { keywords -> [Signal<(String?, [FoundStickerItem]), NoError>] in
|
||||||
var signals: [Signal<(String?, [FoundStickerItem]), NoError>] = []
|
let emoticon = keywords.flatMap { $0.emoticons }.map { $0.basicEmoji.0 }
|
||||||
let emoticons = keywords.flatMap { $0.emoticons }
|
return [context.engine.stickers.searchStickers(query: query, emoticon: emoticon, inputLanguageCode: languageCode)
|
||||||
for emoji in emoticons {
|
|> map { (nil, $0.items) }]
|
||||||
signals.append(context.engine.stickers.searchStickers(query: [emoji.basicEmoji.0])
|
|
||||||
// |> take(1)
|
|
||||||
|> map { (emoji, $0.items) })
|
|
||||||
}
|
|
||||||
return signals
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ private func updatedContextQueryResultStateForQuery(context: AccountContext, cha
|
|||||||
case .installed:
|
case .installed:
|
||||||
scope = [.installed]
|
scope = [.installed]
|
||||||
}
|
}
|
||||||
return context.engine.stickers.searchStickers(query: [query.basicEmoji.0], scope: scope)
|
return context.engine.stickers.searchStickers(query: nil, emoticon: [query.basicEmoji.0], scope: scope)
|
||||||
|> map { items -> [FoundStickerItem] in
|
|> map { items -> [FoundStickerItem] in
|
||||||
return items.items
|
return items.items
|
||||||
}
|
}
|
||||||
|
@ -1759,17 +1759,19 @@ public final class MessageInputPanelComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var lightFieldColor = UIColor(white: 1.0, alpha: 0.09)
|
||||||
var fieldBackgroundIsDark = false
|
var fieldBackgroundIsDark = false
|
||||||
if component.useGrayBackground {
|
if component.useGrayBackground {
|
||||||
fieldBackgroundIsDark = false
|
fieldBackgroundIsDark = false
|
||||||
} else if component.style == .media {
|
} else if component.style == .media {
|
||||||
fieldBackgroundIsDark = true
|
fieldBackgroundIsDark = false
|
||||||
|
lightFieldColor = UIColor(white: 0.2, alpha: 0.45)
|
||||||
} else if self.textFieldExternalState.hasText && component.alwaysDarkWhenHasText {
|
} else if self.textFieldExternalState.hasText && component.alwaysDarkWhenHasText {
|
||||||
fieldBackgroundIsDark = true
|
fieldBackgroundIsDark = true
|
||||||
} else if isEditing || component.style == .editor {
|
} else if isEditing || component.style == .editor {
|
||||||
fieldBackgroundIsDark = true
|
fieldBackgroundIsDark = true
|
||||||
}
|
}
|
||||||
self.fieldBackgroundView.updateColor(color: fieldBackgroundIsDark ? UIColor(white: 0.0, alpha: 0.5) : UIColor(white: 1.0, alpha: 0.09), transition: transition.containedViewLayoutTransition)
|
self.fieldBackgroundView.updateColor(color: fieldBackgroundIsDark ? UIColor(white: 0.0, alpha: 0.5) : lightFieldColor, transition: transition.containedViewLayoutTransition)
|
||||||
if let placeholder = self.placeholder.view, let vibrancyPlaceholderView = self.vibrancyPlaceholder.view {
|
if let placeholder = self.placeholder.view, let vibrancyPlaceholderView = self.vibrancyPlaceholder.view {
|
||||||
placeholder.isHidden = self.textFieldExternalState.hasText
|
placeholder.isHidden = self.textFieldExternalState.hasText
|
||||||
vibrancyPlaceholderView.isHidden = placeholder.isHidden
|
vibrancyPlaceholderView.isHidden = placeholder.isHidden
|
||||||
|
@ -687,7 +687,7 @@ final class PeerAllowedReactionsScreenComponent: Component {
|
|||||||
))
|
))
|
||||||
return .single(resultGroups)
|
return .single(resultGroups)
|
||||||
} else {
|
} else {
|
||||||
let remoteSignal = context.engine.stickers.searchEmoji(emojiString: Array(allEmoticons.keys))
|
let remoteSignal = context.engine.stickers.searchEmoji(query: query, emoticon: Array(allEmoticons.keys), inputLanguageCode: languageCode)
|
||||||
|
|
||||||
return combineLatest(
|
return combineLatest(
|
||||||
context.account.postbox.itemCollectionsView(orderedItemListCollectionIds: [], namespaces: [Namespaces.ItemCollection.CloudEmojiPacks], aroundIndex: nil, count: 10000000) |> take(1),
|
context.account.postbox.itemCollectionsView(orderedItemListCollectionIds: [], namespaces: [Namespaces.ItemCollection.CloudEmojiPacks], aroundIndex: nil, count: 10000000) |> take(1),
|
||||||
|
@ -798,7 +798,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
|||||||
let botsKey = ValueBoxKey(length: 8)
|
let botsKey = ValueBoxKey(length: 8)
|
||||||
botsKey.setInt64(0, value: 0)
|
botsKey.setInt64(0, value: 0)
|
||||||
|
|
||||||
let iconLoaded = Atomic<[EnginePeer.Id: Bool]>(value: [:])
|
//let iconLoaded = Atomic<[EnginePeer.Id: Bool]>(value: [:])
|
||||||
let bots = context.engine.data.subscribe(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: Namespaces.CachedItemCollection.attachMenuBots, id: botsKey))
|
let bots = context.engine.data.subscribe(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: Namespaces.CachedItemCollection.attachMenuBots, id: botsKey))
|
||||||
|> mapToSignal { entry -> Signal<[AttachMenuBot], NoError> in
|
|> mapToSignal { entry -> Signal<[AttachMenuBot], NoError> in
|
||||||
let bots: [AttachMenuBots.Bot] = entry?.get(AttachMenuBots.self)?.bots ?? []
|
let bots: [AttachMenuBots.Bot] = entry?.get(AttachMenuBots.self)?.bots ?? []
|
||||||
@ -811,32 +811,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
|||||||
if let maybePeer = peersMap[bot.peerId], let peer = maybePeer {
|
if let maybePeer = peersMap[bot.peerId], let peer = maybePeer {
|
||||||
let resultBot = AttachMenuBot(peer: peer, shortName: bot.name, icons: bot.icons, peerTypes: bot.peerTypes, flags: bot.flags)
|
let resultBot = AttachMenuBot(peer: peer, shortName: bot.name, icons: bot.icons, peerTypes: bot.peerTypes, flags: bot.flags)
|
||||||
if bot.flags.contains(.showInSettings) {
|
if bot.flags.contains(.showInSettings) {
|
||||||
if let peer = PeerReference(peer._asPeer()), let icon = bot.icons[.iOSSettingsStatic] {
|
result.append(.single(resultBot))
|
||||||
let fileReference: FileMediaReference = .attachBot(peer: peer, media: icon)
|
|
||||||
let signal: Signal<AttachMenuBot?, NoError>
|
|
||||||
if let _ = iconLoaded.with({ $0 })[peer.id] {
|
|
||||||
signal = .single(resultBot)
|
|
||||||
} else {
|
|
||||||
signal = .single(nil)
|
|
||||||
|> then(
|
|
||||||
preloadedBotIcon(account: context.account, fileReference: fileReference)
|
|
||||||
|> filter { $0 }
|
|
||||||
|> map { _ -> AttachMenuBot? in
|
|
||||||
return resultBot
|
|
||||||
}
|
|
||||||
|> afterNext { _ in
|
|
||||||
let _ = iconLoaded.modify { current in
|
|
||||||
var updated = current
|
|
||||||
updated[peer.id] = true
|
|
||||||
return updated
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
result.append(signal)
|
|
||||||
} else {
|
|
||||||
result.append(.single(resultBot))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -923,7 +923,7 @@ private func settingsItems(data: PeerInfoScreenData?, context: AccountContext, p
|
|||||||
}
|
}
|
||||||
let _ = freeMediaFileInteractiveFetched(account: context.account, userLocation: .other, fileReference: fileReference).startStandalone()
|
let _ = freeMediaFileInteractiveFetched(account: context.account, userLocation: .other, fileReference: fileReference).startStandalone()
|
||||||
} else {
|
} else {
|
||||||
iconSignal = .single(UIImage(bundleImageName: "Settings/Menu/Websites")!)
|
iconSignal = .single(UIImage())
|
||||||
}
|
}
|
||||||
let label: PeerInfoScreenDisclosureItem.Label = bot.flags.contains(.notActivated) || bot.flags.contains(.showInSettingsDisclaimer) ? .titleBadge(presentationData.strings.Settings_New, presentationData.theme.list.itemAccentColor) : .none
|
let label: PeerInfoScreenDisclosureItem.Label = bot.flags.contains(.notActivated) || bot.flags.contains(.showInSettingsDisclaimer) ? .titleBadge(presentationData.strings.Settings_New, presentationData.theme.list.itemAccentColor) : .none
|
||||||
items[.apps]!.append(PeerInfoScreenDisclosureItem(id: bot.peer.id.id._internalGetInt64Value(), label: label, text: bot.shortName, icon: nil, iconSignal: iconSignal, action: {
|
items[.apps]!.append(PeerInfoScreenDisclosureItem(id: bot.peer.id.id._internalGetInt64Value(), label: label, text: bot.shortName, icon: nil, iconSignal: iconSignal, action: {
|
||||||
@ -5276,7 +5276,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
transitionCompletion()
|
transitionCompletion()
|
||||||
}, getCaptionPanelView: {
|
}, getCaptionPanelView: {
|
||||||
return nil
|
return nil
|
||||||
}, sendMessagesWithSignals: { [weak self] signals, _, _ in
|
}, sendMessagesWithSignals: { [weak self] signals, _, _, _ in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.enqueueMediaMessageDisposable.set((legacyAssetPickerEnqueueMessages(context: strongSelf.context, account: strongSelf.context.account, signals: signals!)
|
strongSelf.enqueueMediaMessageDisposable.set((legacyAssetPickerEnqueueMessages(context: strongSelf.context, account: strongSelf.context.account, signals: signals!)
|
||||||
|> deliverOnMainQueue).startStrict(next: { [weak self] messages in
|
|> deliverOnMainQueue).startStrict(next: { [weak self] messages in
|
||||||
|
@ -370,7 +370,7 @@ final class BusinessIntroSetupScreenComponent: Component {
|
|||||||
var signals: Signal<[Signal<(String?, [FoundStickerItem]), NoError>], NoError> = .single([])
|
var signals: Signal<[Signal<(String?, [FoundStickerItem]), NoError>], NoError> = .single([])
|
||||||
|
|
||||||
if query.isSingleEmoji {
|
if query.isSingleEmoji {
|
||||||
signals = .single([context.engine.stickers.searchStickers(query: [query.basicEmoji.0])
|
signals = .single([context.engine.stickers.searchStickers(query: nil, emoticon: [query.basicEmoji.0])
|
||||||
|> map { (nil, $0.items) }])
|
|> map { (nil, $0.items) }])
|
||||||
} else if query.count > 1, !languageCode.isEmpty && languageCode != "emoji" {
|
} else if query.count > 1, !languageCode.isEmpty && languageCode != "emoji" {
|
||||||
var signal = context.engine.stickers.searchEmojiKeywords(inputLanguageCode: languageCode, query: query.lowercased(), completeMatch: query.count < 3)
|
var signal = context.engine.stickers.searchEmojiKeywords(inputLanguageCode: languageCode, query: query.lowercased(), completeMatch: query.count < 3)
|
||||||
@ -385,18 +385,12 @@ final class BusinessIntroSetupScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
signals = signal
|
signals = signal
|
||||||
|> map { keywords -> [Signal<(String?, [FoundStickerItem]), NoError>] in
|
|> map { keywords -> [Signal<(String?, [FoundStickerItem]), NoError>] in
|
||||||
var signals: [Signal<(String?, [FoundStickerItem]), NoError>] = []
|
let emoticon = keywords.flatMap { $0.emoticons }.map { $0.basicEmoji.0 }
|
||||||
let emoticons = keywords.flatMap { $0.emoticons }
|
return [context.engine.stickers.searchStickers(query: query, emoticon: emoticon, inputLanguageCode: languageCode)
|
||||||
for emoji in emoticons {
|
|> map { (nil, $0.items) }]
|
||||||
signals.append(context.engine.stickers.searchStickers(query: [emoji.basicEmoji.0])
|
|
||||||
|> take(1)
|
|
||||||
|> map { (emoji, $0.items) })
|
|
||||||
}
|
|
||||||
return signals
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1080,7 +1080,7 @@ public class StickerPickerScreen: ViewController {
|
|||||||
}
|
}
|
||||||
let remoteSignal: Signal<(items: [TelegramMediaFile], isFinalResult: Bool), NoError>
|
let remoteSignal: Signal<(items: [TelegramMediaFile], isFinalResult: Bool), NoError>
|
||||||
if hasPremium {
|
if hasPremium {
|
||||||
remoteSignal = context.engine.stickers.searchEmoji(emojiString: Array(allEmoticons.keys))
|
remoteSignal = context.engine.stickers.searchEmoji(query: query, emoticon: Array(allEmoticons.keys), inputLanguageCode: languageCode)
|
||||||
} else {
|
} else {
|
||||||
remoteSignal = .single(([], true))
|
remoteSignal = .single(([], true))
|
||||||
}
|
}
|
||||||
|
@ -1462,9 +1462,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
transitionCompletion()
|
transitionCompletion()
|
||||||
}, getCaptionPanelView: { [weak self] in
|
}, getCaptionPanelView: { [weak self] in
|
||||||
return self?.getCaptionPanelView(isFile: false)
|
return self?.getCaptionPanelView(isFile: false)
|
||||||
}, sendMessagesWithSignals: { [weak self] signals, _, _ in
|
}, sendMessagesWithSignals: { [weak self] signals, _, _, isCaptionAbove in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.enqueueMediaMessages(signals: signals, silentPosting: false)
|
var parameters: ChatSendMessageActionSheetController.SendParameters?
|
||||||
|
if isCaptionAbove {
|
||||||
|
parameters = ChatSendMessageActionSheetController.SendParameters(effect: nil, textIsAboveMedia: true)
|
||||||
|
}
|
||||||
|
strongSelf.enqueueMediaMessages(signals: signals, silentPosting: false, parameters: parameters)
|
||||||
}
|
}
|
||||||
}, present: { [weak self] c, a in
|
}, present: { [weak self] c, a in
|
||||||
self?.present(c, in: .window(.root), with: a)
|
self?.present(c, in: .window(.root), with: a)
|
||||||
@ -3801,7 +3805,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
let inputText = strongSelf.presentationInterfaceState.interfaceState.effectiveInputState.inputText
|
let inputText = strongSelf.presentationInterfaceState.interfaceState.effectiveInputState.inputText
|
||||||
legacyMediaEditor(context: strongSelf.context, peer: peer, threadTitle: strongSelf.threadInfo?.title, media: mediaReference, mode: .draw, initialCaption: inputText, snapshots: [], transitionCompletion: nil, getCaptionPanelView: { [weak self] in
|
legacyMediaEditor(context: strongSelf.context, peer: peer, threadTitle: strongSelf.threadInfo?.title, media: mediaReference, mode: .draw, initialCaption: inputText, snapshots: [], transitionCompletion: nil, getCaptionPanelView: { [weak self] in
|
||||||
return self?.getCaptionPanelView(isFile: true)
|
return self?.getCaptionPanelView(isFile: true)
|
||||||
}, sendMessagesWithSignals: { [weak self] signals, _, _ in
|
}, sendMessagesWithSignals: { [weak self] signals, _, _, _ in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.interfaceInteraction?.setupEditMessage(messageId, { _ in })
|
strongSelf.interfaceInteraction?.setupEditMessage(messageId, { _ in })
|
||||||
strongSelf.editMessageMediaWithLegacySignals(signals!)
|
strongSelf.editMessageMediaWithLegacySignals(signals!)
|
||||||
|
@ -95,7 +95,7 @@ private func updatedContextQueryResultStateForQuery(context: AccountContext, pee
|
|||||||
case .installed:
|
case .installed:
|
||||||
scope = [.installed]
|
scope = [.installed]
|
||||||
}
|
}
|
||||||
return context.engine.stickers.searchStickers(query: [query.basicEmoji.0], scope: scope)
|
return context.engine.stickers.searchStickers(query: nil, emoticon: [query.basicEmoji.0], scope: scope)
|
||||||
|> map { items -> [FoundStickerItem] in
|
|> map { items -> [FoundStickerItem] in
|
||||||
return items.items
|
return items.items
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"app": "11.4",
|
"app": "11.5",
|
||||||
"xcode": "16.0",
|
"xcode": "16.0",
|
||||||
"bazel": "7.3.1:981f82a470bad1349322b6f51c9c6ffa0aa291dab1014fac411543c12e661dff",
|
"bazel": "7.3.1:981f82a470bad1349322b6f51c9c6ffa0aa291dab1014fac411543c12e661dff",
|
||||||
"macos": "15.0"
|
"macos": "15.0"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user