Poll improvements

This commit is contained in:
Ali 2020-04-14 17:18:03 +04:00
parent f78dba1ddc
commit b3266c8273
22 changed files with 2944 additions and 1499 deletions

View file

@ -2152,6 +2152,7 @@
"Notification.GameScoreSelfSimple_0" = "scored %@";
"Stickers.Install" = "ADD";
"Stickers.Installed" = "ADDED";
"MaskStickerSettings.Title" = "Masks";
"MaskStickerSettings.Info" = "You can add masks to photos and videos you send. To do this, open the photo editor before sending a photo or video.";

View file

@ -87,7 +87,7 @@ private final class AuthorizationSequenceCountrySelectionNavigationContentNode:
self?.cancel()
}
self.searchBar.textUpdated = { [weak self] query in
self.searchBar.textUpdated = { [weak self] query, _ in
self?.queryUpdated?(query)
}
}

View file

@ -31,7 +31,7 @@ final class LocationSearchNavigationContentNode: NavigationBarContentNode {
self?.searchBar.deactivate(clear: false)
self?.interaction.dismissSearch()
}
self.searchBar.textUpdated = { [weak self] query in
self.searchBar.textUpdated = { [weak self] query, _ in
self?.interaction.updateSearchQuery(query)
}
}

View file

@ -132,7 +132,7 @@ private final class ChannelDiscussionSearchNavigationContentNode: NavigationBarC
self?.cancel()
}
self.searchBar.textUpdated = { [weak self] query in
self.searchBar.textUpdated = { [weak self] query, _ in
self?.queryUpdated?(query)
}

View file

@ -45,7 +45,7 @@ final class GroupInfoSearchNavigationContentNode: NavigationBarContentNode, Item
self?.cancel()
}
self.searchBar.textUpdated = { [weak self] query in
self.searchBar.textUpdated = { [weak self] query, _ in
self?.queryUpdated?(query)
}

View file

@ -252,7 +252,7 @@ public enum SearchBarStyle {
public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
public var cancel: (() -> Void)?
public var textUpdated: ((String) -> Void)?
public var textUpdated: ((String, String?) -> Void)?
public var textReturned: ((String) -> Void)?
public var clearPrefix: (() -> Void)?
@ -338,9 +338,11 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
private let fieldStyle: SearchBarStyle
private var theme: SearchBarNodeTheme?
private var strings: PresentationStrings?
private let cancelText: String?
public init(theme: SearchBarNodeTheme, strings: PresentationStrings, fieldStyle: SearchBarStyle = .legacy) {
public init(theme: SearchBarNodeTheme, strings: PresentationStrings, fieldStyle: SearchBarStyle = .legacy, cancelText: String? = nil) {
self.fieldStyle = fieldStyle
self.cancelText = cancelText
self.backgroundNode = ASDisplayNode()
self.backgroundNode.isLayerBacked = true
@ -400,7 +402,7 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
public func updateThemeAndStrings(theme: SearchBarNodeTheme, strings: PresentationStrings) {
if self.theme != theme || self.strings !== strings {
self.cancelButton.setAttributedTitle(NSAttributedString(string: strings.Common_Cancel, font: Font.regular(17.0), textColor: theme.accent), for: [])
self.cancelButton.setAttributedTitle(NSAttributedString(string: self.cancelText ?? strings.Common_Cancel, font: self.cancelText != nil ? Font.semibold(17.0) : Font.regular(17.0), textColor: theme.accent), for: [])
}
if self.theme != theme {
self.backgroundNode.backgroundColor = theme.background
@ -623,7 +625,7 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
@objc private func textFieldDidChange(_ textField: UITextField) {
self.updateIsEmpty()
if let textUpdated = self.textUpdated {
textUpdated(textField.text ?? "")
textUpdated(textField.text ?? "", textField.textInputMode?.primaryLanguage)
}
}

View file

@ -27,7 +27,7 @@ public final class SearchDisplayController {
self.mode = mode
self.contentNode = contentNode
self.searchBar.textUpdated = { [weak contentNode] text in
self.searchBar.textUpdated = { [weak contentNode] text, _ in
contentNode?.searchTextUpdated(text: text)
}
self.searchBar.cancel = { [weak self] in

View file

@ -1066,7 +1066,7 @@ public enum StickerPackScreenPerformedAction {
}
public func StickerPackScreen(context: AccountContext, mode: StickerPackPreviewControllerMode = .default, mainStickerPack: StickerPackReference, stickerPacks: [StickerPackReference], parentNavigationController: NavigationController? = nil, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)? = nil, actionPerformed: ((StickerPackCollectionInfo, [ItemCollectionItem], StickerPackScreenPerformedAction) -> Void)? = nil) -> ViewController {
return StickerPackScreenImpl(context: context, stickerPacks: stickerPacks, selectedStickerPackIndex: stickerPacks.firstIndex(of: mainStickerPack) ?? 0, parentNavigationController: parentNavigationController, sendSticker: sendSticker)
//return StickerPackScreenImpl(context: context, stickerPacks: stickerPacks, selectedStickerPackIndex: stickerPacks.firstIndex(of: mainStickerPack) ?? 0, parentNavigationController: parentNavigationController, sendSticker: sendSticker)
let controller = StickerPackPreviewController(context: context, stickerPack: mainStickerPack, mode: mode, parentNavigationController: parentNavigationController, actionPerformed: actionPerformed)
controller.sendSticker = sendSticker

View file

@ -102,7 +102,7 @@ private func chatMessageStickerDatas(postbox: Postbox, file: TelegramMediaFile,
public func chatMessageAnimatedStickerDatas(postbox: Postbox, file: TelegramMediaFile, small: Bool, size: CGSize, fitzModifier: EmojiFitzModifier? = nil, fetched: Bool, onlyFullSize: Bool, synchronousLoad: Bool) -> Signal<Tuple3<Data?, Data?, Bool>, NoError> {
let thumbnailResource = chatMessageStickerResource(file: file, small: true)
let resource = chatMessageStickerResource(file: file, small: small)
let resource = chatMessageStickerResource(file: file, small: false)
let firstFrameRepresentation = CachedAnimatedStickerFirstFrameRepresentation(width: Int32(size.width), height: Int32(size.height), fitzModifier: fitzModifier)
let maybeFetched = postbox.mediaBox.cachedResourceRepresentation(resource, representation: firstFrameRepresentation, complete: false, fetch: false, attemptSynchronously: synchronousLoad)

View file

@ -143,22 +143,26 @@ func updateContacts(transaction: Transaction, apiUsers: [Api.User]) {
var contactIds = transaction.getContactPeerIds()
var updated = false
for user in apiUsers {
let isContact: Bool
var isContact: Bool?
switch user {
case let .user(user):
case let .user(user):
if (user.flags & (1 << 20)) == 0 {
isContact = (user.flags & (1 << 11)) != 0
case .userEmpty:
isContact = false
}
if isContact {
if !contactIds.contains(user.peerId) {
contactIds.insert(user.peerId)
updated = true
}
} else {
if contactIds.contains(user.peerId) {
contactIds.remove(user.peerId)
updated = true
case .userEmpty:
isContact = false
}
if let isContact = isContact {
if isContact {
if !contactIds.contains(user.peerId) {
contactIds.insert(user.peerId)
updated = true
}
} else {
if contactIds.contains(user.peerId) {
contactIds.remove(user.peerId)
updated = true
}
}
}
}

View file

@ -127,6 +127,7 @@ public enum PresentationResourceKey: Int32 {
case chatInputMediaPanelTrendingIconImage
case chatInputMediaPanelSettingsIconImage
case chatInputMediaPanelAddPackButtonImage
case chatInputMediaPanelAddedPackButtonImage
case chatInputMediaPanelGridSetupImage
case chatInputMediaPanelGridDismissImage

View file

@ -254,6 +254,12 @@ public struct PresentationResourcesChat {
})
}
public static func chatInputMediaPanelAddedPackButtonImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatInputMediaPanelAddedPackButtonImage.rawValue, { theme in
return generateStretchableFilledCircleImage(diameter: 28.0, color: theme.list.itemCheckColors.fillColor.withAlphaComponent(0.08), strokeColor: nil, strokeWidth: 1.0, backgroundColor: nil)
})
}
public static func chatInputMediaPanelGridSetupImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatInputMediaPanelGridSetupImage.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/GridSetupIcon"), color: theme.chat.inputMediaPanel.panelIconColor.withAlphaComponent(0.65))

View file

@ -166,8 +166,8 @@ private func preparedChatMediaInputGridEntryTransition(account: Account, view: I
private func chatMediaInputPanelEntries(view: ItemCollectionsView, savedStickers: OrderedItemListView?, recentStickers: OrderedItemListView?, peerSpecificPack: PeerSpecificPackData?, canInstallPeerSpecificPack: CanInstallPeerSpecificPack, hasUnreadTrending: Bool?, theme: PresentationTheme) -> [ChatMediaInputPanelEntry] {
var entries: [ChatMediaInputPanelEntry] = []
entries.append(.recentGifs(theme))
if let hasUnreadTrending = hasUnreadTrending, hasUnreadTrending {
entries.append(.trending(true, theme))
if let hasUnreadTrending = hasUnreadTrending {
entries.append(.trending(hasUnreadTrending, theme))
}
if let savedStickers = savedStickers, !savedStickers.items.isEmpty {
entries.append(.savedStickers(theme))
@ -211,9 +211,6 @@ private func chatMediaInputPanelEntries(view: ItemCollectionsView, savedStickers
entries.append(.peerSpecific(theme: theme, peer: peer))
}
if let hasUnreadTrending = hasUnreadTrending, !hasUnreadTrending {
entries.append(.trending(false, theme))
}
entries.append(.settings(theme))
return entries
}
@ -371,7 +368,7 @@ private func clipScrollPosition(_ position: StickerPacksCollectionPosition) -> S
private enum ChatMediaInputPaneType {
case gifs
case stickers
case trending
//case trending
}
private struct ChatMediaInputPaneArrangement {
@ -421,7 +418,7 @@ final class ChatMediaInputNode: ChatInputNode {
private var animatingStickerPaneOut = false
private let gifPane: ChatMediaInputGifPane
private var animatingGifPaneOut = false
private let trendingPane: ChatMediaInputTrendingPane
//private let trendingPane: ChatMediaInputTrendingPane
private var animatingTrendingPaneOut = false
private var panRecognizer: UIPanGestureRecognizer?
@ -494,11 +491,11 @@ final class ChatMediaInputNode: ChatInputNode {
})
var getItemIsPreviewedImpl: ((StickerPackItem) -> Bool)?
self.trendingPane = ChatMediaInputTrendingPane(context: context, controllerInteraction: controllerInteraction, getItemIsPreviewed: { item in
/*self.trendingPane = ChatMediaInputTrendingPane(context: context, controllerInteraction: controllerInteraction, getItemIsPreviewed: { item in
return getItemIsPreviewedImpl?(item) ?? false
}, isPane: true)
}, isPane: true)*/
self.paneArrangement = ChatMediaInputPaneArrangement(panes: [.gifs, .stickers, .trending], currentIndex: 1, indexTransition: 0.0)
self.paneArrangement = ChatMediaInputPaneArrangement(panes: [.gifs, .stickers, /*.trending*/], currentIndex: 1, indexTransition: 0.0)
super.init()
@ -508,7 +505,18 @@ final class ChatMediaInputNode: ChatInputNode {
if collectionId.namespace == ChatMediaInputPanelAuxiliaryNamespace.recentGifs.rawValue {
strongSelf.setCurrentPane(.gifs, transition: .animated(duration: 0.25, curve: .spring))
} else if collectionId.namespace == ChatMediaInputPanelAuxiliaryNamespace.trending.rawValue {
strongSelf.setCurrentPane(.trending, transition: .animated(duration: 0.25, curve: .spring))
strongSelf.controllerInteraction.navigationController()?.pushViewController(FeaturedStickersScreen(
context: strongSelf.context,
sendSticker: {
fileReference, sourceNode, sourceRect in
if let strongSelf = self {
return strongSelf.controllerInteraction.sendSticker(fileReference, false, sourceNode, sourceRect)
} else {
return false
}
}
))
//strongSelf.setCurrentPane(.trending, transition: .animated(duration: 0.25, curve: .spring))
} else if collectionId.namespace == ChatMediaInputPanelAuxiliaryNamespace.savedStickers.rawValue {
strongSelf.setCurrentPane(.stickers, transition: .animated(duration: 0.25, curve: .spring), collectionIdHint: collectionId.namespace)
strongSelf.currentStickerPacksCollectionPosition = .navigate(index: nil, collectionId: collectionId)
@ -823,7 +831,7 @@ final class ChatMediaInputNode: ChatInputNode {
strongSelf.initializedArrangement = true
var currentPane = strongSelf.paneArrangement.panes[strongSelf.paneArrangement.currentIndex]
if view.entries.isEmpty {
currentPane = .trending
//currentPane = .trending
}
if currentPane != strongSelf.paneArrangement.panes[strongSelf.paneArrangement.currentIndex] {
strongSelf.setCurrentPane(currentPane, transition: .immediate)
@ -878,7 +886,7 @@ final class ChatMediaInputNode: ChatInputNode {
self.stickerPane.inputNodeInteraction = self.inputNodeInteraction
self.gifPane.inputNodeInteraction = self.inputNodeInteraction
self.trendingPane.inputNodeInteraction = self.inputNodeInteraction
//self.trendingPane.inputNodeInteraction = self.inputNodeInteraction
paneDidScrollImpl = { [weak self] pane, state, transition in
self?.updatePaneDidScroll(pane: pane, state: state, transition: transition)
@ -943,7 +951,7 @@ final class ChatMediaInputNode: ChatInputNode {
self.stickerPane.updateThemeAndStrings(theme: theme, strings: strings)
self.gifPane.updateThemeAndStrings(theme: theme, strings: strings)
self.trendingPane.updateThemeAndStrings(theme: theme, strings: strings)
//self.trendingPane.updateThemeAndStrings(theme: theme, strings: strings)
self.themeAndStringsPromise.set(.single((theme, strings)))
}
@ -1038,7 +1046,7 @@ final class ChatMediaInputNode: ChatInputNode {
}
}
} else {
panes = [strongSelf.gifPane, strongSelf.stickerPane, strongSelf.trendingPane]
panes = [strongSelf.gifPane, strongSelf.stickerPane/*, strongSelf.trendingPane*/]
}
let panelPoint = strongSelf.view.convert(point, to: strongSelf.collectionListPanel.view)
if panelPoint.y < strongSelf.collectionListPanel.frame.maxY {
@ -1191,8 +1199,8 @@ final class ChatMediaInputNode: ChatInputNode {
} else if let collectionIdHint = collectionIdHint {
self.setHighlightedItemCollectionId(ItemCollectionId(namespace: collectionIdHint, id: 0))
}
case .trending:
self.setHighlightedItemCollectionId(ItemCollectionId(namespace: ChatMediaInputPanelAuxiliaryNamespace.trending.rawValue, id: 0))
/*case .trending:
self.setHighlightedItemCollectionId(ItemCollectionId(namespace: ChatMediaInputPanelAuxiliaryNamespace.trending.rawValue, id: 0))*/
}
/*if updatedTrendingPanelIsActive != previousTrendingPanelWasActive {
self.controllerInteraction.updateInputMode { current in
@ -1221,9 +1229,9 @@ final class ChatMediaInputNode: ChatInputNode {
self.inputNodeInteraction.highlightedItemCollectionId = collectionId
}
} else if collectionId.namespace == ChatMediaInputPanelAuxiliaryNamespace.trending.rawValue {
if self.paneArrangement.panes[self.paneArrangement.currentIndex] == .trending {
/*if self.paneArrangement.panes[self.paneArrangement.currentIndex] == .trending {
self.inputNodeInteraction.highlightedItemCollectionId = collectionId
}
}*/
} else {
self.inputNodeInteraction.highlightedStickerItemCollectionId = collectionId
if self.paneArrangement.panes[self.paneArrangement.currentIndex] == .stickers {
@ -1286,8 +1294,8 @@ final class ChatMediaInputNode: ChatInputNode {
return self.stickerPane.collectionListPanelOffset
case .gifs:
return self.gifPane.collectionListPanelOffset
case .trending:
return self.trendingPane.collectionListPanelOffset
/*case .trending:
return self.trendingPane.collectionListPanelOffset*/
}
}
@ -1369,7 +1377,7 @@ final class ChatMediaInputNode: ChatInputNode {
}
self.stickerPane.collectionListPanelOffset = 0.0
self.gifPane.collectionListPanelOffset = 0.0
self.trendingPane.collectionListPanelOffset = 0.0
//self.trendingPane.collectionListPanelOffset = 0.0
self.updateAppearanceTransition(transition: transition)
} else {
panelHeight = standardInputHeight
@ -1398,11 +1406,12 @@ final class ChatMediaInputNode: ChatInputNode {
}
}
case .trending:
self.trendingPane.gridNode.forEachItemNode { itemNode in
/*self.trendingPane.gridNode.forEachItemNode { itemNode in
if let itemNode = itemNode as? PaneSearchBarPlaceholderNode {
placeholderNode = itemNode
}
}
}*/
break
}
}
@ -1467,7 +1476,7 @@ final class ChatMediaInputNode: ChatInputNode {
self.stickerPane.layer.removeAnimation(forKey: "position")
transition.updateFrame(node: self.stickerPane, frame: paneFrame)
}
case .trending:
/*case .trending:
if self.trendingPane.supernode == nil {
self.insertSubnode(self.trendingPane, belowSubnode: self.collectionListContainer)
self.trendingPane.frame = CGRect(origin: CGPoint(x: width, y: 0.0), size: CGSize(width: width, height: panelHeight))
@ -1475,13 +1484,13 @@ final class ChatMediaInputNode: ChatInputNode {
if self.trendingPane.frame != paneFrame {
self.trendingPane.layer.removeAnimation(forKey: "position")
transition.updateFrame(node: self.trendingPane, frame: paneFrame)
}
}*/
}
}
self.gifPane.updateLayout(size: CGSize(width: width - leftInset - rightInset, height: panelHeight), topInset: 41.0, bottomInset: bottomInset, isExpanded: isExpanded, isVisible: isVisible, deviceMetrics: deviceMetrics, transition: transition)
self.stickerPane.updateLayout(size: CGSize(width: width - leftInset - rightInset, height: panelHeight), topInset: 41.0, bottomInset: bottomInset, isExpanded: isExpanded, isVisible: isVisible && visiblePanes.contains(where: { $0.0 == .stickers }), deviceMetrics: deviceMetrics, transition: transition)
self.trendingPane.updateLayout(size: CGSize(width: width - leftInset - rightInset, height: panelHeight), topInset: 41.0, bottomInset: bottomInset, isExpanded: isExpanded, isVisible: isVisible, deviceMetrics: deviceMetrics, transition: transition)
//self.trendingPane.updateLayout(size: CGSize(width: width - leftInset - rightInset, height: panelHeight), topInset: 41.0, bottomInset: bottomInset, isExpanded: isExpanded, isVisible: isVisible, deviceMetrics: deviceMetrics, transition: transition)
if self.gifPane.supernode != nil {
if !visiblePanes.contains(where: { $0.0 == .gifs }) {
@ -1533,7 +1542,7 @@ final class ChatMediaInputNode: ChatInputNode {
self.animatingStickerPaneOut = false
}
if self.trendingPane.supernode != nil {
/*if self.trendingPane.supernode != nil {
if !visiblePanes.contains(where: { $0.0 == .trending }) {
if case .animated = transition {
if !self.animatingTrendingPaneOut {
@ -1556,7 +1565,7 @@ final class ChatMediaInputNode: ChatInputNode {
}
} else {
self.animatingTrendingPaneOut = false
}
}*/
if !displaySearch, let searchContainerNode = self.searchContainerNode {
self.searchContainerNode = nil
@ -1576,12 +1585,13 @@ final class ChatMediaInputNode: ChatInputNode {
}
}
case .trending:
self.trendingPane.gridNode.forEachItemNode { itemNode in
/*self.trendingPane.gridNode.forEachItemNode { itemNode in
if let itemNode = itemNode as? PaneSearchBarPlaceholderNode {
placeholderNode = itemNode
}
}
paneIsEmpty = true
paneIsEmpty = true*/
break
}
}
if let placeholderNode = placeholderNode {
@ -1644,7 +1654,7 @@ final class ChatMediaInputNode: ChatInputNode {
}
self.searchContainerNode?.contentNode.updatePreviewing(animated: animated)
self.trendingPane.updatePreviewing(animated: animated)
//self.trendingPane.updatePreviewing(animated: animated)
}
}
@ -1661,11 +1671,11 @@ final class ChatMediaInputNode: ChatInputNode {
self.animatingStickerPaneOut = false
self.stickerPane.removeFromSupernode()
}
self.trendingPane.layer.removeAllAnimations()
/*self.trendingPane.layer.removeAllAnimations()
if self.animatingTrendingPaneOut {
self.animatingTrendingPaneOut = false
self.trendingPane.removeFromSupernode()
}
}*/
case .changed:
if let (width, leftInset, rightInset, bottomInset, standardInputHeight, inputHeight, maximumHeight, inputPanelHeight, interfaceState, deviceMetrics, isVisible) = self.validLayout {
let translationX = -recognizer.translation(in: self.view).x

View file

@ -39,7 +39,7 @@ final class ChatRecentActionsSearchNavigationContentNode: NavigationBarContentNo
self?.cancel()
}
self.searchBar.textUpdated = { [weak self] query in
self.searchBar.textUpdated = { [weak self] query, _ in
self?.queryUpdated?(query)
}
}

View file

@ -47,7 +47,7 @@ final class ChatSearchNavigationContentNode: NavigationBarContentNode {
self?.interaction.dismissMessageSearch()
}
self.searchBar.textUpdated = { [weak self] query in
self.searchBar.textUpdated = { [weak self] query, _ in
self?.interaction.updateMessageSearch(query)
}

File diff suppressed because it is too large Load diff

View file

@ -115,11 +115,12 @@ final class TrendingTopItemNode: ASDisplayNode {
self.addSubnode(animationNode)
self.animationNode = animationNode
}
let dimensions = item.file.dimensions ?? PixelDimensions(width: 512, height: 512)
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: account.postbox, file: item.file, small: false, size: fittedDimensions, synchronousLoad: synchronousLoads), attemptSynchronously: synchronousLoads)
animationNode.started = { [weak self] in
self?.imageNode.alpha = 0.0
}
let dimensions = item.file.dimensions ?? PixelDimensions(width: 512, height: 512)
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))
animationNode.setup(source: AnimatedStickerResourceSource(account: account, resource: item.file.resource), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .cached)
self.loadDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, fileReference: stickerPackFileReference(item.file), resource: item.file.resource).start())
} else {

View file

@ -19,11 +19,11 @@ import UndoUI
final class StickerPaneSearchInteraction {
let open: (StickerPackCollectionInfo) -> Void
let install: (StickerPackCollectionInfo, [ItemCollectionItem]) -> Void
let install: (StickerPackCollectionInfo, [ItemCollectionItem], Bool) -> Void
let sendSticker: (FileMediaReference, ASDisplayNode, CGRect) -> Void
let getItemIsPreviewed: (StickerPackItem) -> Bool
init(open: @escaping (StickerPackCollectionInfo) -> Void, install: @escaping (StickerPackCollectionInfo, [ItemCollectionItem]) -> Void, sendSticker: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Void, getItemIsPreviewed: @escaping (StickerPackItem) -> Bool) {
init(open: @escaping (StickerPackCollectionInfo) -> Void, install: @escaping (StickerPackCollectionInfo, [ItemCollectionItem], Bool) -> Void, sendSticker: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Void, getItemIsPreviewed: @escaping (StickerPackItem) -> Bool) {
self.open = open
self.install = install
self.sendSticker = sendSticker
@ -107,7 +107,7 @@ private enum StickerSearchEntry: Identifiable, Comparable {
return StickerPaneSearchGlobalItem(account: account, theme: theme, strings: strings, info: info, topItems: topItems, grid: false, topSeparator: topSeparator, installed: installed, unread: false, open: {
interaction.open(info)
}, install: {
interaction.install(info, topItems)
interaction.install(info, topItems, !installed)
}, getItemIsPreviewed: { item in
return interaction.getItemIsPreviewed(item)
})
@ -232,87 +232,93 @@ final class StickerPaneSearchContentNode: ASDisplayNode, PaneSearchContentNode {
})
strongSelf.controllerInteraction.presentController(controller, nil)
}
}, install: { [weak self] info, items in
}, install: { [weak self] info, items, install in
guard let strongSelf = self else {
return
}
let account = strongSelf.context.account
var installSignal = loadedStickerPack(postbox: strongSelf.context.account.postbox, network: strongSelf.context.account.network, reference: .id(id: info.id.id, accessHash: info.accessHash), forceActualized: false)
|> mapToSignal { result -> Signal<(StickerPackCollectionInfo, [ItemCollectionItem]), NoError> in
switch result {
case let .result(info, items, installed):
if installed {
return .complete()
} else {
return preloadedStickerPackThumbnail(account: account, info: info, items: items)
|> filter { $0 }
|> ignoreValues
|> then(
addStickerPackInteractively(postbox: strongSelf.context.account.postbox, info: info, items: items)
|> ignoreValues
)
|> mapToSignal { _ -> Signal<(StickerPackCollectionInfo, [ItemCollectionItem]), NoError> in
if install {
var installSignal = loadedStickerPack(postbox: strongSelf.context.account.postbox, network: strongSelf.context.account.network, reference: .id(id: info.id.id, accessHash: info.accessHash), forceActualized: false)
|> mapToSignal { result -> Signal<(StickerPackCollectionInfo, [ItemCollectionItem]), NoError> in
switch result {
case let .result(info, items, installed):
if installed {
return .complete()
} else {
return preloadedStickerPackThumbnail(account: account, info: info, items: items)
|> filter { $0 }
|> ignoreValues
|> then(
addStickerPackInteractively(postbox: strongSelf.context.account.postbox, info: info, items: items)
|> ignoreValues
)
|> mapToSignal { _ -> Signal<(StickerPackCollectionInfo, [ItemCollectionItem]), NoError> in
return .complete()
}
|> then(.single((info, items)))
}
|> then(.single((info, items)))
case .fetching:
break
case .none:
break
}
case .fetching:
break
case .none:
break
return .complete()
}
return .complete()
}
|> deliverOnMainQueue
let context = strongSelf.context
var cancelImpl: (() -> Void)?
let progressSignal = Signal<Never, NoError> { subscriber in
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: {
cancelImpl?()
}))
self?.controllerInteraction.presentController(controller, nil)
return ActionDisposable { [weak controller] in
Queue.mainQueue().async() {
controller?.dismiss()
}
}
}
|> runOn(Queue.mainQueue())
|> delay(0.12, queue: Queue.mainQueue())
let progressDisposable = progressSignal.start()
installSignal = installSignal
|> afterDisposed {
Queue.mainQueue().async {
progressDisposable.dispose()
}
}
cancelImpl = {
self?.installDisposable.set(nil)
}
|> deliverOnMainQueue
strongSelf.installDisposable.set(installSignal.start(next: { info, items in
guard let strongSelf = self else {
return
}
var animateInAsReplacement = false
if let navigationController = strongSelf.controllerInteraction.navigationController() {
for controller in navigationController.overlayControllers {
if let controller = controller as? UndoOverlayController {
controller.dismissWithCommitActionAndReplacementAnimation()
animateInAsReplacement = true
let context = strongSelf.context
var cancelImpl: (() -> Void)?
let progressSignal = Signal<Never, NoError> { subscriber in
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: {
cancelImpl?()
}))
self?.controllerInteraction.presentController(controller, nil)
return ActionDisposable { [weak controller] in
Queue.mainQueue().async() {
controller?.dismiss()
}
}
}
|> runOn(Queue.mainQueue())
|> delay(0.12, queue: Queue.mainQueue())
let progressDisposable = progressSignal.start()
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
strongSelf.controllerInteraction.navigationController()?.presentOverlay(controller: UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: presentationData.strings.StickerPackActionInfo_AddedTitle, text: presentationData.strings.StickerPackActionInfo_AddedText(info.title).0, undo: false, info: info, topItem: items.first, account: strongSelf.context.account), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { _ in
return true
installSignal = installSignal
|> afterDisposed {
Queue.mainQueue().async {
progressDisposable.dispose()
}
}
cancelImpl = {
self?.installDisposable.set(nil)
}
strongSelf.installDisposable.set(installSignal.start(next: { info, items in
guard let strongSelf = self else {
return
}
var animateInAsReplacement = false
if let navigationController = strongSelf.controllerInteraction.navigationController() {
for controller in navigationController.overlayControllers {
if let controller = controller as? UndoOverlayController {
controller.dismissWithCommitActionAndReplacementAnimation()
animateInAsReplacement = true
}
}
}
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
strongSelf.controllerInteraction.navigationController()?.presentOverlay(controller: UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: presentationData.strings.StickerPackActionInfo_AddedTitle, text: presentationData.strings.StickerPackActionInfo_AddedText(info.title).0, undo: false, info: info, topItem: items.first, account: strongSelf.context.account), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { _ in
return true
}))
}))
}))
} else {
let _ = (removeStickerPackInteractively(postbox: account.postbox, id: info.id, option: .delete)
|> deliverOnMainQueue).start(next: { _ in
})
}
}, sendSticker: { [weak self] file, sourceNode, sourceRect in
if let strongSelf = self {
let _ = strongSelf.controllerInteraction.sendSticker(file, false, sourceNode, sourceRect)

View file

@ -205,13 +205,12 @@ class StickerPaneSearchGlobalItemNode: GridItemNode {
self.updatePreviewing(animated: false)
}
override func layout() {
super.layout()
override func updateLayout(item: GridItem, size: CGSize, isVisible: Bool, synchronousLoads: Bool) {
guard let item = self.item else {
return
}
let params = ListViewItemLayoutParams(width: self.bounds.size.width, leftInset: 0.0, rightInset: 0.0, availableHeight: self.bounds.height)
let params = ListViewItemLayoutParams(width: size.width, leftInset: 0.0, rightInset: 0.0, availableHeight: size.height)
var topOffset: CGFloat = 12.0
if item.topSeparator {
@ -230,15 +229,19 @@ class StickerPaneSearchGlobalItemNode: GridItemNode {
self.appliedItem = item
var updateButtonBackgroundImage: UIImage?
if currentItem?.theme !== item.theme {
updateButtonBackgroundImage = PresentationResourcesChat.chatInputMediaPanelAddPackButtonImage(item.theme)
if currentItem?.theme !== item.theme || currentItem?.installed != item.installed {
if item.installed {
updateButtonBackgroundImage = PresentationResourcesChat.chatInputMediaPanelAddedPackButtonImage(item.theme)
} else {
updateButtonBackgroundImage = PresentationResourcesChat.chatInputMediaPanelAddPackButtonImage(item.theme)
}
}
let unreadImage = PresentationResourcesItemList.stickerUnreadDotImage(item.theme)
let leftInset: CGFloat = 14.0
let rightInset: CGFloat = 16.0
let (installLayout, installApply) = makeInstallLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.strings.Stickers_Install, font: buttonFont, textColor: item.theme.list.itemCheckColors.foregroundColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let (installLayout, installApply) = makeInstallLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.installed ? item.strings.Stickers_Installed : item.strings.Stickers_Install, font: buttonFont, textColor: item.installed ? item.theme.list.itemCheckColors.fillColor : item.theme.list.itemCheckColors.foregroundColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.info.title, font: titleFont, textColor: item.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - leftInset - rightInset - 20.0 - installLayout.size.width, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
@ -260,21 +263,15 @@ class StickerPaneSearchGlobalItemNode: GridItemNode {
strongSelf.installTextNode.frame = CGRect(origin: CGPoint(x: buttonFrame.minX + floor((buttonFrame.width - installLayout.size.width) / 2.0), y: buttonFrame.minY + floor((buttonFrame.height - installLayout.size.height) / 2.0) + 1.0), size: installLayout.size)
strongSelf.installButtonNode.frame = buttonFrame
if item.installed {
strongSelf.installButtonNode.isHidden = true
strongSelf.installBackgroundNode.isHidden = true
strongSelf.installTextNode.isHidden = true
} else {
strongSelf.installButtonNode.isHidden = false
strongSelf.installBackgroundNode.isHidden = false
strongSelf.installTextNode.isHidden = false
}
strongSelf.installButtonNode.isHidden = false
strongSelf.installBackgroundNode.isHidden = false
strongSelf.installTextNode.isHidden = false
let titleFrame = CGRect(origin: CGPoint(x: params.leftInset + leftInset, y: 2.0 + topOffset), size: titleLayout.size)
strongSelf.titleNode.frame = titleFrame
strongSelf.descriptionNode.frame = CGRect(origin: CGPoint(x: params.leftInset + leftInset, y: 23.0 + topOffset), size: descriptionLayout.size)
if false && item.unread {
if item.unread {
strongSelf.unreadNode.isHidden = false
} else {
strongSelf.unreadNode.isHidden = true
@ -309,7 +306,7 @@ class StickerPaneSearchGlobalItemNode: GridItemNode {
strongSelf.addSubnode(node)
}
if file.fileId != node.file?.fileId {
node.setup(account: item.account, item: topItems[i], itemSize: itemSize, synchronousLoads: false)
node.setup(account: item.account, item: topItems[i], itemSize: itemSize, synchronousLoads: synchronousLoads)
}
if let dimensions = file.dimensions {
let imageSize = dimensions.cgSize.aspectFitted(itemSize)

View file

@ -33,7 +33,7 @@ final class WebSearchNavigationContentNode: NavigationBarContentNode {
self.searchBar.textReturned = { [weak self] query in
self?.queryUpdated?(query)
}
self.searchBar.textUpdated = { [weak self] query in
self.searchBar.textUpdated = { [weak self] query, _ in
if query.isEmpty {
self?.queryUpdated?(query)
}