mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Bot apps implementation
This commit is contained in:
parent
4c6dd1e16d
commit
53d1cb856a
@ -8939,5 +8939,16 @@ Sorry for the inconvenience.";
|
||||
"ChatList.ClearSavedMessagesConfirmation" = "Are you sure you want to delete all your saved messages?";
|
||||
|
||||
"Conversation.Translation.Settings" = "Settings";
|
||||
|
||||
"StickerPacksSettings.TrendingStickers" = "Trending Stickers";
|
||||
"StickerPacksSettings.MyStickers" = "MY STICKERS";
|
||||
|
||||
"StickerPacksSettings.DynamicOrder" = "Dynamic Pack Order";
|
||||
"StickerPacksSettings.DynamicOrderInfo" = "Recently used sticker packs will be displayed above the older ones.";
|
||||
"StickerPacksSettings.Emoji" = "Emoji";
|
||||
|
||||
"StickerPacksSettings.DynamicOrderOff" = "Dynamic Order Off";
|
||||
"StickerPacksSettings.DynamicOrderOffInfo" = "Sticker packs will no longer be automatically rearranged every time you use a sticker.";
|
||||
|
||||
"GroupPermission.NotAvailableInDiscussionGroups" = "This permission is not available in discussion groups.";
|
||||
"GroupPermission.NotAvailableInGeoGroups" = "This permission is not available in location-based groups.";
|
||||
|
@ -443,6 +443,7 @@ public final class NavigateToChatControllerParams {
|
||||
public let subject: ChatControllerSubject?
|
||||
public let botStart: ChatControllerInitialBotStart?
|
||||
public let attachBotStart: ChatControllerInitialAttachBotStart?
|
||||
public let botAppStart: ChatControllerInitialBotAppStart?
|
||||
public let updateTextInputState: ChatTextInputState?
|
||||
public let activateInput: ChatControllerActivateInput?
|
||||
public let keepStack: NavigateToChatKeepStack
|
||||
@ -463,7 +464,7 @@ public final class NavigateToChatControllerParams {
|
||||
public let setupController: (ChatController) -> Void
|
||||
public let completion: (ChatController) -> Void
|
||||
|
||||
public init(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: Location, chatLocationContextHolder: Atomic<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, attachBotStart: ChatControllerInitialAttachBotStart? = nil, updateTextInputState: ChatTextInputState? = nil, activateInput: ChatControllerActivateInput? = nil, keepStack: NavigateToChatKeepStack = .default, useExisting: Bool = true, useBackAnimation: Bool = false, purposefulAction: (() -> Void)? = nil, scrollToEndIfExists: Bool = false, activateMessageSearch: (ChatSearchDomain, String)? = nil, peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, reportReason: ReportReason? = nil, animated: Bool = true, options: NavigationAnimationOptions = [], parentGroupId: PeerGroupId? = nil, chatListFilter: Int32? = nil, chatNavigationStack: [ChatNavigationStackItem] = [], changeColors: Bool = false, setupController: @escaping (ChatController) -> Void = { _ in }, completion: @escaping (ChatController) -> Void = { _ in }) {
|
||||
public init(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: Location, chatLocationContextHolder: Atomic<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, attachBotStart: ChatControllerInitialAttachBotStart? = nil, botAppStart: ChatControllerInitialBotAppStart? = nil, updateTextInputState: ChatTextInputState? = nil, activateInput: ChatControllerActivateInput? = nil, keepStack: NavigateToChatKeepStack = .default, useExisting: Bool = true, useBackAnimation: Bool = false, purposefulAction: (() -> Void)? = nil, scrollToEndIfExists: Bool = false, activateMessageSearch: (ChatSearchDomain, String)? = nil, peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, reportReason: ReportReason? = nil, animated: Bool = true, options: NavigationAnimationOptions = [], parentGroupId: PeerGroupId? = nil, chatListFilter: Int32? = nil, chatNavigationStack: [ChatNavigationStackItem] = [], changeColors: Bool = false, setupController: @escaping (ChatController) -> Void = { _ in }, completion: @escaping (ChatController) -> Void = { _ in }) {
|
||||
self.navigationController = navigationController
|
||||
self.chatController = chatController
|
||||
self.chatLocationContextHolder = chatLocationContextHolder
|
||||
@ -472,6 +473,7 @@ public final class NavigateToChatControllerParams {
|
||||
self.subject = subject
|
||||
self.botStart = botStart
|
||||
self.attachBotStart = attachBotStart
|
||||
self.botAppStart = botAppStart
|
||||
self.updateTextInputState = updateTextInputState
|
||||
self.activateInput = activateInput
|
||||
self.keepStack = keepStack
|
||||
|
@ -208,12 +208,25 @@ public struct ChatControllerInitialAttachBotStart {
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatControllerInitialBotAppStart {
|
||||
public let botApp: BotApp
|
||||
public let payload: String?
|
||||
public let justInstalled: Bool
|
||||
|
||||
public init(botApp: BotApp, payload: String?, justInstalled: Bool) {
|
||||
self.botApp = botApp
|
||||
self.payload = payload
|
||||
self.justInstalled = justInstalled
|
||||
}
|
||||
}
|
||||
|
||||
public enum ChatControllerInteractionNavigateToPeer {
|
||||
case `default`
|
||||
case chat(textInputState: ChatTextInputState?, subject: ChatControllerSubject?, peekData: ChatPeekTimeout?)
|
||||
case info
|
||||
case withBotStartPayload(ChatControllerInitialBotStart)
|
||||
case withAttachBot(ChatControllerInitialAttachBotStart)
|
||||
case withBotApp(ChatControllerInitialBotAppStart)
|
||||
}
|
||||
|
||||
public struct ChatInterfaceForwardOptionsState: Codable, Equatable {
|
||||
|
@ -59,6 +59,13 @@ public enum ChatTranslationDisplayType {
|
||||
case translated
|
||||
}
|
||||
|
||||
public enum ChatOpenWebViewSource: Equatable {
|
||||
case generic
|
||||
case menu
|
||||
case inline(bot: EnginePeer)
|
||||
case webApp(botApp: BotApp)
|
||||
}
|
||||
|
||||
public final class ChatPanelInterfaceInteraction {
|
||||
public let setupReplyMessage: (MessageId?, @escaping (ContainedViewLayoutTransition) -> Void) -> Void
|
||||
public let setupEditMessage: (MessageId?, @escaping (ContainedViewLayoutTransition) -> Void) -> Void
|
||||
@ -148,7 +155,7 @@ public final class ChatPanelInterfaceInteraction {
|
||||
public let openSendAsPeer: (ASDisplayNode, ContextGesture?) -> Void
|
||||
public let presentChatRequestAdminInfo: () -> Void
|
||||
public let displayCopyProtectionTip: (ASDisplayNode, Bool) -> Void
|
||||
public let openWebView: (String, String, Bool, Bool) -> Void
|
||||
public let openWebView: (String, String, Bool, ChatOpenWebViewSource) -> Void
|
||||
public let updateShowWebView: ((Bool) -> Bool) -> Void
|
||||
public let insertText: (NSAttributedString) -> Void
|
||||
public let backwardsDeleteText: () -> Void
|
||||
@ -250,7 +257,7 @@ public final class ChatPanelInterfaceInteraction {
|
||||
openSendAsPeer: @escaping (ASDisplayNode, ContextGesture?) -> Void,
|
||||
presentChatRequestAdminInfo: @escaping () -> Void,
|
||||
displayCopyProtectionTip: @escaping (ASDisplayNode, Bool) -> Void,
|
||||
openWebView: @escaping (String, String, Bool, Bool) -> Void,
|
||||
openWebView: @escaping (String, String, Bool, ChatOpenWebViewSource) -> Void,
|
||||
updateShowWebView: @escaping ((Bool) -> Bool) -> Void,
|
||||
insertText: @escaping (NSAttributedString) -> Void,
|
||||
backwardsDeleteText: @escaping () -> Void,
|
||||
|
@ -2471,13 +2471,19 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
|
||||
var speedValue: String = strongSelf.presentationData.strings.PlaybackSpeed_Normal
|
||||
var speedIconText: String = "1x"
|
||||
var didSetSpeedValue = false
|
||||
for (text, iconText, speed) in strongSelf.speedList(strings: strongSelf.presentationData.strings) {
|
||||
if abs(speed - status.baseRate) < 0.01 {
|
||||
speedValue = text
|
||||
speedIconText = iconText
|
||||
didSetSpeedValue = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !didSetSpeedValue && status.baseRate != 1.0 {
|
||||
speedValue = String(format: "%.1fx", status.baseRate)
|
||||
speedIconText = speedValue
|
||||
}
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.PlaybackSpeed_Title, textLayout: .secondLineWithValue(speedValue), icon: { theme in
|
||||
return optionsRateImage(rate: speedIconText, isLarge: false, color: theme.contextMenu.primaryColor)
|
||||
@ -2625,7 +2631,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
}
|
||||
strongSelf.updatePlaybackRate(newValue)
|
||||
if finished {
|
||||
dismiss()
|
||||
//dismiss()
|
||||
}
|
||||
}), true))
|
||||
|
||||
|
@ -411,7 +411,7 @@ public struct LegacyAssetPickerEnqueueMessage {
|
||||
public var isFile: Bool
|
||||
}
|
||||
|
||||
public func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) -> Signal<[LegacyAssetPickerEnqueueMessage], Void> {
|
||||
public func legacyAssetPickerEnqueueMessages(context: AccountContext, account: Account, signals: [Any]) -> Signal<[LegacyAssetPickerEnqueueMessage], Void> {
|
||||
return Signal { subscriber in
|
||||
let disposable = SSignal.combineSignals(signals).start(next: { anyValues in
|
||||
var messages: [LegacyAssetPickerEnqueueMessage] = []
|
||||
|
@ -109,6 +109,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/ChatTimerScreen",
|
||||
"//submodules/AnimatedAvatarSetNode",
|
||||
"//submodules/TelegramUI/Components/StorageUsageScreen",
|
||||
"//submodules/FeaturedStickersScreen:FeaturedStickersScreen",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -11,10 +11,17 @@ import EmojiStatusComponent
|
||||
import ComponentFlow
|
||||
import AccountContext
|
||||
|
||||
public enum ItemListReactionArrowStyle {
|
||||
case arrow
|
||||
case none
|
||||
}
|
||||
|
||||
public class ItemListReactionItem: ListViewItem, ItemListItem {
|
||||
let context: AccountContext
|
||||
let presentationData: ItemListPresentationData
|
||||
let icon: UIImage?
|
||||
let title: String
|
||||
let arrowStyle: ItemListReactionArrowStyle
|
||||
let reaction: MessageReaction.Reaction
|
||||
let availableReactions: AvailableReactions?
|
||||
public let sectionId: ItemListSectionId
|
||||
@ -22,10 +29,12 @@ public class ItemListReactionItem: ListViewItem, ItemListItem {
|
||||
let action: (() -> Void)?
|
||||
public let tag: ItemListItemTag?
|
||||
|
||||
public init(context: AccountContext, presentationData: ItemListPresentationData, title: String, reaction: MessageReaction.Reaction, availableReactions: AvailableReactions?, sectionId: ItemListSectionId, style: ItemListStyle, action: (() -> Void)?, tag: ItemListItemTag? = nil) {
|
||||
public init(context: AccountContext, presentationData: ItemListPresentationData, icon: UIImage? = nil, title: String, arrowStyle: ItemListReactionArrowStyle = .none, reaction: MessageReaction.Reaction, availableReactions: AvailableReactions?, sectionId: ItemListSectionId, style: ItemListStyle, action: (() -> Void)?, tag: ItemListItemTag? = nil) {
|
||||
self.context = context
|
||||
self.presentationData = presentationData
|
||||
self.icon = icon
|
||||
self.title = title
|
||||
self.arrowStyle = arrowStyle
|
||||
self.reaction = reaction
|
||||
self.availableReactions = availableReactions
|
||||
self.sectionId = sectionId
|
||||
@ -84,7 +93,9 @@ public class ItemListReactionItemNode: ListViewItemNode, ItemListItemNode {
|
||||
private let highlightedBackgroundNode: ASDisplayNode
|
||||
private let maskNode: ASImageNode
|
||||
|
||||
let iconNode: ASImageNode
|
||||
let titleNode: TextNode
|
||||
let arrowNode: ASImageNode
|
||||
let iconView: ComponentHostView<Empty>
|
||||
|
||||
private let activateArea: AccessibilityAreaNode
|
||||
@ -119,11 +130,20 @@ public class ItemListReactionItemNode: ListViewItemNode, ItemListItemNode {
|
||||
self.bottomStripeNode = ASDisplayNode()
|
||||
self.bottomStripeNode.isLayerBacked = true
|
||||
|
||||
self.iconNode = ASImageNode()
|
||||
self.iconNode.isLayerBacked = true
|
||||
self.iconNode.displaysAsynchronously = false
|
||||
|
||||
self.titleNode = TextNode()
|
||||
self.titleNode.isUserInteractionEnabled = false
|
||||
|
||||
self.iconView = ComponentHostView<Empty>()
|
||||
|
||||
self.arrowNode = ASImageNode()
|
||||
self.arrowNode.displayWithoutProcessing = true
|
||||
self.arrowNode.displaysAsynchronously = false
|
||||
self.arrowNode.isLayerBacked = true
|
||||
|
||||
self.highlightedBackgroundNode = ASDisplayNode()
|
||||
self.highlightedBackgroundNode.isLayerBacked = true
|
||||
|
||||
@ -133,6 +153,7 @@ public class ItemListReactionItemNode: ListViewItemNode, ItemListItemNode {
|
||||
|
||||
self.addSubnode(self.titleNode)
|
||||
self.view.addSubview(self.iconView)
|
||||
self.addSubnode(self.arrowNode)
|
||||
|
||||
self.addSubnode(self.activateArea)
|
||||
}
|
||||
@ -157,10 +178,28 @@ public class ItemListReactionItemNode: ListViewItemNode, ItemListItemNode {
|
||||
let itemBackgroundColor: UIColor
|
||||
let itemSeparatorColor: UIColor
|
||||
|
||||
let leftInset = 16.0 + params.leftInset
|
||||
var updatedTheme: PresentationTheme?
|
||||
var updateArrowImage: UIImage?
|
||||
if currentItem?.presentationData.theme !== item.presentationData.theme {
|
||||
updatedTheme = item.presentationData.theme
|
||||
updateArrowImage = PresentationResourcesItemList.disclosureArrowImage(item.presentationData.theme)
|
||||
}
|
||||
|
||||
var updateIcon = false
|
||||
if currentItem?.icon != item.icon {
|
||||
updateIcon = true
|
||||
}
|
||||
|
||||
var leftInset = 16.0 + params.leftInset
|
||||
if item.icon != nil {
|
||||
leftInset += 43.0
|
||||
}
|
||||
|
||||
var additionalTextRightInset: CGFloat = 0.0
|
||||
additionalTextRightInset += 44.0
|
||||
if item.arrowStyle == .arrow {
|
||||
additionalTextRightInset += 24.0
|
||||
}
|
||||
|
||||
let titleColor: UIColor = item.presentationData.theme.list.itemPrimaryTextColor
|
||||
|
||||
@ -197,11 +236,30 @@ public class ItemListReactionItemNode: ListViewItemNode, ItemListItemNode {
|
||||
|
||||
strongSelf.activateArea.accessibilityTraits = []
|
||||
|
||||
if currentItem?.presentationData.theme !== item.presentationData.theme {
|
||||
if let icon = item.icon {
|
||||
if strongSelf.iconNode.supernode == nil {
|
||||
strongSelf.addSubnode(strongSelf.iconNode)
|
||||
}
|
||||
if updateIcon {
|
||||
strongSelf.iconNode.image = icon
|
||||
}
|
||||
let iconY = floor((layout.contentSize.height - icon.size.height) / 2.0)
|
||||
strongSelf.iconNode.frame = CGRect(origin: CGPoint(x: params.leftInset + floor((leftInset - params.leftInset - icon.size.width) / 2.0), y: iconY), size: icon.size)
|
||||
} else if strongSelf.iconNode.supernode != nil {
|
||||
strongSelf.iconNode.image = nil
|
||||
strongSelf.iconNode.removeFromSupernode()
|
||||
}
|
||||
|
||||
if let _ = updatedTheme {
|
||||
strongSelf.topStripeNode.backgroundColor = itemSeparatorColor
|
||||
strongSelf.bottomStripeNode.backgroundColor = itemSeparatorColor
|
||||
strongSelf.backgroundNode.backgroundColor = itemBackgroundColor
|
||||
strongSelf.highlightedBackgroundNode.backgroundColor = item.presentationData.theme.list.itemHighlightedBackgroundColor
|
||||
|
||||
}
|
||||
|
||||
if let updateArrowImage = updateArrowImage {
|
||||
strongSelf.arrowNode.image = updateArrowImage
|
||||
}
|
||||
|
||||
let _ = titleApply()
|
||||
@ -282,6 +340,17 @@ public class ItemListReactionItemNode: ListViewItemNode, ItemListItemNode {
|
||||
animationContent = .customEmoji(fileId: fileId)
|
||||
}
|
||||
|
||||
|
||||
var rightInset: CGFloat = 0.0
|
||||
if let arrowImage = strongSelf.arrowNode.image, item.arrowStyle == .arrow {
|
||||
let arrowRightOffset: CGFloat = 7.0
|
||||
strongSelf.arrowNode.frame = CGRect(origin: CGPoint(x: params.width - params.rightInset - arrowRightOffset - arrowImage.size.width, y: floorToScreenPixels((height - arrowImage.size.height) / 2.0)), size: arrowImage.size)
|
||||
rightInset += arrowRightOffset + arrowImage.size.width
|
||||
strongSelf.arrowNode.isHidden = false
|
||||
} else {
|
||||
strongSelf.arrowNode.isHidden = true
|
||||
}
|
||||
|
||||
if let animationContent = animationContent {
|
||||
let iconBoundingSize = CGSize(width: 28.0, height: 28.0)
|
||||
let iconOffsetX: CGFloat = 0.0
|
||||
@ -299,12 +368,9 @@ public class ItemListReactionItemNode: ListViewItemNode, ItemListItemNode {
|
||||
containerSize: iconBoundingSize
|
||||
)
|
||||
strongSelf.iconView.isUserInteractionEnabled = false
|
||||
strongSelf.iconView.frame = CGRect(origin: CGPoint(x: params.width - params.rightInset - 7.0 - iconSize.width + iconOffsetX, y: floorToScreenPixels((height - iconSize.height) / 2.0)), size: iconSize)
|
||||
strongSelf.iconView.frame = CGRect(origin: CGPoint(x: params.width - params.rightInset - 7.0 - iconSize.width + iconOffsetX - rightInset, y: floorToScreenPixels((height - iconSize.height) / 2.0)), size: iconSize)
|
||||
}
|
||||
|
||||
/*if let arrowImage = strongSelf.arrowNode.image {
|
||||
strongSelf.arrowNode.frame = CGRect(origin: CGPoint(x: params.width - params.rightInset - 7.0 - arrowImage.size.width, y: floorToScreenPixels((height - arrowImage.size.height) / 2.0)), size: arrowImage.size)
|
||||
}*/
|
||||
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: height + UIScreenPixel))
|
||||
}
|
||||
})
|
||||
|
@ -17,6 +17,7 @@ import UndoUI
|
||||
import ShareController
|
||||
import WebPBinding
|
||||
import ReactionImageComponent
|
||||
import FeaturedStickersScreen
|
||||
|
||||
private final class InstalledStickerPacksControllerArguments {
|
||||
let context: AccountContext
|
||||
@ -34,10 +35,11 @@ private final class InstalledStickerPacksControllerArguments {
|
||||
let toggleAnimatedStickers: (Bool) -> Void
|
||||
let toggleSuggestAnimatedEmoji: (Bool) -> Void
|
||||
let togglePackSelected: (ItemCollectionId) -> Void
|
||||
let expandTrendingPacks: () -> Void
|
||||
let toggleLargeEmoji: (Bool) -> Void
|
||||
let toggleDynamicPackOrder: (Bool) -> Void
|
||||
let addPack: (StickerPackCollectionInfo) -> Void
|
||||
|
||||
init(context: AccountContext, openStickerPack: @escaping (StickerPackCollectionInfo) -> Void, setPackIdWithRevealedOptions: @escaping (ItemCollectionId?, ItemCollectionId?) -> Void, removePack: @escaping (ArchivedStickerPackItem) -> Void, openStickersBot: @escaping () -> Void, openMasks: @escaping () -> Void, openEmoji: @escaping () -> Void, openQuickReaction: @escaping () -> Void, openFeatured: @escaping () -> Void, openArchived: @escaping ([ArchivedStickerPackItem]?) -> Void, openSuggestOptions: @escaping () -> Void, toggleAnimatedStickers: @escaping (Bool) -> Void, toggleSuggestAnimatedEmoji: @escaping (Bool) -> Void, togglePackSelected: @escaping (ItemCollectionId) -> Void, expandTrendingPacks: @escaping () -> Void, addPack: @escaping (StickerPackCollectionInfo) -> Void) {
|
||||
init(context: AccountContext, openStickerPack: @escaping (StickerPackCollectionInfo) -> Void, setPackIdWithRevealedOptions: @escaping (ItemCollectionId?, ItemCollectionId?) -> Void, removePack: @escaping (ArchivedStickerPackItem) -> Void, openStickersBot: @escaping () -> Void, openMasks: @escaping () -> Void, openEmoji: @escaping () -> Void, openQuickReaction: @escaping () -> Void, openFeatured: @escaping () -> Void, openArchived: @escaping ([ArchivedStickerPackItem]?) -> Void, openSuggestOptions: @escaping () -> Void, toggleAnimatedStickers: @escaping (Bool) -> Void, toggleSuggestAnimatedEmoji: @escaping (Bool) -> Void, togglePackSelected: @escaping (ItemCollectionId) -> Void, toggleLargeEmoji: @escaping (Bool) -> Void, toggleDynamicPackOrder: @escaping (Bool) -> Void, addPack: @escaping (StickerPackCollectionInfo) -> Void) {
|
||||
self.context = context
|
||||
self.openStickerPack = openStickerPack
|
||||
self.setPackIdWithRevealedOptions = setPackIdWithRevealedOptions
|
||||
@ -52,14 +54,16 @@ private final class InstalledStickerPacksControllerArguments {
|
||||
self.toggleAnimatedStickers = toggleAnimatedStickers
|
||||
self.toggleSuggestAnimatedEmoji = toggleSuggestAnimatedEmoji
|
||||
self.togglePackSelected = togglePackSelected
|
||||
self.expandTrendingPacks = expandTrendingPacks
|
||||
self.toggleLargeEmoji = toggleLargeEmoji
|
||||
self.toggleDynamicPackOrder = toggleDynamicPackOrder
|
||||
self.addPack = addPack
|
||||
}
|
||||
}
|
||||
|
||||
private enum InstalledStickerPacksSection: Int32 {
|
||||
case service
|
||||
case trending
|
||||
case settings
|
||||
case categories
|
||||
case order
|
||||
case stickers
|
||||
}
|
||||
|
||||
@ -78,33 +82,34 @@ public enum InstalledStickerPacksEntryTag: ItemListItemTag {
|
||||
|
||||
private enum InstalledStickerPacksEntryId: Hashable {
|
||||
case index(Int32)
|
||||
case trendingPack(ItemCollectionId)
|
||||
case pack(ItemCollectionId)
|
||||
}
|
||||
|
||||
private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
|
||||
case suggestOptions(PresentationTheme, String, String)
|
||||
case largeEmoji(PresentationTheme, String, Bool)
|
||||
case animatedStickers(PresentationTheme, String, Bool)
|
||||
case animatedStickersInfo(PresentationTheme, String)
|
||||
case trending(PresentationTheme, String, Int32)
|
||||
case archived(PresentationTheme, String, Int32, [ArchivedStickerPackItem]?)
|
||||
case masks(PresentationTheme, String)
|
||||
case emoji(PresentationTheme, String)
|
||||
case emoji(PresentationTheme, String, Int32)
|
||||
case quickReaction(String, MessageReaction.Reaction, AvailableReactions)
|
||||
case animatedStickers(PresentationTheme, String, Bool)
|
||||
case animatedStickersInfo(PresentationTheme, String)
|
||||
case packOrder(PresentationTheme, String, Bool)
|
||||
case packOrderInfo(PresentationTheme, String)
|
||||
case suggestAnimatedEmoji(String, Bool)
|
||||
case trendingPacksTitle(PresentationTheme, String)
|
||||
case trendingPack(Int32, PresentationTheme, PresentationStrings, StickerPackCollectionInfo, StickerPackItem?, String, Bool, Bool, Bool)
|
||||
case trendingExpand(PresentationTheme, String)
|
||||
case packsTitle(PresentationTheme, String)
|
||||
case pack(Int32, PresentationTheme, PresentationStrings, StickerPackCollectionInfo, StickerPackItem?, String, Bool, Bool, ItemListStickerPackItemEditing, Bool?)
|
||||
case packsInfo(PresentationTheme, String)
|
||||
|
||||
var section: ItemListSectionId {
|
||||
switch self {
|
||||
case .suggestOptions, .trending, .masks, .emoji, .quickReaction, .archived, .animatedStickers, .animatedStickersInfo, .suggestAnimatedEmoji:
|
||||
return InstalledStickerPacksSection.service.rawValue
|
||||
case .trendingPacksTitle, .trendingPack, .trendingExpand:
|
||||
return InstalledStickerPacksSection.trending.rawValue
|
||||
case .suggestOptions, .largeEmoji, .animatedStickers, .animatedStickersInfo, .suggestAnimatedEmoji:
|
||||
return InstalledStickerPacksSection.settings.rawValue
|
||||
case .trending, .masks, .emoji, .quickReaction, .archived:
|
||||
return InstalledStickerPacksSection.categories.rawValue
|
||||
case .packOrder, .packOrderInfo:
|
||||
return InstalledStickerPacksSection.order.rawValue
|
||||
case .packsTitle, .pack, .packsInfo:
|
||||
return InstalledStickerPacksSection.stickers.rawValue
|
||||
}
|
||||
@ -114,34 +119,34 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
|
||||
switch self {
|
||||
case .suggestOptions:
|
||||
return .index(0)
|
||||
case .trending:
|
||||
case .largeEmoji:
|
||||
return .index(1)
|
||||
case .archived:
|
||||
return .index(2)
|
||||
case .masks:
|
||||
return .index(3)
|
||||
case .emoji:
|
||||
return .index(4)
|
||||
case .quickReaction:
|
||||
return .index(5)
|
||||
case .animatedStickers:
|
||||
return .index(6)
|
||||
return .index(2)
|
||||
case .animatedStickersInfo:
|
||||
return .index(3)
|
||||
case .trending:
|
||||
return .index(4)
|
||||
case .archived:
|
||||
return .index(5)
|
||||
case .emoji:
|
||||
return .index(6)
|
||||
case .masks:
|
||||
return .index(7)
|
||||
case .suggestAnimatedEmoji:
|
||||
case .quickReaction:
|
||||
return .index(8)
|
||||
case .trendingPacksTitle:
|
||||
case .suggestAnimatedEmoji:
|
||||
return .index(9)
|
||||
case let .trendingPack(_, _, _, info, _, _, _, _, _):
|
||||
return .trendingPack(info.id)
|
||||
case .trendingExpand:
|
||||
case .packOrder:
|
||||
return .index(10)
|
||||
case .packsTitle:
|
||||
case .packOrderInfo:
|
||||
return .index(11)
|
||||
case .packsTitle:
|
||||
return .index(12)
|
||||
case let .pack(_, _, _, info, _, _, _, _, _, _):
|
||||
return .pack(info.id)
|
||||
case .packsInfo:
|
||||
return .index(12)
|
||||
return .index(13)
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,6 +158,12 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .largeEmoji(lhsTheme, lhsText, lhsValue):
|
||||
if case let .largeEmoji(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .trending(lhsTheme, lhsText, lhsCount):
|
||||
if case let .trending(rhsTheme, rhsText, rhsCount) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsCount == rhsCount {
|
||||
return true
|
||||
@ -165,8 +176,8 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .emoji(lhsTheme, lhsCount):
|
||||
if case let .emoji(rhsTheme, rhsCount) = rhs, lhsTheme === rhsTheme, lhsCount == rhsCount {
|
||||
case let .emoji(lhsTheme, lhsText, lhsCount):
|
||||
if case let .emoji(rhsTheme, rhsText, rhsCount) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsCount == rhsCount {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -195,63 +206,30 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .packOrder(lhsTheme, lhsText, lhsValue):
|
||||
if case let .packOrder(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .packOrderInfo(lhsTheme, lhsText):
|
||||
if case let .packOrderInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .suggestAnimatedEmoji(lhsText, lhsValue):
|
||||
if case let .suggestAnimatedEmoji(rhsText, rhsValue) = rhs, lhsValue == rhsValue, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .trendingPacksTitle(lhsTheme, lhsText):
|
||||
if case let .trendingPacksTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .packsTitle(lhsTheme, lhsText):
|
||||
if case let .packsTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .trendingPack(lhsIndex, lhsTheme, lhsStrings, lhsInfo, lhsTopItem, lhsCount, lhsAnimatedStickers, lhsUnread, lhsInstalled):
|
||||
if case let .trendingPack(rhsIndex, rhsTheme, rhsStrings, rhsInfo, rhsTopItem, rhsCount, rhsAnimatedStickers, rhsUnread, rhsInstalled) = rhs {
|
||||
if lhsIndex != rhsIndex {
|
||||
return false
|
||||
}
|
||||
if lhsTheme !== rhsTheme {
|
||||
return false
|
||||
}
|
||||
if lhsStrings !== rhsStrings {
|
||||
return false
|
||||
}
|
||||
if lhsInfo != rhsInfo {
|
||||
return false
|
||||
}
|
||||
if lhsTopItem != rhsTopItem {
|
||||
return false
|
||||
}
|
||||
if lhsCount != rhsCount {
|
||||
return false
|
||||
}
|
||||
if lhsAnimatedStickers != rhsAnimatedStickers {
|
||||
return false
|
||||
}
|
||||
if lhsUnread != rhsUnread {
|
||||
return false
|
||||
}
|
||||
if lhsInstalled != rhsInstalled {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .trendingExpand(lhsTheme, lhsText):
|
||||
if case let .trendingExpand(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .pack(lhsIndex, lhsTheme, lhsStrings, lhsInfo, lhsTopItem, lhsCount, lhsAnimatedStickers, lhsEnabled, lhsEditing, lhsSelected):
|
||||
if case let .pack(rhsIndex, rhsTheme, rhsStrings, rhsInfo, rhsTopItem, rhsCount, rhsAnimatedStickers, rhsEnabled, rhsEditing, rhsSelected) = rhs {
|
||||
if lhsIndex != rhsIndex {
|
||||
@ -301,93 +279,91 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
|
||||
switch lhs {
|
||||
case .suggestOptions:
|
||||
switch rhs {
|
||||
case .suggestOptions:
|
||||
case .suggestOptions:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .trending:
|
||||
case .largeEmoji:
|
||||
switch rhs {
|
||||
case .suggestOptions, .trending:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .archived:
|
||||
switch rhs {
|
||||
case .suggestOptions, .trending, .archived:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .masks:
|
||||
switch rhs {
|
||||
case .suggestOptions, .trending, .archived, .masks:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .emoji:
|
||||
switch rhs {
|
||||
case .suggestOptions, .trending, .archived, .masks, .emoji:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .quickReaction:
|
||||
switch rhs {
|
||||
case .suggestOptions, .trending, .archived, .masks, .emoji, .quickReaction:
|
||||
case .suggestOptions, .largeEmoji:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .animatedStickers:
|
||||
switch rhs {
|
||||
case .suggestOptions, .trending, .archived, .masks, .emoji, .quickReaction, .animatedStickers:
|
||||
case .suggestOptions, .largeEmoji, .animatedStickers:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .animatedStickersInfo:
|
||||
switch rhs {
|
||||
case .suggestOptions, .trending, .archived, .masks, .emoji, .quickReaction, .animatedStickers, .animatedStickersInfo:
|
||||
case .suggestOptions, .largeEmoji, .animatedStickers, .animatedStickersInfo:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .trending:
|
||||
switch rhs {
|
||||
case .suggestOptions, .largeEmoji, .animatedStickers, .animatedStickersInfo, .trending:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .archived:
|
||||
switch rhs {
|
||||
case .suggestOptions, .largeEmoji, .animatedStickers, .animatedStickersInfo, .trending, .archived:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .masks:
|
||||
switch rhs {
|
||||
case .suggestOptions, .largeEmoji, .animatedStickers, .animatedStickersInfo, .trending, .archived, .masks:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .emoji:
|
||||
switch rhs {
|
||||
case .suggestOptions, .largeEmoji, .animatedStickers, .animatedStickersInfo, .trending, .archived, .masks, .emoji:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .quickReaction:
|
||||
switch rhs {
|
||||
case .suggestOptions, .largeEmoji, .animatedStickers, .animatedStickersInfo, .trending, .archived, .masks, .emoji, .quickReaction:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .packOrder:
|
||||
switch rhs {
|
||||
case .suggestOptions, .largeEmoji, .animatedStickers, .animatedStickersInfo, .trending, .archived, .masks, .emoji, .quickReaction, .packOrder:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .packOrderInfo:
|
||||
switch rhs {
|
||||
case .suggestOptions, .largeEmoji, .animatedStickers, .animatedStickersInfo, .trending, .archived, .masks, .emoji, .quickReaction, .packOrder, .packOrderInfo:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .suggestAnimatedEmoji:
|
||||
switch rhs {
|
||||
case .suggestOptions, .trending, .archived, .masks, .emoji, .quickReaction, .animatedStickers, .animatedStickersInfo, .suggestAnimatedEmoji:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .trendingPacksTitle:
|
||||
switch rhs {
|
||||
case .suggestOptions, .trending, .masks, .emoji, .quickReaction, .archived, .animatedStickers, .animatedStickersInfo, .suggestAnimatedEmoji, .trendingPacksTitle:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case let .trendingPack(lhsIndex, _, _, _, _, _, _, _, _):
|
||||
switch rhs {
|
||||
case let .trendingPack(rhsIndex, _, _, _, _, _, _, _, _):
|
||||
return lhsIndex < rhsIndex
|
||||
case .trendingExpand, .packsTitle, .pack, .packsInfo:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
case .trendingExpand:
|
||||
switch rhs {
|
||||
case .suggestOptions, .trending, .masks, .emoji, .quickReaction, .archived, .animatedStickers, .animatedStickersInfo, .suggestAnimatedEmoji, .trendingPacksTitle, .trendingPack, .trendingExpand:
|
||||
case .suggestOptions, .largeEmoji, .animatedStickers, .animatedStickersInfo, .trending, .archived, .masks, .emoji, .quickReaction, .packOrder, .packOrderInfo, .suggestAnimatedEmoji:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .packsTitle:
|
||||
switch rhs {
|
||||
case .suggestOptions, .trending, .masks, .emoji, .quickReaction, .archived, .animatedStickers, .animatedStickersInfo, .suggestAnimatedEmoji, .trendingPacksTitle, .trendingPack, .trendingExpand, .packsTitle:
|
||||
case .suggestOptions, .largeEmoji, .animatedStickers, .animatedStickersInfo, .trending, .masks, .emoji, .quickReaction, .archived, .packOrder, .packOrderInfo, .suggestAnimatedEmoji, .packsTitle:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
@ -418,25 +394,9 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
|
||||
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.openSuggestOptions()
|
||||
}, tag: InstalledStickerPacksEntryTag.suggestOptions)
|
||||
case let .trending(theme, text, count):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: count == 0 ? "" : "\(count)", labelStyle: .badge(theme.list.itemAccentColor), sectionId: self.section, style: .blocks, action: {
|
||||
arguments.openFeatured()
|
||||
})
|
||||
case let .masks(_, text):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: "", sectionId: self.section, style: .blocks, action: {
|
||||
arguments.openMasks()
|
||||
})
|
||||
case let .emoji(_, text):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: "", sectionId: self.section, style: .blocks, action: {
|
||||
arguments.openEmoji()
|
||||
})
|
||||
case let .quickReaction(title, reaction, availableReactions):
|
||||
return ItemListReactionItem(context: arguments.context, presentationData: presentationData, title: title, reaction: reaction, availableReactions: availableReactions, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.openQuickReaction()
|
||||
})
|
||||
case let .archived(_, text, count, archived):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: count == 0 ? "" : "\(count)", sectionId: self.section, style: .blocks, action: {
|
||||
arguments.openArchived(archived)
|
||||
case let .largeEmoji(_, text, value):
|
||||
return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||
arguments.toggleAnimatedStickers(value)
|
||||
})
|
||||
case let .animatedStickers(_, text, value):
|
||||
return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||
@ -444,25 +404,36 @@ private indirect enum InstalledStickerPacksEntry: ItemListNodeEntry {
|
||||
})
|
||||
case let .animatedStickersInfo(_, text):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
||||
case let .trending(theme, text, count):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, icon: UIImage(bundleImageName: "Settings/Menu/Trending")?.precomposed(), title: text, label: count == 0 ? "" : "\(count)", labelStyle: .badge(theme.list.itemAccentColor), sectionId: self.section, style: .blocks, action: {
|
||||
arguments.openFeatured()
|
||||
})
|
||||
case let .masks(_, text):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: "", sectionId: self.section, style: .blocks, action: {
|
||||
arguments.openMasks()
|
||||
})
|
||||
case let .emoji(_, text, count):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, icon: UIImage(bundleImageName: "Settings/Menu/Emoji")?.precomposed(), title: text, label: count == 0 ? "" : "\(count)", sectionId: self.section, style: .blocks, action: {
|
||||
arguments.openEmoji()
|
||||
})
|
||||
case let .quickReaction(title, reaction, availableReactions):
|
||||
return ItemListReactionItem(context: arguments.context, presentationData: presentationData, icon: UIImage(bundleImageName: "Settings/Menu/Reactions")?.precomposed(), title: title, arrowStyle: .arrow, reaction: reaction, availableReactions: availableReactions, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.openQuickReaction()
|
||||
})
|
||||
case let .archived(_, text, count, archived):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, icon: UIImage(bundleImageName: "Settings/Menu/Archived")?.precomposed(), title: text, label: count == 0 ? "" : "\(count)", sectionId: self.section, style: .blocks, action: {
|
||||
arguments.openArchived(archived)
|
||||
})
|
||||
case let .packOrder(_, text, value):
|
||||
return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||
arguments.toggleDynamicPackOrder(value)
|
||||
})
|
||||
case let .packOrderInfo(_, text):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
||||
case let .suggestAnimatedEmoji(text, value):
|
||||
return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||
arguments.toggleSuggestAnimatedEmoji(value)
|
||||
})
|
||||
case let .trendingPacksTitle(_, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .trendingPack(_, _, _, info, topItem, count, animatedStickers, unread, installed):
|
||||
return ItemListStickerPackItem(presentationData: presentationData, context: arguments.context, packInfo: info, itemCount: count, topItem: topItem, unread: unread, control: .installation(installed: installed), editing: ItemListStickerPackItemEditing(editable: false, editing: false, revealed: false, reorderable: false, selectable: false), enabled: true, playAnimatedStickers: animatedStickers, sectionId: self.section, action: {
|
||||
arguments.openStickerPack(info)
|
||||
}, setPackIdWithRevealedOptions: { _, _ in
|
||||
}, addPack: {
|
||||
arguments.addPack(info)
|
||||
}, removePack: {
|
||||
}, toggleSelected: {
|
||||
})
|
||||
case let .trendingExpand(theme, text):
|
||||
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.downArrowImage(theme), title: text, sectionId: self.section, editing: false, action: {
|
||||
arguments.expandTrendingPacks()
|
||||
})
|
||||
case let .packsTitle(_, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .pack(_, _, _, info, topItem, count, animatedStickers, enabled, editing, selected):
|
||||
@ -550,7 +521,7 @@ private func namespaceForMode(_ mode: InstalledStickerPacksControllerMode) -> It
|
||||
|
||||
private let maxTrendingPacksDisplayedLimit: Int32 = 3
|
||||
|
||||
private func installedStickerPacksControllerEntries(presentationData: PresentationData, state: InstalledStickerPacksControllerState, mode: InstalledStickerPacksControllerMode, view: CombinedView, temporaryPackOrder: [ItemCollectionId]?, featured: [FeaturedStickerPackItem], archived: [ArchivedStickerPackItem]?, stickerSettings: StickerSettings, quickReaction: MessageReaction.Reaction?, availableReactions: AvailableReactions?) -> [InstalledStickerPacksEntry] {
|
||||
private func installedStickerPacksControllerEntries(presentationData: PresentationData, state: InstalledStickerPacksControllerState, mode: InstalledStickerPacksControllerMode, view: CombinedView, temporaryPackOrder: [ItemCollectionId]?, featured: [FeaturedStickerPackItem], archived: [ArchivedStickerPackItem]?, stickerSettings: StickerSettings, quickReaction: MessageReaction.Reaction?, availableReactions: AvailableReactions?, emojiCount: Int32) -> [InstalledStickerPacksEntry] {
|
||||
var entries: [InstalledStickerPacksEntry] = []
|
||||
|
||||
var installedPacks = Set<ItemCollectionId>()
|
||||
@ -579,52 +550,28 @@ private func installedStickerPacksControllerEntries(presentationData: Presentati
|
||||
}
|
||||
entries.append(.suggestOptions(presentationData.theme, presentationData.strings.Stickers_SuggestStickers, suggestString))
|
||||
|
||||
entries.append(.largeEmoji(presentationData.theme, presentationData.strings.Appearance_LargeEmoji, presentationData.largeEmoji))
|
||||
|
||||
entries.append(.animatedStickers(presentationData.theme, presentationData.strings.StickerPacksSettings_AnimatedStickers, stickerSettings.loopAnimatedStickers))
|
||||
entries.append(.animatedStickersInfo(presentationData.theme, presentationData.strings.StickerPacksSettings_AnimatedStickersInfo))
|
||||
|
||||
if !featured.isEmpty {
|
||||
entries.append(.trending(presentationData.theme, presentationData.strings.StickerPacksSettings_TrendingStickers, Int32(featured.count)))
|
||||
}
|
||||
if let archived = archived, !archived.isEmpty {
|
||||
entries.append(.archived(presentationData.theme, presentationData.strings.StickerPacksSettings_ArchivedPacks, Int32(archived.count), archived))
|
||||
}
|
||||
entries.append(.masks(presentationData.theme, presentationData.strings.MaskStickerSettings_Title))
|
||||
|
||||
entries.append(.emoji(presentationData.theme, presentationData.strings.StickersList_EmojiItem))
|
||||
entries.append(.emoji(presentationData.theme, presentationData.strings.StickerPacksSettings_Emoji, emojiCount))
|
||||
|
||||
if let quickReaction = quickReaction, let availableReactions = availableReactions {
|
||||
entries.append(.quickReaction(presentationData.strings.Settings_QuickReactionSetup_NavigationTitle, quickReaction, availableReactions))
|
||||
}
|
||||
|
||||
entries.append(.animatedStickers(presentationData.theme, presentationData.strings.StickerPacksSettings_AnimatedStickers, stickerSettings.loopAnimatedStickers))
|
||||
entries.append(.animatedStickersInfo(presentationData.theme, presentationData.strings.StickerPacksSettings_AnimatedStickersInfo))
|
||||
entries.append(.packOrder(presentationData.theme, presentationData.strings.StickerPacksSettings_DynamicOrder, stickerSettings.dynamicPackOrder))
|
||||
entries.append(.packOrderInfo(presentationData.theme, presentationData.strings.StickerPacksSettings_DynamicOrderInfo))
|
||||
|
||||
if featured.count > 0 {
|
||||
entries.append(.trendingPacksTitle(presentationData.theme, presentationData.strings.StickerPacksSettings_FeaturedPacks.uppercased()))
|
||||
|
||||
var index: Int32 = 0
|
||||
var featuredPacks = featured
|
||||
var effectiveExpanded = state.trendingPacksExpanded
|
||||
if featuredPacks.count > maxTrendingPacksDisplayedLimit && !effectiveExpanded {
|
||||
featuredPacks = Array(featuredPacks.prefix(Int(maxTrendingPacksDisplayedLimit)))
|
||||
} else {
|
||||
effectiveExpanded = true
|
||||
}
|
||||
|
||||
for featuredPack in featuredPacks {
|
||||
let countTitle: String
|
||||
if featuredPack.info.id.namespace == Namespaces.ItemCollection.CloudEmojiPacks {
|
||||
countTitle = presentationData.strings.StickerPack_EmojiCount(featuredPack.info.count)
|
||||
} else if featuredPack.info.id.namespace == Namespaces.ItemCollection.CloudMaskPacks {
|
||||
countTitle = presentationData.strings.StickerPack_MaskCount(featuredPack.info.count)
|
||||
} else {
|
||||
countTitle = presentationData.strings.StickerPack_StickerCount(featuredPack.info.count)
|
||||
}
|
||||
|
||||
entries.append(.trendingPack(index, presentationData.theme, presentationData.strings, featuredPack.info, featuredPack.topItems.first, countTitle, stickerSettings.loopAnimatedStickers, featuredPack.unread, installedPacks.contains(featuredPack.info.id)))
|
||||
index += 1
|
||||
}
|
||||
|
||||
if !effectiveExpanded {
|
||||
entries.append(.trendingExpand(presentationData.theme, presentationData.strings.Stickers_ShowMore))
|
||||
}
|
||||
}
|
||||
|
||||
entries.append(.packsTitle(presentationData.theme, presentationData.strings.StickerPacksSettings_StickerPacksSection))
|
||||
entries.append(.packsTitle(presentationData.theme, presentationData.strings.StickerPacksSettings_MyStickers.uppercased()))
|
||||
case .masks:
|
||||
if let archived = archived, !archived.isEmpty {
|
||||
entries.append(.archived(presentationData.theme, presentationData.strings.StickerPacksSettings_ArchivedMasks, Int32(archived.count), archived))
|
||||
@ -825,7 +772,7 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
|
||||
context: context
|
||||
))
|
||||
}, openFeatured: {
|
||||
pushControllerImpl?(featuredStickerPacksController(context: context))
|
||||
pushControllerImpl?(FeaturedStickersScreen(context: context, highlightedPackId: nil))
|
||||
}, openArchived: { archived in
|
||||
let archivedMode: ArchivedStickerPacksControllerMode
|
||||
switch mode {
|
||||
@ -887,10 +834,14 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
|
||||
return state
|
||||
}
|
||||
}
|
||||
}, expandTrendingPacks: {
|
||||
updateState { state in
|
||||
return state.withUpdatedTrendingPacksExpanded(true)
|
||||
}
|
||||
}, toggleLargeEmoji: { value in
|
||||
let _ = updatePresentationThemeSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in
|
||||
return current.withUpdatedLargeEmoji(value)
|
||||
}).start()
|
||||
}, toggleDynamicPackOrder: { value in
|
||||
let _ = updateStickerSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in
|
||||
return current.withUpdatedDynamicPackOrder(value)
|
||||
}).start()
|
||||
}, addPack: { info in
|
||||
let _ = (context.engine.stickers.loadedStickerPack(reference: .id(id: info.id.id, accessHash: info.accessHash), forceActualized: false)
|
||||
|> mapToSignal { result -> Signal<Void, NoError> in
|
||||
@ -915,7 +866,8 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
|
||||
|
||||
let featured = Promise<[FeaturedStickerPackItem]>()
|
||||
let quickReaction: Signal<MessageReaction.Reaction?, NoError>
|
||||
|
||||
let emojiCount = Promise<Int32>()
|
||||
|
||||
switch mode {
|
||||
case .general, .modal:
|
||||
featured.set(context.account.viewTracker.featuredStickerPacks())
|
||||
@ -938,14 +890,24 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
|
||||
return reactionSettings.effectiveQuickReaction(hasPremium: hasPremium)
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
emojiCount.set(context.account.postbox.combinedView(keys: [.itemCollectionInfos(namespaces: [Namespaces.ItemCollection.CloudEmojiPacks])])
|
||||
|> map { view in
|
||||
if let info = view.views[.itemCollectionInfos(namespaces: [Namespaces.ItemCollection.CloudEmojiPacks])] as? ItemCollectionInfosView, let entries = info.entriesByNamespace[Namespaces.ItemCollection.CloudEmojiPacks] {
|
||||
return Int32(entries.count)
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
})
|
||||
case .masks:
|
||||
featured.set(.single([]))
|
||||
archivedPromise.set(.single(nil) |> then(context.engine.stickers.archivedStickerPacks(namespace: .masks) |> map(Optional.init)))
|
||||
quickReaction = .single(nil)
|
||||
emojiCount.set(.single(0))
|
||||
case .emoji:
|
||||
featured.set(.single([]))
|
||||
archivedPromise.set(.single(nil) |> then(context.engine.stickers.archivedStickerPacks(namespace: .emoji) |> map(Optional.init)))
|
||||
quickReaction = .single(nil)
|
||||
emojiCount.set(.single(0))
|
||||
}
|
||||
|
||||
var previousPackCount: Int?
|
||||
@ -956,10 +918,11 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
|
||||
combineLatest(queue: .mainQueue(), featured.get(), archivedPromise.get()),
|
||||
context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.stickerSettings]),
|
||||
quickReaction,
|
||||
context.engine.stickers.availableReactions()
|
||||
context.engine.stickers.availableReactions(),
|
||||
emojiCount.get()
|
||||
)
|
||||
|> deliverOnMainQueue
|
||||
|> map { presentationData, state, view, temporaryPackOrder, featuredAndArchived, sharedData, quickReaction, availableReactions -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
|> map { presentationData, state, view, temporaryPackOrder, featuredAndArchived, sharedData, quickReaction, availableReactions, emojiCount -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
var stickerSettings = StickerSettings.defaultSettings
|
||||
if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings]?.get(StickerSettings.self) {
|
||||
stickerSettings = value
|
||||
@ -1113,7 +1076,7 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
|
||||
|
||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
|
||||
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: installedStickerPacksControllerEntries(presentationData: presentationData, state: state, mode: mode, view: view, temporaryPackOrder: temporaryPackOrder, featured: featuredAndArchived.0, archived: featuredAndArchived.1, stickerSettings: stickerSettings, quickReaction: quickReaction, availableReactions: availableReactions), style: .blocks, ensureVisibleItemTag: focusOnItemTag, toolbarItem: toolbarItem, animateChanges: previous != nil && packCount != nil && (previous! != 0 && previous! >= packCount! - 10))
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: installedStickerPacksControllerEntries(presentationData: presentationData, state: state, mode: mode, view: view, temporaryPackOrder: temporaryPackOrder, featured: featuredAndArchived.0, archived: featuredAndArchived.1, stickerSettings: stickerSettings, quickReaction: quickReaction, availableReactions: availableReactions, emojiCount: emojiCount), style: .blocks, ensureVisibleItemTag: focusOnItemTag, toolbarItem: toolbarItem, animateChanges: previous != nil && packCount != nil && (previous! != 0 && previous! >= packCount! - 10))
|
||||
return (controllerState, (listState, arguments))
|
||||
}
|
||||
|> afterDisposed {
|
||||
@ -1124,26 +1087,7 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
|
||||
if case .modal = mode {
|
||||
controller.navigationPresentation = .modal
|
||||
}
|
||||
|
||||
var alreadyReadIds = Set<ItemCollectionId>()
|
||||
controller.visibleEntriesUpdated = { entries in
|
||||
var unreadIds: [ItemCollectionId] = []
|
||||
for entry in entries {
|
||||
if let entry = entry as? InstalledStickerPacksEntry {
|
||||
if case let .trendingPack(_, _, _, info, _, _, _, unread, _) = entry {
|
||||
if unread && !alreadyReadIds.contains(info.id) {
|
||||
unreadIds.append(info.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !unreadIds.isEmpty {
|
||||
alreadyReadIds.formUnion(Set(unreadIds))
|
||||
|
||||
let _ = context.engine.stickers.markFeaturedStickerPacksAsSeenInteractively(ids: unreadIds).start()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
controller.setReorderEntry({ (fromIndex: Int, toIndex: Int, entries: [InstalledStickerPacksEntry]) -> Signal<Bool, NoError> in
|
||||
let fromEntry = entries[fromIndex]
|
||||
guard case let .pack(_, _, _, fromPackInfo, _, _, _, _, _, _) = fromEntry else {
|
||||
@ -1234,6 +1178,23 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
temporaryPackOrder.set(.single(nil))
|
||||
})
|
||||
|
||||
let _ = (context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.stickerSettings])
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { sharedData in
|
||||
var stickerSettings = StickerSettings.defaultSettings
|
||||
if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings]?.get(StickerSettings.self) {
|
||||
stickerSettings = value
|
||||
}
|
||||
|
||||
if stickerSettings.dynamicPackOrder {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_reorder", scale: 0.05, colors: [:], title: presentationData.strings.StickerPacksSettings_DynamicOrderOff, text: presentationData.strings.StickerPacksSettings_DynamicOrderOffInfo, customUndoText: nil), elevatedLayout: false, animateInAsReplacement: false, action: { action in
|
||||
return false }), nil)
|
||||
|
||||
arguments.toggleDynamicPackOrder(false)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
presentControllerImpl = { [weak controller] c, p in
|
||||
|
@ -513,7 +513,7 @@ final class ThemeGridSearchContentNode: SearchDisplayControllerContentNode {
|
||||
nextOffset = newNextOffset
|
||||
}
|
||||
}
|
||||
let merged = ChatContextResultCollection(botId: collection.botId, peerId: collection.peerId, query: collection.query, geoPoint: collection.geoPoint, queryId: nextResults?.queryId ?? collection.queryId, nextOffset: nextOffset ?? "", presentation: collection.presentation, switchPeer: collection.switchPeer, results: results, cacheTimeout: collection.cacheTimeout)
|
||||
let merged = ChatContextResultCollection(botId: collection.botId, peerId: collection.peerId, query: collection.query, geoPoint: collection.geoPoint, queryId: nextResults?.queryId ?? collection.queryId, nextOffset: nextOffset ?? "", presentation: collection.presentation, switchPeer: collection.switchPeer, webView: collection.webView, results: results, cacheTimeout: collection.cacheTimeout)
|
||||
return (merged, nextOffset)
|
||||
}
|
||||
|> mapToSignal { newCollection, nextOffset -> Signal<([ThemeGridSearchEntry], Bool)?, NoError> in
|
||||
|
@ -753,7 +753,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-651419003] = { return Api.SendMessageAction.parse_speakingInGroupCallAction($0) }
|
||||
dict[-1239335713] = { return Api.ShippingOption.parse_shippingOption($0) }
|
||||
dict[-2010155333] = { return Api.SimpleWebViewResult.parse_simpleWebViewResultUrl($0) }
|
||||
dict[981691896] = { return Api.SponsoredMessage.parse_sponsoredMessage($0) }
|
||||
dict[-64636888] = { return Api.SponsoredMessage.parse_sponsoredMessage($0) }
|
||||
dict[-884757282] = { return Api.StatsAbsValueAndPrev.parse_statsAbsValueAndPrev($0) }
|
||||
dict[-1237848657] = { return Api.StatsDateRangeDays.parse_statsDateRangeDays($0) }
|
||||
dict[-1901828938] = { return Api.StatsGraph.parse_statsGraph($0) }
|
||||
|
@ -434,13 +434,13 @@ public extension Api {
|
||||
}
|
||||
public extension Api {
|
||||
indirect enum SponsoredMessage: TypeConstructorDescription {
|
||||
case sponsoredMessage(flags: Int32, randomId: Buffer, fromId: Api.Peer?, chatInvite: Api.ChatInvite?, chatInviteHash: String?, channelPost: Int32?, startParam: String?, message: String, entities: [Api.MessageEntity]?)
|
||||
case sponsoredMessage(flags: Int32, randomId: Buffer, fromId: Api.Peer?, chatInvite: Api.ChatInvite?, chatInviteHash: String?, channelPost: Int32?, startParam: String?, message: String, entities: [Api.MessageEntity]?, sponsorInfo: String?, additionalInfo: String?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .sponsoredMessage(let flags, let randomId, let fromId, let chatInvite, let chatInviteHash, let channelPost, let startParam, let message, let entities):
|
||||
case .sponsoredMessage(let flags, let randomId, let fromId, let chatInvite, let chatInviteHash, let channelPost, let startParam, let message, let entities, let sponsorInfo, let additionalInfo):
|
||||
if boxed {
|
||||
buffer.appendInt32(981691896)
|
||||
buffer.appendInt32(-64636888)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeBytes(randomId, buffer: buffer, boxed: false)
|
||||
@ -455,14 +455,16 @@ public extension Api {
|
||||
for item in entities! {
|
||||
item.serialize(buffer, true)
|
||||
}}
|
||||
if Int(flags) & Int(1 << 7) != 0 {serializeString(sponsorInfo!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 8) != 0 {serializeString(additionalInfo!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .sponsoredMessage(let flags, let randomId, let fromId, let chatInvite, let chatInviteHash, let channelPost, let startParam, let message, let entities):
|
||||
return ("sponsoredMessage", [("flags", flags as Any), ("randomId", randomId as Any), ("fromId", fromId as Any), ("chatInvite", chatInvite as Any), ("chatInviteHash", chatInviteHash as Any), ("channelPost", channelPost as Any), ("startParam", startParam as Any), ("message", message as Any), ("entities", entities as Any)])
|
||||
case .sponsoredMessage(let flags, let randomId, let fromId, let chatInvite, let chatInviteHash, let channelPost, let startParam, let message, let entities, let sponsorInfo, let additionalInfo):
|
||||
return ("sponsoredMessage", [("flags", flags as Any), ("randomId", randomId as Any), ("fromId", fromId as Any), ("chatInvite", chatInvite as Any), ("chatInviteHash", chatInviteHash as Any), ("channelPost", channelPost as Any), ("startParam", startParam as Any), ("message", message as Any), ("entities", entities as Any), ("sponsorInfo", sponsorInfo as Any), ("additionalInfo", additionalInfo as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -491,6 +493,10 @@ public extension Api {
|
||||
if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() {
|
||||
_9 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
|
||||
} }
|
||||
var _10: String?
|
||||
if Int(_1!) & Int(1 << 7) != 0 {_10 = parseString(reader) }
|
||||
var _11: String?
|
||||
if Int(_1!) & Int(1 << 8) != 0 {_11 = parseString(reader) }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = (Int(_1!) & Int(1 << 3) == 0) || _3 != nil
|
||||
@ -500,8 +506,10 @@ public extension Api {
|
||||
let _c7 = (Int(_1!) & Int(1 << 0) == 0) || _7 != nil
|
||||
let _c8 = _8 != nil
|
||||
let _c9 = (Int(_1!) & Int(1 << 1) == 0) || _9 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 {
|
||||
return Api.SponsoredMessage.sponsoredMessage(flags: _1!, randomId: _2!, fromId: _3, chatInvite: _4, chatInviteHash: _5, channelPost: _6, startParam: _7, message: _8!, entities: _9)
|
||||
let _c10 = (Int(_1!) & Int(1 << 7) == 0) || _10 != nil
|
||||
let _c11 = (Int(_1!) & Int(1 << 8) == 0) || _11 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 {
|
||||
return Api.SponsoredMessage.sponsoredMessage(flags: _1!, randomId: _2!, fromId: _3, chatInvite: _4, chatInviteHash: _5, channelPost: _6, startParam: _7, message: _8!, entities: _9, sponsorInfo: _10, additionalInfo: _11)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
@ -565,8 +565,8 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
|
||||
dismissImpl?()
|
||||
})
|
||||
let contextController = ContextController(account: self.context.account, presentationData: self.context.sharedContext.currentPresentationData.with { $0 }, source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceNode: self.rateButton.referenceNode, shouldBeDismissed: self.dismissedPromise.get())), items: items |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
|
||||
dismissImpl = { [weak contextController] in
|
||||
contextController?.dismiss()
|
||||
dismissImpl = {
|
||||
//contextController?.dismiss()
|
||||
}
|
||||
self.presentInGlobalOverlay?(contextController)
|
||||
}
|
||||
|
@ -352,6 +352,15 @@ public struct ChatContextResultSwitchPeer: Equatable, Codable {
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatContextResultWebView: Equatable, Codable {
|
||||
public let text: String
|
||||
public let url: String
|
||||
|
||||
public static func ==(lhs: ChatContextResultWebView, rhs: ChatContextResultWebView) -> Bool {
|
||||
return lhs.text == rhs.text && lhs.url == rhs.url
|
||||
}
|
||||
}
|
||||
|
||||
public final class ChatContextResultCollection: Equatable, Codable {
|
||||
public struct GeoPoint: Equatable, Codable {
|
||||
public let latitude: Double
|
||||
@ -371,10 +380,11 @@ public final class ChatContextResultCollection: Equatable, Codable {
|
||||
public let nextOffset: String?
|
||||
public let presentation: ChatContextResultCollectionPresentation
|
||||
public let switchPeer: ChatContextResultSwitchPeer?
|
||||
public let webView: ChatContextResultWebView?
|
||||
public let results: [ChatContextResult]
|
||||
public let cacheTimeout: Int32
|
||||
|
||||
public init(botId: PeerId, peerId: PeerId, query: String, geoPoint: ChatContextResultCollection.GeoPoint?, queryId: Int64, nextOffset: String?, presentation: ChatContextResultCollectionPresentation, switchPeer: ChatContextResultSwitchPeer?, results: [ChatContextResult], cacheTimeout: Int32) {
|
||||
public init(botId: PeerId, peerId: PeerId, query: String, geoPoint: ChatContextResultCollection.GeoPoint?, queryId: Int64, nextOffset: String?, presentation: ChatContextResultCollectionPresentation, switchPeer: ChatContextResultSwitchPeer?, webView: ChatContextResultWebView?, results: [ChatContextResult], cacheTimeout: Int32) {
|
||||
self.botId = botId
|
||||
self.peerId = peerId
|
||||
self.query = query
|
||||
@ -383,6 +393,7 @@ public final class ChatContextResultCollection: Equatable, Codable {
|
||||
self.nextOffset = nextOffset
|
||||
self.presentation = presentation
|
||||
self.switchPeer = switchPeer
|
||||
self.webView = webView
|
||||
self.results = results
|
||||
self.cacheTimeout = cacheTimeout
|
||||
}
|
||||
@ -412,6 +423,9 @@ public final class ChatContextResultCollection: Equatable, Codable {
|
||||
if lhs.switchPeer != rhs.switchPeer {
|
||||
return false
|
||||
}
|
||||
if lhs.webView != rhs.webView {
|
||||
return false
|
||||
}
|
||||
if lhs.results != rhs.results {
|
||||
return false
|
||||
}
|
||||
@ -511,14 +525,27 @@ extension ChatContextResultSwitchPeer {
|
||||
}
|
||||
}
|
||||
|
||||
extension ChatContextResultWebView {
|
||||
init(apiSwitchWebView: Api.InlineBotWebView) {
|
||||
switch apiSwitchWebView {
|
||||
case let .inlineBotWebView(text, url):
|
||||
self.init(text: text, url: url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ChatContextResultCollection {
|
||||
convenience init(apiResults: Api.messages.BotResults, botId: PeerId, peerId: PeerId, query: String, geoPoint: (Double, Double)?) {
|
||||
switch apiResults {
|
||||
case let .botResults(flags, queryId, nextOffset, switchPm, _, results, cacheTime, _):
|
||||
case let .botResults(flags, queryId, nextOffset, switchPm, switchWebView, results, cacheTime, _):
|
||||
var switchPeer: ChatContextResultSwitchPeer?
|
||||
if let switchPm = switchPm {
|
||||
switchPeer = ChatContextResultSwitchPeer(apiSwitchPeer: switchPm)
|
||||
}
|
||||
var webView: ChatContextResultWebView?
|
||||
if let switchWebView = switchWebView {
|
||||
webView = ChatContextResultWebView(apiSwitchWebView: switchWebView)
|
||||
}
|
||||
let parsedResults = results.map({ ChatContextResult(apiResult: $0, queryId: queryId) })
|
||||
/*.filter({ result in
|
||||
switch result {
|
||||
@ -531,7 +558,7 @@ extension ChatContextResultCollection {
|
||||
let mappedGeoPoint = geoPoint.flatMap { geoPoint -> ChatContextResultCollection.GeoPoint in
|
||||
return ChatContextResultCollection.GeoPoint(latitude: geoPoint.0, longitude: geoPoint.1)
|
||||
}
|
||||
self.init(botId: botId, peerId: peerId, query: query, geoPoint: mappedGeoPoint, queryId: queryId, nextOffset: nextOffset, presentation: (flags & (1 << 0) != 0) ? .media : .list, switchPeer: switchPeer, results: parsedResults, cacheTimeout: cacheTime)
|
||||
self.init(botId: botId, peerId: peerId, query: query, geoPoint: mappedGeoPoint, queryId: queryId, nextOffset: nextOffset, presentation: (flags & (1 << 0) != 0) ? .media : .list, switchPeer: switchPeer, webView: webView, results: parsedResults, cacheTimeout: cacheTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -560,7 +587,7 @@ public func requestContextResults(engine: TelegramEngine, botId: EnginePeer.Id,
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
collection = ChatContextResultCollection(botId: existingResults.botId, peerId: existingResults.peerId, query: existingResults.query, geoPoint: existingResults.geoPoint, queryId: results.queryId, nextOffset: results.nextOffset, presentation: existingResults.presentation, switchPeer: existingResults.switchPeer, results: newResults, cacheTimeout: existingResults.cacheTimeout)
|
||||
collection = ChatContextResultCollection(botId: existingResults.botId, peerId: existingResults.peerId, query: existingResults.query, geoPoint: existingResults.geoPoint, queryId: results.queryId, nextOffset: results.nextOffset, presentation: existingResults.presentation, switchPeer: existingResults.switchPeer, webView: existingResults.webView, results: newResults, cacheTimeout: existingResults.cacheTimeout)
|
||||
} else {
|
||||
collection = results
|
||||
updated = true
|
||||
|
@ -450,7 +450,9 @@ private class AdMessagesHistoryContextImpl {
|
||||
|
||||
for message in messages {
|
||||
switch message {
|
||||
case let .sponsoredMessage(flags, randomId, fromId, chatInvite, chatInviteHash, channelPost, startParam, message, entities):
|
||||
case let .sponsoredMessage(flags, randomId, fromId, chatInvite, chatInviteHash, channelPost, startParam, message, entities, sponsorInfo, additionalInfo):
|
||||
let _ = sponsorInfo
|
||||
let _ = additionalInfo
|
||||
var parsedEntities: [MessageTextEntity] = []
|
||||
if let entities = entities {
|
||||
parsedEntities = messageTextEntitiesFromApiEntities(entities)
|
||||
|
@ -467,8 +467,8 @@ func _internal_attachMenuBots(postbox: Postbox) -> Signal<[AttachMenuBot], NoErr
|
||||
public enum GetAttachMenuBotError {
|
||||
case generic
|
||||
}
|
||||
|
||||
public func _internal_getAttachMenuBot(postbox: Postbox, network: Network, botId: PeerId, cached: Bool) -> Signal<AttachMenuBot, GetAttachMenuBotError> {
|
||||
|
||||
func _internal_getAttachMenuBot(postbox: Postbox, network: Network, botId: PeerId, cached: Bool) -> Signal<AttachMenuBot, GetAttachMenuBotError> {
|
||||
return postbox.transaction { transaction -> Signal<AttachMenuBot, GetAttachMenuBotError> in
|
||||
if cached, let cachedBots = cachedAttachMenuBots(transaction: transaction)?.bots {
|
||||
if let bot = cachedBots.first(where: { $0.peerId == botId }), let peer = transaction.getPeer(bot.peerId) {
|
||||
@ -549,3 +549,183 @@ public func _internal_getAttachMenuBot(postbox: Postbox, network: Network, botId
|
||||
|> castError(GetAttachMenuBotError.self)
|
||||
|> switchToLatest
|
||||
}
|
||||
|
||||
public enum BotAppReference {
|
||||
case id(id: Int64, accessHash: Int64)
|
||||
case shortName(peerId: PeerId, shortName: String)
|
||||
}
|
||||
|
||||
public final class BotApp: Equatable, Codable {
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case accessHash
|
||||
case shortName
|
||||
case title
|
||||
case description
|
||||
case photo
|
||||
case document
|
||||
case hash
|
||||
case flags
|
||||
}
|
||||
|
||||
public struct Flags: OptionSet {
|
||||
public var rawValue: Int32
|
||||
|
||||
public init(rawValue: Int32) {
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
|
||||
public init() {
|
||||
self.rawValue = 0
|
||||
}
|
||||
|
||||
public static let notActivated = Flags(rawValue: 1 << 0)
|
||||
public static let requiresWriteAccess = Flags(rawValue: 1 << 1)
|
||||
}
|
||||
|
||||
public let id: Int64
|
||||
public let accessHash: Int64
|
||||
public let shortName: String
|
||||
public let title: String
|
||||
public let description: String
|
||||
public let photo: TelegramMediaImage?
|
||||
public let document: TelegramMediaFile?
|
||||
public let hash: Int64
|
||||
public let flags: Flags
|
||||
|
||||
public init(
|
||||
id: Int64,
|
||||
accessHash: Int64,
|
||||
shortName: String,
|
||||
title: String,
|
||||
description: String,
|
||||
photo: TelegramMediaImage?,
|
||||
document: TelegramMediaFile?,
|
||||
hash: Int64,
|
||||
flags: Flags
|
||||
) {
|
||||
self.id = id
|
||||
self.accessHash = accessHash
|
||||
self.shortName = shortName
|
||||
self.title = title
|
||||
self.description = description
|
||||
self.photo = photo
|
||||
self.document = document
|
||||
self.hash = hash
|
||||
self.flags = flags
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
self.id = try container.decode(Int64.self, forKey: .id)
|
||||
self.accessHash = try container.decode(Int64.self, forKey: .accessHash)
|
||||
self.shortName = try container.decode(String.self, forKey: .shortName)
|
||||
self.title = try container.decode(String.self, forKey: .title)
|
||||
self.description = try container.decode(String.self, forKey: .description)
|
||||
|
||||
if let data = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: .photo) {
|
||||
self.photo = TelegramMediaImage(decoder: PostboxDecoder(buffer: MemoryBuffer(data: data.data)))
|
||||
} else {
|
||||
self.photo = nil
|
||||
}
|
||||
|
||||
if let data = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: .document) {
|
||||
self.document = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: data.data)))
|
||||
} else {
|
||||
self.document = nil
|
||||
}
|
||||
|
||||
self.hash = try container.decode(Int64.self, forKey: .hash)
|
||||
self.flags = Flags(rawValue: try container.decode(Int32.self, forKey: .flags))
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
try container.encode(self.id, forKey: .id)
|
||||
try container.encode(self.accessHash, forKey: .accessHash)
|
||||
try container.encode(self.shortName, forKey: .shortName)
|
||||
try container.encode(self.title, forKey: .title)
|
||||
try container.encode(self.description, forKey: .description)
|
||||
try container.encodeIfPresent(self.photo, forKey: .photo)
|
||||
try container.encodeIfPresent(self.document, forKey: .document)
|
||||
try container.encode(self.hash, forKey: .hash)
|
||||
try container.encode(self.flags.rawValue, forKey: .flags)
|
||||
}
|
||||
|
||||
public static func ==(lhs: BotApp, rhs: BotApp) -> Bool {
|
||||
if lhs.id != rhs.id {
|
||||
return false
|
||||
}
|
||||
if lhs.accessHash != rhs.accessHash {
|
||||
return false
|
||||
}
|
||||
if lhs.shortName != rhs.shortName {
|
||||
return false
|
||||
}
|
||||
if lhs.title != rhs.title {
|
||||
return false
|
||||
}
|
||||
if lhs.description != rhs.description {
|
||||
return false
|
||||
}
|
||||
if lhs.photo != rhs.photo {
|
||||
return false
|
||||
}
|
||||
if lhs.document != rhs.document {
|
||||
return false
|
||||
}
|
||||
if lhs.hash != rhs.hash {
|
||||
return false
|
||||
}
|
||||
if lhs.flags != rhs.flags {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public enum GetBotAppError {
|
||||
case generic
|
||||
}
|
||||
|
||||
func _internal_getBotApp(account: Account, reference: BotAppReference) -> Signal<BotApp, GetBotAppError> {
|
||||
return account.postbox.transaction { transaction -> Signal<BotApp, GetBotAppError> in
|
||||
let app: Api.InputBotApp
|
||||
switch reference {
|
||||
case let .id(id, accessHash):
|
||||
app = .inputBotAppID(id: id, accessHash: accessHash)
|
||||
case let .shortName(peerId, shortName):
|
||||
guard let bot = transaction.getPeer(peerId), let inputBot = apiInputUser(bot) else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
app = .inputBotAppShortName(botId: inputBot, shortName: shortName)
|
||||
}
|
||||
|
||||
return account.network.request(Api.functions.messages.getBotApp(app: app, hash: 0))
|
||||
|> mapError { _ -> GetBotAppError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { result -> Signal<BotApp, GetBotAppError> in
|
||||
switch result {
|
||||
case let .botApp(_, app):
|
||||
switch app {
|
||||
case let .botApp(flags, id, accessHash, shortName, title, description, photo, document, hash):
|
||||
var appFlags = BotApp.Flags()
|
||||
if (flags & (1 << 0)) != 0 {
|
||||
appFlags.insert(.notActivated)
|
||||
}
|
||||
if (flags & (1 << 1)) != 0 {
|
||||
appFlags.insert(.requiresWriteAccess)
|
||||
}
|
||||
return .single(BotApp(id: id, accessHash: accessHash, shortName: shortName, title: title, description: description, photo: telegramMediaImageFromApiPhoto(photo), document: document.flatMap(telegramMediaFileFromApiDocument), hash: hash, flags: appFlags))
|
||||
case .botAppNotModified:
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|> castError(GetBotAppError.self)
|
||||
|> switchToLatest
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ public enum RequestSimpleWebViewError {
|
||||
case generic
|
||||
}
|
||||
|
||||
func _internal_requestSimpleWebView(postbox: Postbox, network: Network, botId: PeerId, url: String, themeParams: [String: Any]?) -> Signal<String, RequestSimpleWebViewError> {
|
||||
func _internal_requestSimpleWebView(postbox: Postbox, network: Network, botId: PeerId, url: String, inline: Bool, themeParams: [String: Any]?) -> Signal<String, RequestSimpleWebViewError> {
|
||||
var serializedThemeParams: Api.DataJSON?
|
||||
if let themeParams = themeParams, let data = try? JSONSerialization.data(withJSONObject: themeParams, options: []), let dataString = String(data: data, encoding: .utf8) {
|
||||
serializedThemeParams = .dataJSON(data: dataString)
|
||||
@ -28,6 +28,9 @@ func _internal_requestSimpleWebView(postbox: Postbox, network: Network, botId: P
|
||||
if let _ = serializedThemeParams {
|
||||
flags |= (1 << 0)
|
||||
}
|
||||
if inline {
|
||||
flags |= (1 << 1)
|
||||
}
|
||||
return network.request(Api.functions.messages.requestSimpleWebView(flags: flags, bot: inputUser, url: url, themeParams: serializedThemeParams, platform: botWebViewPlatform))
|
||||
|> mapError { _ -> RequestSimpleWebViewError in
|
||||
return .generic
|
||||
@ -131,9 +134,7 @@ func _internal_requestWebView(postbox: Postbox, network: Network, stateManager:
|
||||
if threadId != nil {
|
||||
flags |= (1 << 9)
|
||||
}
|
||||
// if _ {
|
||||
// flags |= (1 << 13)
|
||||
// }
|
||||
|
||||
return network.request(Api.functions.messages.requestWebView(flags: flags, peer: inputPeer, bot: inputBot, url: url, startParam: payload, themeParams: serializedThemeParams, platform: botWebViewPlatform, replyToMsgId: replyToMsgId, topMsgId: threadId.flatMap(Int32.init(clamping:)), sendAs: nil))
|
||||
|> mapError { _ -> RequestWebViewError in
|
||||
return .generic
|
||||
@ -172,3 +173,52 @@ func _internal_sendWebViewData(postbox: Postbox, network: Network, stateManager:
|
||||
|> castError(SendWebViewDataError.self)
|
||||
|> switchToLatest
|
||||
}
|
||||
|
||||
public enum RequestAppWebViewError {
|
||||
case generic
|
||||
}
|
||||
|
||||
func _internal_requestAppWebView(postbox: Postbox, network: Network, stateManager: AccountStateManager, peerId: PeerId, appReference: BotAppReference, payload: String?, themeParams: [String: Any]?, allowWrite: Bool) -> Signal<String, RequestAppWebViewError> {
|
||||
var serializedThemeParams: Api.DataJSON?
|
||||
if let themeParams = themeParams, let data = try? JSONSerialization.data(withJSONObject: themeParams, options: []), let dataString = String(data: data, encoding: .utf8) {
|
||||
serializedThemeParams = .dataJSON(data: dataString)
|
||||
}
|
||||
|
||||
return postbox.transaction { transaction -> Signal<String, RequestAppWebViewError> in
|
||||
guard let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
let app: Api.InputBotApp
|
||||
switch appReference {
|
||||
case let .id(id, accessHash):
|
||||
app = .inputBotAppID(id: id, accessHash: accessHash)
|
||||
case let .shortName(peerId, shortName):
|
||||
guard let bot = transaction.getPeer(peerId), let inputBot = apiInputUser(bot) else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
app = .inputBotAppShortName(botId: inputBot, shortName: shortName)
|
||||
}
|
||||
|
||||
var flags: Int32 = 0
|
||||
if let _ = serializedThemeParams {
|
||||
flags |= (1 << 2)
|
||||
}
|
||||
if let _ = payload {
|
||||
flags |= (1 << 1)
|
||||
}
|
||||
|
||||
return network.request(Api.functions.messages.requestAppWebView(flags: flags, peer: inputPeer, app: app, startParam: payload, themeParams: serializedThemeParams, platform: botWebViewPlatform))
|
||||
|> mapError { _ -> RequestAppWebViewError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { result -> Signal<String, RequestAppWebViewError> in
|
||||
switch result {
|
||||
case let .appWebViewResultUrl(url):
|
||||
return .single(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|> castError(RequestAppWebViewError.self)
|
||||
|> switchToLatest
|
||||
}
|
||||
|
@ -99,6 +99,7 @@ func _internal_requestChatContextResults(account: Account, botId: PeerId, peerId
|
||||
nextOffset: nil,
|
||||
presentation: cachedResult.presentation,
|
||||
switchPeer: cachedResult.switchPeer,
|
||||
webView: cachedResult.webView,
|
||||
results: cachedResult.results,
|
||||
cacheTimeout: 0
|
||||
)
|
||||
|
@ -394,11 +394,14 @@ public extension TelegramEngine {
|
||||
return _internal_requestWebView(postbox: self.account.postbox, network: self.account.network, stateManager: self.account.stateManager, peerId: peerId, botId: botId, url: url, payload: payload, themeParams: themeParams, fromMenu: fromMenu, replyToMessageId: replyToMessageId, threadId: threadId)
|
||||
}
|
||||
|
||||
public func requestSimpleWebView(botId: PeerId, url: String, themeParams: [String: Any]?) -> Signal<String, RequestSimpleWebViewError> {
|
||||
return _internal_requestSimpleWebView(postbox: self.account.postbox, network: self.account.network, botId: botId, url: url, themeParams: themeParams)
|
||||
public func requestSimpleWebView(botId: PeerId, url: String, inline: Bool, themeParams: [String: Any]?) -> Signal<String, RequestSimpleWebViewError> {
|
||||
return _internal_requestSimpleWebView(postbox: self.account.postbox, network: self.account.network, botId: botId, url: url, inline: inline, themeParams: themeParams)
|
||||
}
|
||||
|
||||
public func requestAppWebView(peerId: PeerId, appReference: BotAppReference, payload: String?, themeParams: [String: Any]?, allowWrite: Bool) -> Signal<String, RequestAppWebViewError> {
|
||||
return _internal_requestAppWebView(postbox: self.account.postbox, network: self.account.network, stateManager: self.account.stateManager, peerId: peerId, appReference: appReference, payload: payload, themeParams: themeParams, allowWrite: allowWrite)
|
||||
}
|
||||
|
||||
|
||||
public func sendWebViewData(botId: PeerId, buttonText: String, data: String) -> Signal<Never, SendWebViewDataError> {
|
||||
return _internal_sendWebViewData(postbox: self.account.postbox, network: self.account.network, stateManager: self.account.stateManager, botId: botId, buttonText: buttonText, data: data)
|
||||
}
|
||||
@ -419,6 +422,10 @@ public extension TelegramEngine {
|
||||
return _internal_attachMenuBots(postbox: self.account.postbox)
|
||||
}
|
||||
|
||||
public func getBotApp(botId: PeerId, shortName: String, cached: Bool = false) -> Signal<BotApp, GetBotAppError> {
|
||||
return _internal_getBotApp(account: self.account, reference: .shortName(peerId: botId, shortName: shortName))
|
||||
}
|
||||
|
||||
public func ensureMessagesAreLocallyAvailable(messages: [EngineMessage]) {
|
||||
let _ = self.account.postbox.transaction({ transaction in
|
||||
for message in messages {
|
||||
|
@ -165,7 +165,7 @@ public final class ChatControllerInteraction {
|
||||
public let commitEmojiInteraction: (MessageId, String, EmojiInteraction, TelegramMediaFile) -> Void
|
||||
public let openLargeEmojiInfo: (String, String?, TelegramMediaFile) -> Void
|
||||
public let openJoinLink: (String) -> Void
|
||||
public let openWebView: (String, String, Bool, Bool) -> Void
|
||||
public let openWebView: (String, String, Bool, ChatOpenWebViewSource) -> Void
|
||||
public let activateAdAction: (EngineMessage.Id) -> Void
|
||||
public let openRequestedPeerSelection: (EngineMessage.Id, ReplyMarkupButtonRequestPeerType, Int32) -> Void
|
||||
|
||||
@ -277,7 +277,7 @@ public final class ChatControllerInteraction {
|
||||
commitEmojiInteraction: @escaping (MessageId, String, EmojiInteraction, TelegramMediaFile) -> Void,
|
||||
openLargeEmojiInfo: @escaping (String, String?, TelegramMediaFile) -> Void,
|
||||
openJoinLink: @escaping (String) -> Void,
|
||||
openWebView: @escaping (String, String, Bool, Bool) -> Void,
|
||||
openWebView: @escaping (String, String, Bool, ChatOpenWebViewSource) -> Void,
|
||||
activateAdAction: @escaping (EngineMessage.Id) -> Void,
|
||||
openRequestedPeerSelection: @escaping (EngineMessage.Id, ReplyMarkupButtonRequestPeerType, Int32) -> Void,
|
||||
requestMessageUpdate: @escaping (MessageId, Bool) -> Void,
|
||||
|
@ -1243,7 +1243,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
return
|
||||
}
|
||||
var bubbleUpEmojiOrStickersets: [ItemCollectionId] = []
|
||||
if let id = groupId.base as? ItemCollectionId {
|
||||
if let id = groupId.base as? ItemCollectionId, context.sharedContext.currentStickerSettings.with({ $0 }).dynamicPackOrder {
|
||||
bubbleUpEmojiOrStickersets.append(id)
|
||||
}
|
||||
let _ = interfaceInteraction.sendSticker(.standalone(media: file), false, view, rect, layer, bubbleUpEmojiOrStickersets)
|
||||
@ -2507,12 +2507,15 @@ public final class EmojiContentPeekBehaviorImpl: EmojiContentPeekBehavior {
|
||||
return nil
|
||||
}
|
||||
|
||||
let context = strongSelf.context
|
||||
|
||||
var bubbleUpEmojiOrStickersets: [ItemCollectionId] = []
|
||||
if let id = groupId.base as? ItemCollectionId {
|
||||
bubbleUpEmojiOrStickersets.append(id)
|
||||
if file.isCustomEmoji || context.sharedContext.currentStickerSettings.with({ $0 }).dynamicPackOrder {
|
||||
bubbleUpEmojiOrStickersets.append(id)
|
||||
}
|
||||
}
|
||||
|
||||
let context = strongSelf.context
|
||||
let accountPeerId = context.account.peerId
|
||||
let chatPeerId = strongSelf.chatPeerId
|
||||
|
||||
|
@ -199,7 +199,7 @@ private final class SliderContextItemNode: ASDisplayNode, ContextMenuCustomNode
|
||||
@objc private func tapGesture(_ gestureRecognizer: UITapGestureRecognizer) {
|
||||
let range = self.maxValue - self.minValue
|
||||
let location = gestureRecognizer.location(in: gestureRecognizer.view)
|
||||
self.value = max(self.minValue, min(self.maxValue, location.x / range))
|
||||
self.value = max(self.minValue, min(self.maxValue, self.minValue + location.x / self.bounds.width * range))
|
||||
self.valueChanged(self.value, true)
|
||||
}
|
||||
|
||||
|
12
submodules/TelegramUI/Images.xcassets/Settings/Menu/Archived.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Settings/Menu/Archived.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "archived.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
224
submodules/TelegramUI/Images.xcassets/Settings/Menu/Archived.imageset/archived.pdf
vendored
Normal file
224
submodules/TelegramUI/Images.xcassets/Settings/Menu/Archived.imageset/archived.pdf
vendored
Normal file
@ -0,0 +1,224 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
|
||||
0.203922 0.780392 0.349020 scn
|
||||
0.000000 18.799999 m
|
||||
0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c
|
||||
1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c
|
||||
5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c
|
||||
18.799999 30.000000 l
|
||||
22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c
|
||||
27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c
|
||||
30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c
|
||||
30.000000 11.200001 l
|
||||
30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c
|
||||
28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c
|
||||
24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c
|
||||
11.200000 0.000000 l
|
||||
7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c
|
||||
2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c
|
||||
0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c
|
||||
0.000000 18.799999 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 6.000000 6.000000 cm
|
||||
1.000000 1.000000 1.000000 scn
|
||||
0.000000 11.600000 m
|
||||
0.000000 13.840210 0.000000 14.960315 0.435974 15.815962 c
|
||||
0.819467 16.568611 1.431390 17.180532 2.184038 17.564026 c
|
||||
3.039685 18.000000 4.159790 18.000000 6.400000 18.000000 c
|
||||
12.461538 18.000000 l
|
||||
13.893039 18.000000 14.608788 18.000000 15.190012 17.818884 c
|
||||
16.445040 17.427801 17.427801 16.445040 17.818884 15.190012 c
|
||||
18.000000 14.608788 18.000000 13.893039 18.000000 12.461538 c
|
||||
18.000000 9.240663 18.000000 7.630225 17.592487 6.322473 c
|
||||
16.712553 3.498662 14.501338 1.287447 11.677527 0.407513 c
|
||||
10.369775 0.000000 8.759336 0.000000 5.538461 0.000000 c
|
||||
4.106961 0.000000 3.391211 0.000000 2.809988 0.181116 c
|
||||
1.554961 0.572199 0.572199 1.554960 0.181116 2.809988 c
|
||||
0.000000 3.391212 0.000000 4.106961 0.000000 5.538462 c
|
||||
0.000000 11.600000 l
|
||||
h
|
||||
6.250000 9.625000 m
|
||||
6.940356 9.625000 7.500000 10.324555 7.500000 11.187500 c
|
||||
7.500000 12.050446 6.940356 12.750000 6.250000 12.750000 c
|
||||
5.559644 12.750000 5.000000 12.050446 5.000000 11.187500 c
|
||||
5.000000 10.324555 5.559644 9.625000 6.250000 9.625000 c
|
||||
h
|
||||
11.750000 9.625000 m
|
||||
12.440355 9.625000 13.000000 10.324555 13.000000 11.187500 c
|
||||
13.000000 12.050446 12.440355 12.750000 11.750000 12.750000 c
|
||||
11.059645 12.750000 10.500000 12.050446 10.500000 11.187500 c
|
||||
10.500000 10.324555 11.059645 9.625000 11.750000 9.625000 c
|
||||
h
|
||||
5.531705 6.899393 m
|
||||
5.311266 7.192869 4.894684 7.252263 4.601000 7.032000 c
|
||||
4.307185 6.811639 4.247638 6.394815 4.468000 6.101000 c
|
||||
5.000000 6.500000 l
|
||||
4.468000 6.101000 4.468162 6.100784 4.468329 6.100561 c
|
||||
4.468694 6.100076 l
|
||||
4.469531 6.098966 l
|
||||
4.471629 6.096197 l
|
||||
4.477521 6.088497 l
|
||||
4.496066 6.064772 l
|
||||
4.511416 6.045382 4.532754 6.018972 4.559963 5.986553 c
|
||||
4.614337 5.921766 4.692429 5.832656 4.793315 5.727383 c
|
||||
4.994541 5.517408 5.289614 5.239828 5.671366 4.962191 c
|
||||
6.432307 4.408777 7.566772 3.834998 8.999999 3.834996 c
|
||||
9.826370 3.834996 10.586204 3.974838 11.266029 4.271576 c
|
||||
11.602630 4.418500 11.756393 4.810473 11.609470 5.147075 c
|
||||
11.462546 5.483676 11.070572 5.637440 10.733971 5.490517 c
|
||||
10.249819 5.279187 9.676319 5.164996 9.000001 5.164996 c
|
||||
7.933228 5.164998 7.067693 5.591221 6.453634 6.037808 c
|
||||
6.147886 6.260172 5.911709 6.482592 5.753560 6.647617 c
|
||||
5.674759 6.729844 5.616131 6.796984 5.578709 6.841572 c
|
||||
5.560019 6.863840 5.546690 6.880400 5.538846 6.890306 c
|
||||
5.531443 6.899742 l
|
||||
5.531705 6.899393 l
|
||||
h
|
||||
5.531705 6.899393 m
|
||||
5.531803 6.899262 5.531902 6.899131 5.532000 6.899000 c
|
||||
5.000000 6.500000 l
|
||||
5.532000 6.899000 5.531850 6.899200 5.531705 6.899393 c
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 16.000000 2.340088 cm
|
||||
0.203922 0.780392 0.349020 scn
|
||||
7.670000 7.159912 m
|
||||
7.670000 5.409170 6.250742 3.989912 4.500000 3.989912 c
|
||||
4.500000 1.329912 l
|
||||
7.719820 1.329912 10.330000 3.940092 10.330000 7.159912 c
|
||||
7.670000 7.159912 l
|
||||
h
|
||||
4.500000 3.989912 m
|
||||
2.749257 3.989912 1.330000 5.409170 1.330000 7.159912 c
|
||||
-1.330000 7.159912 l
|
||||
-1.330000 3.940092 1.280180 1.329912 4.500000 1.329912 c
|
||||
4.500000 3.989912 l
|
||||
h
|
||||
1.330000 7.159912 m
|
||||
1.330000 8.910655 2.749257 10.329912 4.500000 10.329912 c
|
||||
4.500000 12.989912 l
|
||||
1.280180 12.989912 -1.330000 10.379732 -1.330000 7.159912 c
|
||||
1.330000 7.159912 l
|
||||
h
|
||||
4.500000 10.329912 m
|
||||
6.250742 10.329912 7.670000 8.910655 7.670000 7.159912 c
|
||||
10.330000 7.159912 l
|
||||
10.330000 10.379732 7.719820 12.989912 4.500000 12.989912 c
|
||||
4.500000 10.329912 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 16.000000 2.340088 cm
|
||||
1.000000 1.000000 1.000000 scn
|
||||
9.000000 7.159912 m
|
||||
9.000000 4.674631 6.985281 2.659912 4.500000 2.659912 c
|
||||
2.014719 2.659912 0.000000 4.674631 0.000000 7.159912 c
|
||||
0.000000 9.645193 2.014719 11.659912 4.500000 11.659912 c
|
||||
6.985281 11.659912 9.000000 9.645193 9.000000 7.159912 c
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 20.500000 8.169922 cm
|
||||
0.203922 0.780392 0.349020 scn
|
||||
0.665000 3.830078 m
|
||||
0.665000 4.197348 0.367269 4.495078 0.000000 4.495078 c
|
||||
-0.367269 4.495078 -0.665000 4.197348 -0.665000 3.830078 c
|
||||
0.665000 3.830078 l
|
||||
h
|
||||
0.000000 1.330078 m
|
||||
-0.665000 1.330078 l
|
||||
-0.665000 0.962809 -0.367269 0.665078 0.000000 0.665078 c
|
||||
0.000000 1.330078 l
|
||||
h
|
||||
2.000000 0.665078 m
|
||||
2.367269 0.665078 2.665000 0.962809 2.665000 1.330078 c
|
||||
2.665000 1.697347 2.367269 1.995078 2.000000 1.995078 c
|
||||
2.000000 0.665078 l
|
||||
h
|
||||
-0.665000 3.830078 m
|
||||
-0.665000 1.330078 l
|
||||
0.665000 1.330078 l
|
||||
0.665000 3.830078 l
|
||||
-0.665000 3.830078 l
|
||||
h
|
||||
0.000000 0.665078 m
|
||||
2.000000 0.665078 l
|
||||
2.000000 1.995078 l
|
||||
0.000000 1.995078 l
|
||||
0.000000 0.665078 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
5423
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000005513 00000 n
|
||||
0000005536 00000 n
|
||||
0000005709 00000 n
|
||||
0000005783 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
5842
|
||||
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Settings/Menu/Emoji.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Settings/Menu/Emoji.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "emoji (2).pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
144
submodules/TelegramUI/Images.xcassets/Settings/Menu/Emoji.imageset/emoji (2).pdf
vendored
Normal file
144
submodules/TelegramUI/Images.xcassets/Settings/Menu/Emoji.imageset/emoji (2).pdf
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
|
||||
0.196078 0.678431 0.901961 scn
|
||||
0.000000 18.799999 m
|
||||
0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c
|
||||
1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c
|
||||
5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c
|
||||
18.799999 30.000000 l
|
||||
22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c
|
||||
27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c
|
||||
30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c
|
||||
30.000000 11.200001 l
|
||||
30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c
|
||||
28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c
|
||||
24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c
|
||||
11.200000 0.000000 l
|
||||
7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c
|
||||
2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c
|
||||
0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c
|
||||
0.000000 18.799999 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 5.000000 5.000000 cm
|
||||
1.000000 1.000000 1.000000 scn
|
||||
0.000000 10.000000 m
|
||||
0.000000 5.332758 3.197396 1.412308 7.521235 0.309603 c
|
||||
7.192342 0.790955 7.000000 1.373016 7.000000 2.000000 c
|
||||
7.000000 3.113091 l
|
||||
5.212887 3.938812 4.297566 5.421120 3.859255 6.432051 c
|
||||
3.686586 6.830300 4.118104 7.180214 4.520657 7.017826 c
|
||||
5.607882 6.579245 7.514322 6.000000 10.000001 6.000000 c
|
||||
12.485676 6.000000 14.392107 6.579244 15.479328 7.017824 c
|
||||
15.881880 7.180212 16.313400 6.830300 16.140732 6.432050 c
|
||||
15.702424 5.421119 14.787108 3.938814 13.000000 3.113092 c
|
||||
13.000000 2.000000 l
|
||||
13.000000 1.373016 12.807658 0.790955 12.478765 0.309603 c
|
||||
16.802603 1.412308 20.000000 5.332758 20.000000 10.000000 c
|
||||
20.000000 15.522848 15.522847 20.000000 10.000000 20.000000 c
|
||||
4.477152 20.000000 0.000000 15.522848 0.000000 10.000000 c
|
||||
h
|
||||
14.000001 9.250000 m
|
||||
15.242641 9.250000 16.250000 10.257360 16.250000 11.500000 c
|
||||
16.250000 12.742640 15.242641 13.750000 14.000001 13.750000 c
|
||||
12.757360 13.750000 11.750001 12.742640 11.750001 11.500000 c
|
||||
11.750001 10.257360 12.757360 9.250000 14.000001 9.250000 c
|
||||
h
|
||||
14.000001 8.250000 m
|
||||
15.794927 8.250000 17.250000 9.705074 17.250000 11.500000 c
|
||||
17.250000 13.294926 15.794927 14.750000 14.000001 14.750000 c
|
||||
12.205075 14.750000 10.750001 13.294926 10.750001 11.500000 c
|
||||
10.750001 9.705074 12.205075 8.250000 14.000001 8.250000 c
|
||||
h
|
||||
15.000001 11.500000 m
|
||||
15.000001 10.947716 14.552285 10.500000 14.000001 10.500000 c
|
||||
13.447717 10.500000 13.000001 10.947716 13.000001 11.500000 c
|
||||
13.000001 12.052284 13.447717 12.500000 14.000001 12.500000 c
|
||||
14.552285 12.500000 15.000001 12.052284 15.000001 11.500000 c
|
||||
h
|
||||
8.982612 10.447145 m
|
||||
8.552257 10.964127 7.794065 11.500000 6.500000 11.500000 c
|
||||
5.205936 11.500000 4.447744 10.964127 4.017390 10.447145 c
|
||||
3.744092 10.118834 4.103591 9.767232 4.509996 9.898819 c
|
||||
5.063556 10.078053 5.781778 10.250000 6.500000 10.250000 c
|
||||
7.218223 10.250000 7.936446 10.078053 8.490005 9.898819 c
|
||||
8.896410 9.767232 9.255910 10.118834 8.982612 10.447145 c
|
||||
h
|
||||
9.000000 5.000000 m
|
||||
8.447716 5.000000 8.000000 4.552284 8.000000 4.000000 c
|
||||
8.000000 2.000000 l
|
||||
8.000000 0.895432 8.895431 0.000000 10.000000 0.000000 c
|
||||
11.104569 0.000000 12.000000 0.895432 12.000000 2.000000 c
|
||||
12.000000 4.000000 l
|
||||
12.000000 4.552284 11.552284 5.000000 11.000000 5.000000 c
|
||||
10.714355 5.000000 10.473413 4.787300 10.437983 4.503861 c
|
||||
10.137049 2.096386 l
|
||||
10.116884 1.935076 9.883116 1.935074 9.862951 2.096386 c
|
||||
9.562017 4.503861 l
|
||||
9.526587 4.787299 9.285645 5.000000 9.000000 5.000000 c
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
3490
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000003580 00000 n
|
||||
0000003603 00000 n
|
||||
0000003776 00000 n
|
||||
0000003850 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
3909
|
||||
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Settings/Menu/Trending.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Settings/Menu/Trending.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "trending.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
187
submodules/TelegramUI/Images.xcassets/Settings/Menu/Trending.imageset/trending.pdf
vendored
Normal file
187
submodules/TelegramUI/Images.xcassets/Settings/Menu/Trending.imageset/trending.pdf
vendored
Normal file
@ -0,0 +1,187 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
|
||||
1.000000 0.584314 0.000000 scn
|
||||
0.000000 18.799999 m
|
||||
0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c
|
||||
1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c
|
||||
5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c
|
||||
18.799999 30.000000 l
|
||||
22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c
|
||||
27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c
|
||||
30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c
|
||||
30.000000 11.200001 l
|
||||
30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c
|
||||
28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c
|
||||
24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c
|
||||
11.200000 0.000000 l
|
||||
7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c
|
||||
2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c
|
||||
0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c
|
||||
0.000000 18.799999 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 7.000000 4.949829 cm
|
||||
1.000000 1.000000 1.000000 scn
|
||||
7.482707 0.050171 m
|
||||
13.209023 0.050171 16.000000 4.179979 16.000000 8.852560 c
|
||||
16.000000 13.454344 13.257144 18.598904 7.987970 21.029589 c
|
||||
7.771429 21.100386 7.627068 20.982391 7.651128 20.770000 c
|
||||
8.060151 16.899782 7.458647 13.312751 6.183459 11.613630 c
|
||||
5.581955 12.982367 4.860150 14.162312 3.753384 15.129866 c
|
||||
3.584962 15.271460 3.440602 15.200663 3.392481 14.988272 c
|
||||
3.007519 12.321597 0.000000 10.834866 0.000000 6.681460 c
|
||||
0.000000 2.716846 2.983459 0.050171 7.482707 0.050171 c
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 16.000000 2.340088 cm
|
||||
1.000000 0.584314 0.000000 scn
|
||||
7.670000 7.159912 m
|
||||
7.670000 5.409170 6.250742 3.989912 4.500000 3.989912 c
|
||||
4.500000 1.329912 l
|
||||
7.719820 1.329912 10.330000 3.940092 10.330000 7.159912 c
|
||||
7.670000 7.159912 l
|
||||
h
|
||||
4.500000 3.989912 m
|
||||
2.749257 3.989912 1.330000 5.409170 1.330000 7.159912 c
|
||||
-1.330000 7.159912 l
|
||||
-1.330000 3.940092 1.280180 1.329912 4.500000 1.329912 c
|
||||
4.500000 3.989912 l
|
||||
h
|
||||
1.330000 7.159912 m
|
||||
1.330000 8.910655 2.749257 10.329912 4.500000 10.329912 c
|
||||
4.500000 12.989912 l
|
||||
1.280180 12.989912 -1.330000 10.379732 -1.330000 7.159912 c
|
||||
1.330000 7.159912 l
|
||||
h
|
||||
4.500000 10.329912 m
|
||||
6.250742 10.329912 7.670000 8.910655 7.670000 7.159912 c
|
||||
10.330000 7.159912 l
|
||||
10.330000 10.379732 7.719820 12.989912 4.500000 12.989912 c
|
||||
4.500000 10.329912 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 16.000000 2.340088 cm
|
||||
1.000000 1.000000 1.000000 scn
|
||||
9.000000 7.159912 m
|
||||
9.000000 4.674631 6.985281 2.659912 4.500000 2.659912 c
|
||||
2.014719 2.659912 0.000000 4.674631 0.000000 7.159912 c
|
||||
0.000000 9.645193 2.014719 11.659912 4.500000 11.659912 c
|
||||
6.985281 11.659912 9.000000 9.645193 9.000000 7.159912 c
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 20.500000 6.169922 cm
|
||||
1.000000 0.584314 0.000000 scn
|
||||
0.665000 5.330078 m
|
||||
0.665000 5.697348 0.367269 5.995078 0.000000 5.995078 c
|
||||
-0.367269 5.995078 -0.665000 5.697348 -0.665000 5.330078 c
|
||||
0.665000 5.330078 l
|
||||
h
|
||||
-0.665000 1.330078 m
|
||||
-0.665000 0.962809 -0.367269 0.665078 0.000000 0.665078 c
|
||||
0.367269 0.665078 0.665000 0.962809 0.665000 1.330078 c
|
||||
-0.665000 1.330078 l
|
||||
h
|
||||
-0.665000 5.330078 m
|
||||
-0.665000 1.330078 l
|
||||
0.665000 1.330078 l
|
||||
0.665000 5.330078 l
|
||||
-0.665000 5.330078 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
0.000000 1.000000 -1.000000 0.000000 19.830078 9.500000 cm
|
||||
1.000000 0.584314 0.000000 scn
|
||||
0.665000 1.330078 m
|
||||
0.665000 1.697348 0.367269 1.995078 0.000000 1.995078 c
|
||||
-0.367269 1.995078 -0.665000 1.697348 -0.665000 1.330078 c
|
||||
0.665000 1.330078 l
|
||||
h
|
||||
-0.665000 -2.669922 m
|
||||
-0.665000 -3.037191 -0.367269 -3.334922 0.000000 -3.334922 c
|
||||
0.367269 -3.334922 0.665000 -3.037191 0.665000 -2.669922 c
|
||||
-0.665000 -2.669922 l
|
||||
h
|
||||
-0.665000 1.330078 m
|
||||
-0.665000 -2.669922 l
|
||||
0.665000 -2.669922 l
|
||||
0.665000 1.330078 l
|
||||
-0.665000 1.330078 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
3743
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000003833 00000 n
|
||||
0000003856 00000 n
|
||||
0000004029 00000 n
|
||||
0000004103 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
4162
|
||||
%%EOF
|
@ -433,7 +433,7 @@ final class ChatButtonKeyboardInputNode: ChatInputNode {
|
||||
self.controllerInteraction.openPeer(peer, .info, nil, .default)
|
||||
})
|
||||
case let .openWebView(url, simple):
|
||||
self.controllerInteraction.openWebView(markupButton.title, url, simple, false)
|
||||
self.controllerInteraction.openWebView(markupButton.title, url, simple, .generic)
|
||||
case let .requestPeer(peerType, buttonId):
|
||||
if let message = self.message {
|
||||
self.controllerInteraction.openRequestedPeerSelection(message.id, peerType, buttonId)
|
||||
|
@ -90,6 +90,7 @@ import ChatControllerInteraction
|
||||
import FeaturedStickersScreen
|
||||
import ChatEntityKeyboardInputNode
|
||||
import StorageUsageScreen
|
||||
import AvatarEditorScreen
|
||||
|
||||
#if DEBUG
|
||||
import os.signpost
|
||||
@ -234,6 +235,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
public let subject: ChatControllerSubject?
|
||||
private let botStart: ChatControllerInitialBotStart?
|
||||
private var attachBotStart: ChatControllerInitialAttachBotStart?
|
||||
private var botAppStart: ChatControllerInitialBotAppStart?
|
||||
|
||||
private let peerDisposable = MetaDisposable()
|
||||
private let titleDisposable = MetaDisposable()
|
||||
@ -545,7 +547,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
private var currentSpeechHolder: SpeechSynthesizerHolder?
|
||||
|
||||
public init(context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, attachBotStart: ChatControllerInitialAttachBotStart? = nil, mode: ChatControllerPresentationMode = .standard(previewing: false), peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, chatListFilter: Int32? = nil, chatNavigationStack: [ChatNavigationStackItem] = []) {
|
||||
public init(context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, attachBotStart: ChatControllerInitialAttachBotStart? = nil, botAppStart: ChatControllerInitialBotAppStart? = nil, mode: ChatControllerPresentationMode = .standard(previewing: false), peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, chatListFilter: Int32? = nil, chatNavigationStack: [ChatNavigationStackItem] = []) {
|
||||
let _ = ChatControllerCount.modify { value in
|
||||
return value + 1
|
||||
}
|
||||
@ -556,6 +558,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
self.subject = subject
|
||||
self.botStart = botStart
|
||||
self.attachBotStart = attachBotStart
|
||||
self.botAppStart = botAppStart
|
||||
self.peekData = peekData
|
||||
self.currentChatListFilter = chatListFilter
|
||||
self.chatNavigationStack = chatNavigationStack
|
||||
@ -671,6 +674,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return false
|
||||
}
|
||||
|
||||
if strongSelf.presentVoiceMessageDiscardAlert(action: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
Queue.mainQueue().after(0.1, {
|
||||
let _ = strongSelf.controllerInteraction?.openMessage(message, mode)
|
||||
})
|
||||
}
|
||||
}, performAction: false) {
|
||||
return false
|
||||
}
|
||||
|
||||
strongSelf.commitPurposefulAction()
|
||||
strongSelf.dismissAllTooltips()
|
||||
|
||||
@ -833,38 +846,59 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
if let image = image {
|
||||
if message.effectivelyIncoming(strongSelf.context.account.peerId) {
|
||||
var selectedNode: (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?
|
||||
strongSelf.chatDisplayNode.historyNode.forEachItemNode { itemNode in
|
||||
if let itemNode = itemNode as? ChatMessageItemView {
|
||||
if let result = itemNode.transitionNode(id: message.id, media: image) {
|
||||
selectedNode = result
|
||||
if let emojiMarkup = image.emojiMarkup {
|
||||
let controller = AvatarEditorScreen(context: strongSelf.context, inputData: AvatarEditorScreen.inputData(context: strongSelf.context, isGroup: false), peerType: .user, markup: emojiMarkup)
|
||||
controller.imageCompletion = { [weak self] image, commit in
|
||||
if let strongSelf = self {
|
||||
if let rootController = strongSelf.effectiveNavigationController as? TelegramRootController, let settingsController = rootController.accountSettingsController as? PeerInfoScreenImpl {
|
||||
settingsController.updateProfilePhoto(image, mode: .accept)
|
||||
commit()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let transitionView = selectedNode?.0.view
|
||||
|
||||
let senderName: String?
|
||||
if let peer = message.peers[message.id.peerId] {
|
||||
senderName = EnginePeer(peer).compactDisplayTitle
|
||||
controller.videoCompletion = { [weak self] image, url, adjustments, commit in
|
||||
if let strongSelf = self {
|
||||
if let rootController = strongSelf.effectiveNavigationController as? TelegramRootController, let settingsController = rootController.accountSettingsController as? PeerInfoScreenImpl {
|
||||
settingsController.updateProfileVideo(image, mode: .accept, asset: AVURLAsset(url: url), adjustments: adjustments)
|
||||
commit()
|
||||
}
|
||||
}
|
||||
}
|
||||
strongSelf.push(controller)
|
||||
} else {
|
||||
senderName = nil
|
||||
var selectedNode: (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?
|
||||
strongSelf.chatDisplayNode.historyNode.forEachItemNode { itemNode in
|
||||
if let itemNode = itemNode as? ChatMessageItemView {
|
||||
if let result = itemNode.transitionNode(id: message.id, media: image) {
|
||||
selectedNode = result
|
||||
}
|
||||
}
|
||||
}
|
||||
let transitionView = selectedNode?.0.view
|
||||
|
||||
let senderName: String?
|
||||
if let peer = message.peers[message.id.peerId] {
|
||||
senderName = EnginePeer(peer).compactDisplayTitle
|
||||
} else {
|
||||
senderName = nil
|
||||
}
|
||||
|
||||
legacyAvatarEditor(context: strongSelf.context, media: .message(message: MessageReference(message), media: image), transitionView: transitionView, senderName: senderName, present: { [weak self] c, a in
|
||||
self?.present(c, in: .window(.root), with: a)
|
||||
}, imageCompletion: { [weak self] image in
|
||||
if let strongSelf = self {
|
||||
if let rootController = strongSelf.effectiveNavigationController as? TelegramRootController, let settingsController = rootController.accountSettingsController as? PeerInfoScreenImpl {
|
||||
settingsController.updateProfilePhoto(image, mode: .accept)
|
||||
}
|
||||
}
|
||||
}, videoCompletion: { [weak self] image, url, adjustments in
|
||||
if let strongSelf = self {
|
||||
if let rootController = strongSelf.effectiveNavigationController as? TelegramRootController, let settingsController = rootController.accountSettingsController as? PeerInfoScreenImpl {
|
||||
settingsController.updateProfileVideo(image, mode: .accept, asset: AVURLAsset(url: url), adjustments: adjustments)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
legacyAvatarEditor(context: strongSelf.context, media: .message(message: MessageReference(message), media: image), transitionView: transitionView, senderName: senderName, present: { [weak self] c, a in
|
||||
self?.present(c, in: .window(.root), with: a)
|
||||
}, imageCompletion: { [weak self] image in
|
||||
if let strongSelf = self {
|
||||
if let rootController = strongSelf.effectiveNavigationController as? TelegramRootController, let settingsController = rootController.accountSettingsController as? PeerInfoScreenImpl {
|
||||
settingsController.updateProfilePhoto(image, mode: .accept)
|
||||
}
|
||||
}
|
||||
}, videoCompletion: { [weak self] image, url, adjustments in
|
||||
if let strongSelf = self {
|
||||
if let rootController = strongSelf.effectiveNavigationController as? TelegramRootController, let settingsController = rootController.accountSettingsController as? PeerInfoScreenImpl {
|
||||
settingsController.updateProfileVideo(image, mode: .accept, asset: AVURLAsset(url: url), adjustments: adjustments)
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
openMessageByAction = true
|
||||
}
|
||||
@ -2529,27 +2563,33 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}, openInstantPage: { [weak self] message, associatedData in
|
||||
if let strongSelf = self, strongSelf.isNodeLoaded, let navigationController = strongSelf.effectiveNavigationController, let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(message.id) {
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
openChatInstantPage(context: strongSelf.context, message: message, sourcePeerType: associatedData?.automaticDownloadPeerType, navigationController: navigationController)
|
||||
|
||||
if case .overlay = strongSelf.presentationInterfaceState.mode {
|
||||
strongSelf.chatDisplayNode.dismissAsOverlay()
|
||||
}
|
||||
let _ = strongSelf.presentVoiceMessageDiscardAlert(action: {
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
openChatInstantPage(context: strongSelf.context, message: message, sourcePeerType: associatedData?.automaticDownloadPeerType, navigationController: navigationController)
|
||||
|
||||
if case .overlay = strongSelf.presentationInterfaceState.mode {
|
||||
strongSelf.chatDisplayNode.dismissAsOverlay()
|
||||
}
|
||||
})
|
||||
}
|
||||
}, openWallpaper: { [weak self] message in
|
||||
if let strongSelf = self, strongSelf.isNodeLoaded, let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(message.id) {
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
openChatWallpaper(context: strongSelf.context, message: message, present: { [weak self] c, a in
|
||||
self?.present(c, in: .window(.root), with: a, blockInteraction: true)
|
||||
let _ = strongSelf.presentVoiceMessageDiscardAlert(action: {
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
openChatWallpaper(context: strongSelf.context, message: message, present: { [weak self] c, a in
|
||||
self?.present(c, in: .window(.root), with: a, blockInteraction: true)
|
||||
})
|
||||
})
|
||||
}
|
||||
}, openTheme: { [weak self] message in
|
||||
if let strongSelf = self, strongSelf.isNodeLoaded, let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(message.id) {
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
openChatTheme(context: strongSelf.context, message: message, pushController: { [weak self] c in
|
||||
self?.effectiveNavigationController?.pushViewController(c)
|
||||
}, present: { [weak self] c, a in
|
||||
self?.present(c, in: .window(.root), with: a, blockInteraction: true)
|
||||
let _ = strongSelf.presentVoiceMessageDiscardAlert(action: {
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
openChatTheme(context: strongSelf.context, message: message, pushController: { [weak self] c in
|
||||
self?.effectiveNavigationController?.pushViewController(c)
|
||||
}, present: { [weak self] c, a in
|
||||
self?.present(c, in: .window(.root), with: a, blockInteraction: true)
|
||||
})
|
||||
})
|
||||
}
|
||||
}, openHashtag: { [weak self] peerName, hashtag in
|
||||
@ -3984,7 +4024,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return
|
||||
}
|
||||
strongSelf.openResolved(result: .join(joinHash), sourceMessageId: nil)
|
||||
}, openWebView: { [weak self] buttonText, url, simple, fromMenu in
|
||||
}, openWebView: { [weak self] buttonText, url, simple, source in
|
||||
guard let strongSelf = self, let peerId = strongSelf.chatLocation.peerId, let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer as? TelegramUser else {
|
||||
return
|
||||
}
|
||||
@ -3993,7 +4033,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
let botName = EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)
|
||||
|
||||
if !fromMenu {
|
||||
if source == .generic {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, {
|
||||
return $0.updatedTitlePanelContext {
|
||||
if !$0.contains(where: {
|
||||
@ -4038,12 +4078,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
|
||||
let openWebView = {
|
||||
if fromMenu {
|
||||
if source == .menu {
|
||||
strongSelf.updateChatPresentationInterfaceState(interactive: false) { state in
|
||||
return state.updatedShowWebView(true).updatedForceInputCommandsHidden(true)
|
||||
}
|
||||
|
||||
let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, fromMenu: true, isSimple: false)
|
||||
let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, fromMenu: true, isInline: false, isSimple: false)
|
||||
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url in
|
||||
self?.openUrl(url, concealed: true, forceExternal: true)
|
||||
}, getInputContainerNode: { [weak self] in
|
||||
@ -4079,7 +4119,18 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
strongSelf.push(controller)
|
||||
strongSelf.currentMenuWebAppController = controller
|
||||
} else if simple {
|
||||
strongSelf.messageActionCallbackDisposable.set(((strongSelf.context.engine.messages.requestSimpleWebView(botId: peerId, url: url, themeParams: generateWebAppThemeParams(strongSelf.presentationData.theme))
|
||||
var isInline = false
|
||||
var botId = peerId
|
||||
var botName = botName
|
||||
var botAddress = ""
|
||||
if case let .inline(bot) = source {
|
||||
isInline = true
|
||||
botId = bot.id
|
||||
botName = bot.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)
|
||||
botAddress = bot.addressName ?? ""
|
||||
}
|
||||
|
||||
strongSelf.messageActionCallbackDisposable.set(((strongSelf.context.engine.messages.requestSimpleWebView(botId: botId, url: url, inline: isInline, themeParams: generateWebAppThemeParams(strongSelf.presentationData.theme))
|
||||
|> afterDisposed {
|
||||
updateProgress()
|
||||
})
|
||||
@ -4087,9 +4138,24 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, fromMenu: false, isSimple: true)
|
||||
let params = WebAppParameters(peerId: peerId, botId: botId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, fromMenu: false, isInline: isInline, isSimple: true)
|
||||
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url in
|
||||
self?.openUrl(url, concealed: true, forceExternal: true)
|
||||
}, requestSwitchInline: { [weak self] query, chatTypes in
|
||||
if let strongSelf = self {
|
||||
if let _ = chatTypes {
|
||||
let controller = strongSelf.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: strongSelf.context, filter: [.excludeRecent, .doNotSearchMessages], requestPeerType: nil, hasContactSelector: false))
|
||||
controller.peerSelected = { [weak self, weak controller] peer, _ in
|
||||
if let strongSelf = self {
|
||||
controller?.dismiss()
|
||||
strongSelf.controllerInteraction?.activateSwitchInline(peer.id, "@\(botAddress) \(query)")
|
||||
}
|
||||
}
|
||||
strongSelf.push(controller)
|
||||
} else {
|
||||
strongSelf.controllerInteraction?.activateSwitchInline(peerId, "@\(botAddress) \(query)")
|
||||
}
|
||||
}
|
||||
}, getNavigationController: { [weak self] in
|
||||
return self?.effectiveNavigationController
|
||||
})
|
||||
@ -4111,7 +4177,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botName, url: result.url, queryId: result.queryId, payload: nil, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, fromMenu: false, isSimple: false)
|
||||
let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botName, url: result.url, queryId: result.queryId, payload: nil, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, fromMenu: false, isInline: false, isSimple: false)
|
||||
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url in
|
||||
self?.openUrl(url, concealed: true, forceExternal: true)
|
||||
}, completion: { [weak self] in
|
||||
@ -10009,9 +10075,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}))
|
||||
})
|
||||
}
|
||||
}, openWebView: { [weak self] buttonText, url, simple, fromMenu in
|
||||
}, openWebView: { [weak self] buttonText, url, simple, source in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.openWebView(buttonText, url, simple, fromMenu)
|
||||
strongSelf.controllerInteraction?.openWebView(buttonText, url, simple, source)
|
||||
}
|
||||
}, updateShowWebView: { [weak self] f in
|
||||
if let strongSelf = self {
|
||||
@ -12228,7 +12294,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
|
||||
private func editMessageMediaWithLegacySignals(_ signals: [Any]) {
|
||||
let _ = (legacyAssetPickerEnqueueMessages(account: self.context.account, signals: signals)
|
||||
let _ = (legacyAssetPickerEnqueueMessages(context: self.context, account: self.context.account, signals: signals)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] messages in
|
||||
self?.editMessageMediaWithMessages(messages.map { $0.message })
|
||||
})
|
||||
@ -12424,6 +12490,81 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
self.presentAttachmentMenu(editMediaOptions: nil, editMediaReference: nil, botId: botId, botPayload: payload, botJustInstalled: justInstalled)
|
||||
}
|
||||
|
||||
public func presentBotApp(botApp: BotApp, payload: String?) {
|
||||
guard let peerId = self.chatLocation.peerId else {
|
||||
return
|
||||
}
|
||||
self.attachmentController?.dismiss(animated: true, completion: nil)
|
||||
|
||||
self.updateChatPresentationInterfaceState(animated: true, interactive: true, {
|
||||
return $0.updatedTitlePanelContext {
|
||||
if !$0.contains(where: {
|
||||
switch $0 {
|
||||
case .requestInProgress:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}) {
|
||||
var updatedContexts = $0
|
||||
updatedContexts.append(.requestInProgress)
|
||||
return updatedContexts.sorted()
|
||||
}
|
||||
return $0
|
||||
}
|
||||
})
|
||||
|
||||
let updateProgress = { [weak self] in
|
||||
Queue.mainQueue().async {
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, {
|
||||
return $0.updatedTitlePanelContext {
|
||||
if let index = $0.firstIndex(where: {
|
||||
switch $0 {
|
||||
case .requestInProgress:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}) {
|
||||
var updatedContexts = $0
|
||||
updatedContexts.remove(at: index)
|
||||
return updatedContexts
|
||||
}
|
||||
return $0
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.messageActionCallbackDisposable.set(((self.context.engine.messages.requestAppWebView(peerId: peerId, appReference: .id(id: botApp.id, accessHash: botApp.accessHash), payload: payload, themeParams: generateWebAppThemeParams(self.presentationData.theme), allowWrite: false)
|
||||
|> afterDisposed {
|
||||
updateProgress()
|
||||
})
|
||||
|> deliverOnMainQueue).start(next: { [weak self] url in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botApp.title, url: url, queryId: 0, payload: payload, buttonText: "", keepAliveSignal: nil, fromMenu: false, isInline: false, isSimple: false)
|
||||
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url in
|
||||
self?.openUrl(url, concealed: true, forceExternal: true)
|
||||
}, completion: { [weak self] in
|
||||
self?.chatDisplayNode.historyNode.scrollToEndOfHistory()
|
||||
}, getNavigationController: { [weak self] in
|
||||
return self?.effectiveNavigationController
|
||||
})
|
||||
controller.navigationPresentation = .flatModal
|
||||
strongSelf.currentWebAppController = controller
|
||||
strongSelf.push(controller)
|
||||
}, error: { [weak self] error in
|
||||
if let strongSelf = self {
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, title: nil, text: strongSelf.presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {
|
||||
})]), in: .window(.root))
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
private func presentAttachmentMenu(editMediaOptions: MessageMediaEditingOptions?, editMediaReference: AnyMediaReference?, botId: PeerId? = nil, botPayload: String? = nil, botJustInstalled: Bool = false) {
|
||||
guard let peer = self.presentationInterfaceState.renderedPeer?.peer else {
|
||||
return
|
||||
@ -12876,7 +13017,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
completion(controller, controller?.mediaPickerContext)
|
||||
strongSelf.controllerNavigationDisposable.set(nil)
|
||||
case let .app(bot, botName, _):
|
||||
let params = WebAppParameters(peerId: peer.id, botId: bot.id, botName: botName, url: nil, queryId: nil, payload: botPayload, buttonText: nil, keepAliveSignal: nil, fromMenu: false, isSimple: false)
|
||||
let params = WebAppParameters(peerId: peer.id, botId: bot.id, botName: botName, url: nil, queryId: nil, payload: botPayload, buttonText: nil, keepAliveSignal: nil, fromMenu: false, isInline: false, isSimple: false)
|
||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||
let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, replyToMessageId: replyMessageId, threadId: strongSelf.chatLocation.threadId)
|
||||
controller.openUrl = { [weak self] url in
|
||||
@ -14408,7 +14549,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
|
||||
private func enqueueMediaMessages(signals: [Any]?, silentPosting: Bool, scheduleTime: Int32? = nil, getAnimatedTransitionSource: ((String) -> UIView?)? = nil, completion: @escaping () -> Void = {}) {
|
||||
self.enqueueMediaMessageDisposable.set((legacyAssetPickerEnqueueMessages(account: self.context.account, signals: signals!)
|
||||
self.enqueueMediaMessageDisposable.set((legacyAssetPickerEnqueueMessages(context: self.context, account: self.context.account, signals: signals!)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] items in
|
||||
if let strongSelf = self {
|
||||
var completionImpl: (() -> Void)? = completion
|
||||
@ -16262,6 +16403,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if let navigationController = self.effectiveNavigationController {
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peer), attachBotStart: attachBotStart))
|
||||
}
|
||||
case let .withBotApp(botAppStart):
|
||||
if let navigationController = self.effectiveNavigationController {
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peer), botAppStart: botAppStart))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -16741,6 +16886,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if let navigationController = strongSelf.effectiveNavigationController {
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), attachBotStart: attachBotStart))
|
||||
}
|
||||
case let .withBotApp(botAppStart):
|
||||
strongSelf.presentBotApp(botApp: botAppStart.botApp, payload: botAppStart.payload)
|
||||
default:
|
||||
break
|
||||
}
|
||||
@ -17647,24 +17794,26 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
|
||||
private func openPinnedMessages(at messageId: MessageId?) {
|
||||
guard let navigationController = self.effectiveNavigationController, navigationController.topViewController == self else {
|
||||
return
|
||||
}
|
||||
let controller = ChatControllerImpl(context: self.context, chatLocation: self.chatLocation, subject: .pinnedMessages(id: messageId))
|
||||
controller.navigationPresentation = .modal
|
||||
controller.updatedClosedPinnedMessageId = { [weak self] pinnedMessageId in
|
||||
guard let strongSelf = self else {
|
||||
let _ = self.presentVoiceMessageDiscardAlert(action: { [weak self] in
|
||||
guard let self, let navigationController = self.effectiveNavigationController, navigationController.topViewController == self else {
|
||||
return
|
||||
}
|
||||
strongSelf.performUpdatedClosedPinnedMessageId(pinnedMessageId: pinnedMessageId)
|
||||
}
|
||||
controller.requestedUnpinAllMessages = { [weak self] count, pinnedMessageId in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
let controller = ChatControllerImpl(context: self.context, chatLocation: self.chatLocation, subject: .pinnedMessages(id: messageId))
|
||||
controller.navigationPresentation = .modal
|
||||
controller.updatedClosedPinnedMessageId = { [weak self] pinnedMessageId in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.performUpdatedClosedPinnedMessageId(pinnedMessageId: pinnedMessageId)
|
||||
}
|
||||
strongSelf.performRequestedUnpinAllMessages(count: count, pinnedMessageId: pinnedMessageId)
|
||||
}
|
||||
navigationController.pushViewController(controller)
|
||||
controller.requestedUnpinAllMessages = { [weak self] count, pinnedMessageId in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.performRequestedUnpinAllMessages(count: count, pinnedMessageId: pinnedMessageId)
|
||||
}
|
||||
navigationController.pushViewController(controller)
|
||||
})
|
||||
}
|
||||
|
||||
private func performUpdatedClosedPinnedMessageId(pinnedMessageId: MessageId) {
|
||||
|
@ -154,7 +154,7 @@ func inputContextPanelForChatPresentationIntefaceState(_ chatPresentationInterfa
|
||||
return nil
|
||||
}
|
||||
case let .contextRequestResult(_, results):
|
||||
if let results = results, (!results.results.isEmpty || results.switchPeer != nil) {
|
||||
if let results = results, (!results.results.isEmpty || results.switchPeer != nil || results.webView != nil) {
|
||||
switch results.presentation {
|
||||
case .list:
|
||||
if let currentPanel = currentPanel as? VerticalListContextResultsChatInputContextPanelNode {
|
||||
|
@ -118,7 +118,6 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
|
||||
let labelNode: TextNode
|
||||
let backgroundNode: NavigationBackgroundNode
|
||||
let stickBackgroundNode: ASImageNode
|
||||
let activateArea: AccessibilityAreaNode
|
||||
|
||||
private var backgroundContent: WallpaperBubbleBackgroundNode?
|
||||
|
||||
@ -191,9 +190,6 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
|
||||
}
|
||||
self.text = text
|
||||
|
||||
self.activateArea = AccessibilityAreaNode()
|
||||
self.activateArea.accessibilityTraits = .staticText
|
||||
|
||||
super.init(layerBacked: false, dynamicBounce: true, isRotated: true, seeThrough: false)
|
||||
|
||||
self.transform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0)
|
||||
@ -212,16 +208,12 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
|
||||
self.addSubnode(self.backgroundNode)
|
||||
}
|
||||
self.addSubnode(self.labelNode)
|
||||
|
||||
self.addSubnode(self.activateArea)
|
||||
|
||||
|
||||
let titleFont = Font.medium(min(18.0, floor(presentationData.fontSize.baseDisplaySize * 13.0 / 17.0)))
|
||||
|
||||
let attributedString = NSAttributedString(string: text, font: titleFont, textColor: bubbleVariableColor(variableColor: presentationData.theme.theme.chat.serviceMessage.dateTextColor, wallpaper: presentationData.theme.wallpaper))
|
||||
let labelLayout = TextNode.asyncLayout(self.labelNode)
|
||||
|
||||
self.activateArea.accessibilityLabel = text
|
||||
|
||||
|
||||
let (size, apply) = labelLayout(TextNodeLayoutArguments(attributedString: attributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 320.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
let _ = apply()
|
||||
self.labelNode.frame = CGRect(origin: CGPoint(), size: size.size)
|
||||
@ -285,9 +277,7 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
|
||||
self.backgroundNode.frame = backgroundFrame
|
||||
self.backgroundNode.update(size: backgroundFrame.size, cornerRadius: backgroundFrame.size.height / 2.0, transition: .immediate)
|
||||
self.labelNode.frame = CGRect(origin: CGPoint(x: backgroundFrame.origin.x + chatDateInset, y: backgroundFrame.origin.y + floorToScreenPixels((backgroundSize.height - labelSize.height) / 2.0)), size: labelSize)
|
||||
|
||||
self.activateArea.frame = backgroundFrame
|
||||
|
||||
|
||||
if let backgroundContent = self.backgroundContent {
|
||||
backgroundContent.allowsGroupOpacity = true
|
||||
self.backgroundNode.isHidden = true
|
||||
|
@ -897,7 +897,7 @@ public class ChatMessageItemView: ListViewItemNode, ChatMessageItemNodeProtocol
|
||||
}
|
||||
})
|
||||
case let .openWebView(url, simple):
|
||||
item.controllerInteraction.openWebView(button.title, url, simple, false)
|
||||
item.controllerInteraction.openWebView(button.title, url, simple, .generic)
|
||||
case .requestPeer:
|
||||
break
|
||||
}
|
||||
|
@ -900,7 +900,7 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
|
||||
}
|
||||
})
|
||||
case let .openWebView(url, simple):
|
||||
controllerInteraction.openWebView(button.title, url, simple, false)
|
||||
controllerInteraction.openWebView(button.title, url, simple, .generic)
|
||||
case .requestPeer:
|
||||
break
|
||||
}
|
||||
|
@ -3637,7 +3637,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
} else if case let .webView(title, url) = presentationInterfaceState.botMenuButton {
|
||||
let willShow = !(self.presentationInterfaceState?.showWebView ?? false)
|
||||
if willShow {
|
||||
self.interfaceInteraction?.openWebView(title, url, false, true)
|
||||
self.interfaceInteraction?.openWebView(title, url, false, .menu)
|
||||
} else {
|
||||
self.interfaceInteraction?.updateShowWebView { _ in
|
||||
return false
|
||||
|
@ -292,7 +292,7 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont
|
||||
existingIds.insert(result.id)
|
||||
}
|
||||
}
|
||||
let mergedResults = ChatContextResultCollection(botId: currentProcessedResults.botId, peerId: currentProcessedResults.peerId, query: currentProcessedResults.query, geoPoint: currentProcessedResults.geoPoint, queryId: nextResults.queryId, nextOffset: nextResults.nextOffset, presentation: currentProcessedResults.presentation, switchPeer: currentProcessedResults.switchPeer, results: results, cacheTimeout: currentProcessedResults.cacheTimeout)
|
||||
let mergedResults = ChatContextResultCollection(botId: currentProcessedResults.botId, peerId: currentProcessedResults.peerId, query: currentProcessedResults.query, geoPoint: currentProcessedResults.geoPoint, queryId: nextResults.queryId, nextOffset: nextResults.nextOffset, presentation: currentProcessedResults.presentation, switchPeer: currentProcessedResults.switchPeer, webView: currentProcessedResults.webView, results: results, cacheTimeout: currentProcessedResults.cacheTimeout)
|
||||
strongSelf.currentProcessedResults = mergedResults
|
||||
strongSelf.updateInternalResults(mergedResults)
|
||||
}))
|
||||
|
@ -244,7 +244,7 @@ func presentedLegacyShortcutCamera(context: AccountContext, saveCapturedMedia: B
|
||||
})
|
||||
if let parentController = parentController {
|
||||
parentController.present(ShareController(context: context, subject: .fromExternal({ peerIds, _, text, account, silently in
|
||||
return legacyAssetPickerEnqueueMessages(account: account, signals: signals!)
|
||||
return legacyAssetPickerEnqueueMessages(context: context, account: account, signals: signals!)
|
||||
|> `catch` { _ -> Signal<[LegacyAssetPickerEnqueueMessage], ShareControllerError> in
|
||||
return .single([])
|
||||
}
|
||||
|
@ -132,8 +132,11 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam
|
||||
if let attachBotStart = params.attachBotStart {
|
||||
controller.presentAttachmentBot(botId: attachBotStart.botId, payload: attachBotStart.payload, justInstalled: attachBotStart.justInstalled)
|
||||
}
|
||||
if let botAppStart = params.botAppStart {
|
||||
controller.presentBotApp(botApp: botAppStart.botApp, payload: botAppStart.payload)
|
||||
}
|
||||
} else {
|
||||
controller = ChatControllerImpl(context: params.context, chatLocation: params.chatLocation.asChatLocation, chatLocationContextHolder: params.chatLocationContextHolder, subject: params.subject, botStart: params.botStart, attachBotStart: params.attachBotStart, peekData: params.peekData, peerNearbyData: params.peerNearbyData, chatListFilter: params.chatListFilter, chatNavigationStack: params.chatNavigationStack)
|
||||
controller = ChatControllerImpl(context: params.context, chatLocation: params.chatLocation.asChatLocation, chatLocationContextHolder: params.chatLocationContextHolder, subject: params.subject, botStart: params.botStart, attachBotStart: params.attachBotStart, botAppStart: params.botAppStart, peekData: params.peekData, peerNearbyData: params.peerNearbyData, chatListFilter: params.chatListFilter, chatNavigationStack: params.chatNavigationStack)
|
||||
}
|
||||
controller.purposefulAction = params.purposefulAction
|
||||
if let search = params.activateMessageSearch {
|
||||
|
@ -687,6 +687,8 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
||||
var startAttach: String?
|
||||
var choose: String?
|
||||
var threadId: Int64?
|
||||
var appName: String?
|
||||
var startApp: String?
|
||||
if let queryItems = components.queryItems {
|
||||
for queryItem in queryItems {
|
||||
if let value = queryItem.value {
|
||||
@ -714,6 +716,10 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
||||
choose = value
|
||||
} else if queryItem.name == "thread" {
|
||||
threadId = Int64(value)
|
||||
} else if queryItem.name == "appname" {
|
||||
appName = value
|
||||
} else if queryItem.name == "startapp" {
|
||||
startApp = value
|
||||
}
|
||||
} else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) {
|
||||
voiceChat = ""
|
||||
@ -731,13 +737,19 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
||||
convertedUrl = "https://t.me/+\(phone)"
|
||||
} else if let domain = domain {
|
||||
var result = "https://t.me/\(domain)"
|
||||
if let threadId = threadId {
|
||||
if let appName {
|
||||
result += "\(appName)"
|
||||
}
|
||||
if let startApp {
|
||||
result += "?startapp=\(startApp)"
|
||||
}
|
||||
if let threadId {
|
||||
result += "/\(threadId)"
|
||||
if let post = post, let postValue = Int(post) {
|
||||
if let post, let postValue = Int(post) {
|
||||
result += "/\(postValue)"
|
||||
}
|
||||
} else {
|
||||
if let post = post, let postValue = Int(post) {
|
||||
if let post, let postValue = Int(post) {
|
||||
result += "/\(postValue)"
|
||||
}
|
||||
}
|
||||
|
@ -3980,7 +3980,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
return nil
|
||||
}, sendMessagesWithSignals: { [weak self] signals, _, _ in
|
||||
if let strongSelf = self {
|
||||
strongSelf.enqueueMediaMessageDisposable.set((legacyAssetPickerEnqueueMessages(account: strongSelf.context.account, signals: signals!)
|
||||
strongSelf.enqueueMediaMessageDisposable.set((legacyAssetPickerEnqueueMessages(context: strongSelf.context, account: strongSelf.context.account, signals: signals!)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] messages in
|
||||
if let strongSelf = self {
|
||||
let _ = enqueueMessages(account: strongSelf.context.account, peerId: strongSelf.peerId, messages: messages.map { $0.message }).start()
|
||||
@ -4019,6 +4019,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer), botStart: startPayload))
|
||||
case let .withAttachBot(attachBotStart):
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer), attachBotStart: attachBotStart))
|
||||
case let .withBotApp(botAppStart):
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer), botAppStart: botAppStart))
|
||||
default:
|
||||
break
|
||||
}
|
||||
@ -4101,6 +4103,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
if let navigationController = self.controller?.navigationController as? NavigationController {
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peer), attachBotStart: attachBotStart))
|
||||
}
|
||||
case let .withBotApp(botAppStart):
|
||||
if let navigationController = self.controller?.navigationController as? NavigationController {
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peer), botAppStart: botAppStart))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -4332,9 +4338,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
guard let strongSelf = self, let peer = strongSelf.data?.peer else {
|
||||
return
|
||||
}
|
||||
let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: strongSelf.chatLocation.threadId, muteInterval: value).start()
|
||||
|
||||
strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_mute_for", scale: 0.066, colors: [:], title: nil, text: strongSelf.presentationData.strings.PeerInfo_TooltipMutedFor(mutedForTimeIntervalString(strings: strongSelf.presentationData.strings, value: value)).string, customUndoText: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
|
@ -187,6 +187,11 @@ final class VerticalListContextResultsChatInputContextPanelNode: ChatInputContex
|
||||
entries.append(entry)
|
||||
resultIds.insert(entry.stableId)
|
||||
}
|
||||
if let webView = results.webView {
|
||||
let entry: VerticalListContextResultsChatInputContextPanelEntry = .action(self.theme, webView.text)
|
||||
entries.append(entry)
|
||||
resultIds.insert(entry.stableId)
|
||||
}
|
||||
for result in results.results {
|
||||
let entry: VerticalListContextResultsChatInputContextPanelEntry = .result(index, self.theme, result)
|
||||
if resultIds.contains(entry.stableId) {
|
||||
@ -204,8 +209,17 @@ final class VerticalListContextResultsChatInputContextPanelNode: ChatInputContex
|
||||
private func prepareTransition(from: [VerticalListContextResultsChatInputContextPanelEntry]?, to: [VerticalListContextResultsChatInputContextPanelEntry], results: ChatContextResultCollection) {
|
||||
let firstTime = self.currentEntries == nil
|
||||
let transition = preparedTransition(from: from ?? [], to: to, account: self.context.account, actionSelected: { [weak self] in
|
||||
if let strongSelf = self, let interfaceInteraction = strongSelf.interfaceInteraction, let switchPeer = results.switchPeer {
|
||||
interfaceInteraction.botSwitchChatWithPayload(results.botId, switchPeer.startParam)
|
||||
if let strongSelf = self, let interfaceInteraction = strongSelf.interfaceInteraction {
|
||||
if let switchPeer = results.switchPeer {
|
||||
interfaceInteraction.botSwitchChatWithPayload(results.botId, switchPeer.startParam)
|
||||
} else if let webView = results.webView {
|
||||
let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: results.botId))
|
||||
|> deliverOnMainQueue).start(next: { bot in
|
||||
if let bot {
|
||||
interfaceInteraction.openWebView(webView.text, webView.url, true, .inline(bot: bot))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}, resultSelected: { [weak self] result, node, rect in
|
||||
if let strongSelf = self, let interfaceInteraction = strongSelf.interfaceInteraction {
|
||||
@ -241,7 +255,7 @@ final class VerticalListContextResultsChatInputContextPanelNode: ChatInputContex
|
||||
}
|
||||
|
||||
var insets = UIEdgeInsets()
|
||||
insets.top = topInsetForLayout(size: validLayout.0, hasSwitchPeer: self.currentExternalResults?.switchPeer != nil)
|
||||
insets.top = topInsetForLayout(size: validLayout.0, hasSwitchPeer: self.currentExternalResults?.switchPeer != nil || self.currentExternalResults?.webView != nil)
|
||||
insets.left = validLayout.1
|
||||
insets.right = validLayout.2
|
||||
|
||||
@ -284,7 +298,7 @@ final class VerticalListContextResultsChatInputContextPanelNode: ChatInputContex
|
||||
self.validLayout = (size, leftInset, rightInset, bottomInset)
|
||||
|
||||
var insets = UIEdgeInsets()
|
||||
insets.top = self.topInsetForLayout(size: size, hasSwitchPeer: self.currentExternalResults?.switchPeer != nil)
|
||||
insets.top = self.topInsetForLayout(size: size, hasSwitchPeer: self.currentExternalResults?.switchPeer != nil || self.currentExternalResults?.webView != nil)
|
||||
insets.left = leftInset
|
||||
insets.right = rightInset
|
||||
|
||||
@ -362,7 +376,7 @@ final class VerticalListContextResultsChatInputContextPanelNode: ChatInputContex
|
||||
existingIds.insert(result.id)
|
||||
}
|
||||
}
|
||||
let mergedResults = ChatContextResultCollection(botId: currentProcessedResults.botId, peerId: currentProcessedResults.peerId, query: currentProcessedResults.query, geoPoint: currentProcessedResults.geoPoint, queryId: nextResults.queryId, nextOffset: nextResults.nextOffset, presentation: currentProcessedResults.presentation, switchPeer: currentProcessedResults.switchPeer, results: results, cacheTimeout: currentProcessedResults.cacheTimeout)
|
||||
let mergedResults = ChatContextResultCollection(botId: currentProcessedResults.botId, peerId: currentProcessedResults.peerId, query: currentProcessedResults.query, geoPoint: currentProcessedResults.geoPoint, queryId: nextResults.queryId, nextOffset: nextResults.nextOffset, presentation: currentProcessedResults.presentation, switchPeer: currentProcessedResults.switchPeer, webView: currentProcessedResults.webView, results: results, cacheTimeout: currentProcessedResults.cacheTimeout)
|
||||
strongSelf.currentProcessedResults = mergedResults
|
||||
strongSelf.updateInternalResults(mergedResults)
|
||||
}))
|
||||
|
@ -13,15 +13,17 @@ public struct StickerSettings: Codable, Equatable {
|
||||
public var emojiStickerSuggestionMode: EmojiStickerSuggestionMode
|
||||
public var loopAnimatedStickers: Bool
|
||||
public var suggestAnimatedEmoji: Bool
|
||||
public var dynamicPackOrder: Bool
|
||||
|
||||
public static var defaultSettings: StickerSettings {
|
||||
return StickerSettings(emojiStickerSuggestionMode: .all, loopAnimatedStickers: true, suggestAnimatedEmoji: true)
|
||||
return StickerSettings(emojiStickerSuggestionMode: .all, loopAnimatedStickers: true, suggestAnimatedEmoji: true, dynamicPackOrder: true)
|
||||
}
|
||||
|
||||
init(emojiStickerSuggestionMode: EmojiStickerSuggestionMode, loopAnimatedStickers: Bool, suggestAnimatedEmoji: Bool) {
|
||||
init(emojiStickerSuggestionMode: EmojiStickerSuggestionMode, loopAnimatedStickers: Bool, suggestAnimatedEmoji: Bool, dynamicPackOrder: Bool) {
|
||||
self.emojiStickerSuggestionMode = emojiStickerSuggestionMode
|
||||
self.loopAnimatedStickers = loopAnimatedStickers
|
||||
self.suggestAnimatedEmoji = suggestAnimatedEmoji
|
||||
self.dynamicPackOrder = dynamicPackOrder
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
@ -30,6 +32,7 @@ public struct StickerSettings: Codable, Equatable {
|
||||
self.emojiStickerSuggestionMode = EmojiStickerSuggestionMode(rawValue: try container.decode(Int32.self, forKey: "emojiStickerSuggestionMode"))!
|
||||
self.loopAnimatedStickers = try container.decodeIfPresent(Bool.self, forKey: "loopAnimatedStickers") ?? true
|
||||
self.suggestAnimatedEmoji = try container.decodeIfPresent(Bool.self, forKey: "suggestAnimatedEmoji") ?? true
|
||||
self.dynamicPackOrder = try container.decodeIfPresent(Bool.self, forKey: "dynamicPackOrder") ?? true
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
@ -38,22 +41,27 @@ public struct StickerSettings: Codable, Equatable {
|
||||
try container.encode(self.emojiStickerSuggestionMode.rawValue, forKey: "emojiStickerSuggestionMode")
|
||||
try container.encode(self.loopAnimatedStickers, forKey: "loopAnimatedStickers")
|
||||
try container.encode(self.suggestAnimatedEmoji, forKey: "suggestAnimatedEmoji")
|
||||
try container.encode(self.dynamicPackOrder, forKey: "dynamicPackOrder")
|
||||
}
|
||||
|
||||
public static func ==(lhs: StickerSettings, rhs: StickerSettings) -> Bool {
|
||||
return lhs.emojiStickerSuggestionMode == rhs.emojiStickerSuggestionMode && lhs.loopAnimatedStickers == rhs.loopAnimatedStickers && lhs.suggestAnimatedEmoji == rhs.suggestAnimatedEmoji
|
||||
return lhs.emojiStickerSuggestionMode == rhs.emojiStickerSuggestionMode && lhs.loopAnimatedStickers == rhs.loopAnimatedStickers && lhs.suggestAnimatedEmoji == rhs.suggestAnimatedEmoji && lhs.dynamicPackOrder == rhs.dynamicPackOrder
|
||||
}
|
||||
|
||||
public func withUpdatedEmojiStickerSuggestionMode(_ emojiStickerSuggestionMode: EmojiStickerSuggestionMode) -> StickerSettings {
|
||||
return StickerSettings(emojiStickerSuggestionMode: emojiStickerSuggestionMode, loopAnimatedStickers: self.loopAnimatedStickers, suggestAnimatedEmoji: self.suggestAnimatedEmoji)
|
||||
return StickerSettings(emojiStickerSuggestionMode: emojiStickerSuggestionMode, loopAnimatedStickers: self.loopAnimatedStickers, suggestAnimatedEmoji: self.suggestAnimatedEmoji, dynamicPackOrder: self.dynamicPackOrder)
|
||||
}
|
||||
|
||||
public func withUpdatedLoopAnimatedStickers(_ loopAnimatedStickers: Bool) -> StickerSettings {
|
||||
return StickerSettings(emojiStickerSuggestionMode: self.emojiStickerSuggestionMode, loopAnimatedStickers: loopAnimatedStickers, suggestAnimatedEmoji: self.suggestAnimatedEmoji)
|
||||
return StickerSettings(emojiStickerSuggestionMode: self.emojiStickerSuggestionMode, loopAnimatedStickers: loopAnimatedStickers, suggestAnimatedEmoji: self.suggestAnimatedEmoji, dynamicPackOrder: self.dynamicPackOrder)
|
||||
}
|
||||
|
||||
public func withUpdatedSuggestAnimatedEmoji(_ suggestAnimatedEmoji: Bool) -> StickerSettings {
|
||||
return StickerSettings(emojiStickerSuggestionMode: self.emojiStickerSuggestionMode, loopAnimatedStickers: self.loopAnimatedStickers, suggestAnimatedEmoji: suggestAnimatedEmoji)
|
||||
return StickerSettings(emojiStickerSuggestionMode: self.emojiStickerSuggestionMode, loopAnimatedStickers: self.loopAnimatedStickers, suggestAnimatedEmoji: suggestAnimatedEmoji, dynamicPackOrder: self.dynamicPackOrder)
|
||||
}
|
||||
|
||||
public func withUpdatedDynamicPackOrder(_ dynamicPackOrder: Bool) -> StickerSettings {
|
||||
return StickerSettings(emojiStickerSuggestionMode: self.emojiStickerSuggestionMode, loopAnimatedStickers: self.loopAnimatedStickers, suggestAnimatedEmoji: self.suggestAnimatedEmoji, dynamicPackOrder: dynamicPackOrder)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,6 +71,7 @@ public enum ParsedInternalPeerUrlParameter {
|
||||
case channelMessage(Int32, Double?)
|
||||
case replyThread(Int32, Int32)
|
||||
case voiceChat(String?)
|
||||
case appStart(String, String?)
|
||||
}
|
||||
|
||||
public enum ParsedInternalUrl {
|
||||
@ -510,6 +511,19 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
|
||||
} else {
|
||||
return .peer(.name(peerName), .channelMessage(value, timecode))
|
||||
}
|
||||
} else if pathComponents.count == 2 {
|
||||
let appName = pathComponents[1]
|
||||
var startApp: String?
|
||||
if let queryItems = components.queryItems {
|
||||
for queryItem in queryItems {
|
||||
if let value = queryItem.value {
|
||||
if queryItem.name == "startApp"{
|
||||
startApp = value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return .peer(.name(peerName), .appStart(appName, startApp))
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
@ -598,6 +612,20 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
|
||||
return .single(.peer(peer, .chat(textInputState: nil, subject: nil, peekData: nil)))
|
||||
}
|
||||
}
|
||||
case let .appStart(name, payload):
|
||||
return context.engine.messages.getBotApp(botId: peer.id, shortName: name, cached: false)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<BotApp?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> take(1)
|
||||
|> mapToSignal { botApp -> Signal<ResolvedUrl?, NoError> in
|
||||
if let botApp {
|
||||
return .single(.peer(peer, .withBotApp(ChatControllerInitialBotAppStart(botApp: botApp, payload: payload, justInstalled: false))))
|
||||
} else {
|
||||
return .single(.peer(peer, .chat(textInputState: nil, subject: nil, peekData: nil)))
|
||||
}
|
||||
}
|
||||
case let .channelMessage(id, timecode):
|
||||
if let channel = peer as? TelegramChannel, channel.flags.contains(.isForum) {
|
||||
let messageId = MessageId(peerId: channel.id, namespace: Namespaces.Message.Cloud, id: id)
|
||||
|
@ -629,7 +629,7 @@ class WebSearchControllerNode: ASDisplayNode {
|
||||
existingIds.insert(result.id)
|
||||
}
|
||||
}
|
||||
let mergedResults = ChatContextResultCollection(botId: currentProcessedResults.botId, peerId: currentProcessedResults.peerId, query: currentProcessedResults.query, geoPoint: currentProcessedResults.geoPoint, queryId: nextResults.results.queryId, nextOffset: nextResults.results.nextOffset, presentation: currentProcessedResults.presentation, switchPeer: currentProcessedResults.switchPeer, results: results, cacheTimeout: currentProcessedResults.cacheTimeout)
|
||||
let mergedResults = ChatContextResultCollection(botId: currentProcessedResults.botId, peerId: currentProcessedResults.peerId, query: currentProcessedResults.query, geoPoint: currentProcessedResults.geoPoint, queryId: nextResults.results.queryId, nextOffset: nextResults.results.nextOffset, presentation: currentProcessedResults.presentation, switchPeer: currentProcessedResults.switchPeer, webView: currentProcessedResults.webView, results: results, cacheTimeout: currentProcessedResults.cacheTimeout)
|
||||
strongSelf.currentProcessedResults = mergedResults
|
||||
strongSelf.results.set(mergedResults)
|
||||
}))
|
||||
|
@ -134,6 +134,7 @@ public struct WebAppParameters {
|
||||
let buttonText: String?
|
||||
let keepAliveSignal: Signal<Never, KeepWebViewError>?
|
||||
let fromMenu: Bool
|
||||
let isInline: Bool
|
||||
let isSimple: Bool
|
||||
|
||||
public init(
|
||||
@ -146,6 +147,7 @@ public struct WebAppParameters {
|
||||
buttonText: String?,
|
||||
keepAliveSignal: Signal<Never, KeepWebViewError>?,
|
||||
fromMenu: Bool,
|
||||
isInline: Bool,
|
||||
isSimple: Bool
|
||||
) {
|
||||
self.peerId = peerId
|
||||
@ -157,6 +159,7 @@ public struct WebAppParameters {
|
||||
self.buttonText = buttonText
|
||||
self.keepAliveSignal = keepAliveSignal
|
||||
self.fromMenu = fromMenu
|
||||
self.isInline = isInline
|
||||
self.isSimple = isSimple
|
||||
}
|
||||
}
|
||||
@ -186,7 +189,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
public var cancelPanGesture: () -> Void = { }
|
||||
public var isContainerPanning: () -> Bool = { return false }
|
||||
public var isContainerExpanded: () -> Bool = { return false }
|
||||
|
||||
|
||||
fileprivate class Node: ViewControllerTracingNode, WKNavigationDelegate, WKUIDelegate, UIScrollViewDelegate {
|
||||
private weak var controller: WebAppController?
|
||||
|
||||
@ -622,6 +625,15 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
switch eventName {
|
||||
case "web_app_ready":
|
||||
self.animateTransitionIn()
|
||||
case "web_app_switch_inline_query":
|
||||
if controller.isInline, let json, let query = json["query"] as? String {
|
||||
controller.dismiss()
|
||||
if let chatTypes = json["chat_types"] as? [String], !chatTypes.isEmpty {
|
||||
controller.requestSwitchInline(query, .user(.init(isBot: nil, isPremium: nil)))
|
||||
} else {
|
||||
controller.requestSwitchInline(query, nil)
|
||||
}
|
||||
}
|
||||
case "web_app_data_send":
|
||||
if controller.isSimple, let eventData = body["eventData"] as? String {
|
||||
self.handleSendData(data: eventData)
|
||||
@ -1029,6 +1041,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
private let payload: String?
|
||||
private let buttonText: String?
|
||||
private let fromMenu: Bool
|
||||
private let isInline: Bool
|
||||
private let isSimple: Bool
|
||||
private let keepAliveSignal: Signal<Never, KeepWebViewError>?
|
||||
private let replyToMessageId: MessageId?
|
||||
@ -1041,7 +1054,8 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
public var openUrl: (String) -> Void = { _ in }
|
||||
public var getNavigationController: () -> NavigationController? = { return nil }
|
||||
public var completion: () -> Void = {}
|
||||
|
||||
public var requestSwitchInline: (String, ReplyMarkupButtonRequestPeerType?) -> Void = { _, _ in }
|
||||
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, params: WebAppParameters, replyToMessageId: MessageId?, threadId: Int64?) {
|
||||
self.context = context
|
||||
self.peerId = params.peerId
|
||||
@ -1052,6 +1066,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
self.payload = params.payload
|
||||
self.buttonText = params.buttonText
|
||||
self.fromMenu = params.fromMenu
|
||||
self.isInline = params.isInline
|
||||
self.isSimple = params.isSimple
|
||||
self.keepAliveSignal = params.keepAliveSignal
|
||||
self.replyToMessageId = replyToMessageId
|
||||
@ -1334,7 +1349,7 @@ private final class WebAppContextReferenceContentSource: ContextReferenceContent
|
||||
}
|
||||
}
|
||||
|
||||
public func standaloneWebAppController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, params: WebAppParameters, threadId: Int64?, openUrl: @escaping (String) -> Void, getInputContainerNode: @escaping () -> (CGFloat, ASDisplayNode, () -> AttachmentController.InputPanelTransition?)? = { return nil }, completion: @escaping () -> Void = {}, willDismiss: @escaping () -> Void = {}, didDismiss: @escaping () -> Void = {}, getNavigationController: @escaping () -> NavigationController? = { return nil }, getSourceRect: (() -> CGRect?)? = nil) -> ViewController {
|
||||
public func standaloneWebAppController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, params: WebAppParameters, threadId: Int64?, openUrl: @escaping (String) -> Void, requestSwitchInline: @escaping (String, ReplyMarkupButtonRequestPeerType?) -> Void = { _, _ in }, getInputContainerNode: @escaping () -> (CGFloat, ASDisplayNode, () -> AttachmentController.InputPanelTransition?)? = { return nil }, completion: @escaping () -> Void = {}, willDismiss: @escaping () -> Void = {}, didDismiss: @escaping () -> Void = {}, getNavigationController: @escaping () -> NavigationController? = { return nil }, getSourceRect: (() -> CGRect?)? = nil) -> ViewController {
|
||||
let controller = AttachmentController(context: context, updatedPresentationData: updatedPresentationData, chatLocation: .peer(id: params.peerId), buttons: [.standalone], initialButton: .standalone, fromMenu: params.fromMenu, hasTextInput: false, makeEntityInputView: {
|
||||
return nil
|
||||
})
|
||||
@ -1344,6 +1359,7 @@ public func standaloneWebAppController(context: AccountContext, updatedPresentat
|
||||
webAppController.openUrl = openUrl
|
||||
webAppController.completion = completion
|
||||
webAppController.getNavigationController = getNavigationController
|
||||
webAppController.requestSwitchInline = requestSwitchInline
|
||||
present(webAppController, webAppController.mediaPickerContext)
|
||||
}
|
||||
controller.willDismiss = willDismiss
|
||||
|
Loading…
x
Reference in New Issue
Block a user