diff --git a/submodules/HashtagSearchUI/Sources/HashtagSearchControllerNode.swift b/submodules/HashtagSearchUI/Sources/HashtagSearchControllerNode.swift index 3dec889a25..6012db359d 100644 --- a/submodules/HashtagSearchUI/Sources/HashtagSearchControllerNode.swift +++ b/submodules/HashtagSearchUI/Sources/HashtagSearchControllerNode.swift @@ -54,7 +54,8 @@ final class HashtagSearchControllerNode: ASDisplayNode { self.shimmerNode.allowsGroupOpacity = true self.recentListNode = HashtagSearchRecentListNode(context: context) - + self.recentListNode.alpha = 0.0 + let navigationController = controller.navigationController as? NavigationController if let peer { self.currentController = context.sharedContext.makeChatController(context: context, chatLocation: .peer(id: peer.id), subject: nil, botStart: nil, mode: .inline(navigationController)) @@ -150,6 +151,10 @@ final class HashtagSearchControllerNode: ASDisplayNode { } self.searchContentNode.query = query self.updateSearchQuery(query) + + Queue.mainQueue().after(0.4) { + let _ = addRecentHashtagSearchQuery(engine: context.engine, string: query).startStandalone() + } } self.currentController?.isSelectingMessagesUpdated = { [weak self] isSelecting in @@ -303,9 +308,20 @@ final class HashtagSearchControllerNode: ASDisplayNode { self.insertSubnode(self.recentListNode, aboveSubnode: self.shimmerNode) } - self.recentListNode.frame = CGRect(origin: .zero, size: layout.size) + transition.updateFrame(node: self.recentListNode, frame: CGRect(origin: .zero, size: layout.size)) self.recentListNode.updateLayout(layout: ContainerViewLayout(size: layout.size, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, intrinsicInsets: UIEdgeInsets(top: insets.top - 35.0, left: layout.safeInsets.left, bottom: layout.intrinsicInsets.bottom, right: layout.safeInsets.right), safeInsets: layout.safeInsets, additionalInsets: layout.additionalInsets, statusBarHeight: nil, inputHeight: layout.inputHeight, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: transition) - self.recentListNode.isHidden = !self.query.isEmpty + + let recentTransition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut) + if self.query.isEmpty { + recentTransition.updateAlpha(node: self.recentListNode, alpha: 1.0) + } else if self.recentListNode.alpha > 0.0 { + Queue.mainQueue().after(0.1, { + if !self.query.isEmpty { + recentTransition.updateAlpha(node: self.recentListNode, alpha: 0.0) + } + }) + } + if !self.hasValidLayout { self.hasValidLayout = true diff --git a/submodules/HashtagSearchUI/Sources/HashtagSearchGlobalChatContents.swift b/submodules/HashtagSearchUI/Sources/HashtagSearchGlobalChatContents.swift index f7acade603..11e88d64c9 100644 --- a/submodules/HashtagSearchUI/Sources/HashtagSearchGlobalChatContents.swift +++ b/submodules/HashtagSearchUI/Sources/HashtagSearchGlobalChatContents.swift @@ -94,7 +94,7 @@ final class HashtagSearchGlobalChatContents: ChatCustomContentsProtocol { } func loadMore() { - guard self.historyViewDisposable == nil, let currentSearchState = self.currentSearchState else { + guard self.historyViewDisposable == nil, let currentSearchState = self.currentSearchState, let currentHistoryView = self.sourceHistoryView, currentHistoryView.holeEarlier else { return } @@ -114,7 +114,7 @@ final class HashtagSearchGlobalChatContents: ChatCustomContentsProtocol { let updateType: ViewUpdateType = .FillHole - let historyView = MessageHistoryView(tag: nil, namespaces: .just(Set([Namespaces.Message.Cloud])), entries: result.0.messages.reversed().map { MessageHistoryEntry(message: $0, isRead: false, location: nil, monthLocation: nil, attributes: MutableMessageHistoryEntryAttributes(authorIsContact: false)) }, holeEarlier: false, holeLater: false, isLoading: false) + let historyView = MessageHistoryView(tag: nil, namespaces: .just(Set([Namespaces.Message.Cloud])), entries: result.0.messages.reversed().map { MessageHistoryEntry(message: $0, isRead: false, location: nil, monthLocation: nil, attributes: MutableMessageHistoryEntryAttributes(authorIsContact: false)) }, holeEarlier: !result.0.completed, holeLater: false, isLoading: false) self.sourceHistoryView = historyView self.updateHistoryView(updateType: updateType) diff --git a/submodules/TelegramUI/Components/Chat/ChatInlineSearchResultsListComponent/Sources/ChatInlineSearchResultsListComponent.swift b/submodules/TelegramUI/Components/Chat/ChatInlineSearchResultsListComponent/Sources/ChatInlineSearchResultsListComponent.swift index d8a51a421e..13552cf68f 100644 --- a/submodules/TelegramUI/Components/Chat/ChatInlineSearchResultsListComponent/Sources/ChatInlineSearchResultsListComponent.swift +++ b/submodules/TelegramUI/Components/Chat/ChatInlineSearchResultsListComponent/Sources/ChatInlineSearchResultsListComponent.swift @@ -768,10 +768,14 @@ public final class ChatInlineSearchResultsListComponent: Component { } let renderedPeer: EngineRenderedPeer - if let effectiveAuthor { + if let effectiveAuthor, !component.showEmptyResults { renderedPeer = EngineRenderedPeer(peer: effectiveAuthor) } else { - renderedPeer = EngineRenderedPeer(peerId: message.id.peerId, peers: [:], associatedMedia: [:]) + var peers: [EnginePeer.Id: EnginePeer] = [:] + if let peer = message.peers[message.id.peerId] { + peers[message.id.peerId] = EnginePeer(peer) + } + renderedPeer = EngineRenderedPeer(peerId: message.id.peerId, peers: peers, associatedMedia: [:]) } return ChatListItem( @@ -800,7 +804,7 @@ public final class ChatInlineSearchResultsListComponent: Component { inputActivities: nil, promoInfo: nil, ignoreUnreadBadge: false, - displayAsMessage: component.peerId != component.context.account.peerId, + displayAsMessage: component.peerId != component.context.account.peerId && !component.showEmptyResults, hasFailedMessages: false, forumTopicData: nil, topForumTopicItems: [], diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageItemImpl/Sources/ChatMessageItemImpl.swift b/submodules/TelegramUI/Components/Chat/ChatMessageItemImpl/Sources/ChatMessageItemImpl.swift index 7bb83c771d..4c7a445884 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageItemImpl/Sources/ChatMessageItemImpl.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageItemImpl/Sources/ChatMessageItemImpl.swift @@ -75,11 +75,16 @@ private func messagesShouldBeMerged(accountPeerId: PeerId, _ lhs: Message, _ rhs } } + var sameChat = true + if lhs.id.peerId != rhs.id.peerId { + sameChat = false + } + var sameThread = true if let lhsPeer = lhs.peers[lhs.id.peerId], let rhsPeer = rhs.peers[rhs.id.peerId], arePeersEqual(lhsPeer, rhsPeer), let channel = lhsPeer as? TelegramChannel, channel.flags.contains(.isForum), lhs.threadId != rhs.threadId { sameThread = false } - + var sameAuthor = false if lhsEffectiveAuthor?.id == rhsEffectiveAuthor?.id && lhs.effectivelyIncoming(accountPeerId) == rhs.effectivelyIncoming(accountPeerId) { sameAuthor = true @@ -124,7 +129,7 @@ private func messagesShouldBeMerged(accountPeerId: PeerId, _ lhs: Message, _ rhs } } - if abs(lhsEffectiveTimestamp - rhsEffectiveTimestamp) < Int32(10 * 60) && sameAuthor && sameThread { + if abs(lhsEffectiveTimestamp - rhsEffectiveTimestamp) < Int32(10 * 60) && sameChat && sameAuthor && sameThread { if let channel = lhs.peers[lhs.id.peerId] as? TelegramChannel, case .group = channel.info, lhsEffectiveAuthor?.id == channel.id, !lhs.effectivelyIncoming(accountPeerId) { return .none } diff --git a/submodules/TelegramUI/Components/Premium/PremiumStarComponent/Sources/GiftAvatarComponent.swift b/submodules/TelegramUI/Components/Premium/PremiumStarComponent/Sources/GiftAvatarComponent.swift index dc127f1f20..d53649dbcc 100644 --- a/submodules/TelegramUI/Components/Premium/PremiumStarComponent/Sources/GiftAvatarComponent.swift +++ b/submodules/TelegramUI/Components/Premium/PremiumStarComponent/Sources/GiftAvatarComponent.swift @@ -22,6 +22,7 @@ public final class GiftAvatarComponent: Component { let theme: PresentationTheme let peers: [EnginePeer] let photo: TelegramMediaWebFile? + let starsPeer: StarsContext.State.Transaction.Peer? let isVisible: Bool let hasIdleAnimations: Bool let hasScaleAnimation: Bool @@ -29,11 +30,24 @@ public final class GiftAvatarComponent: Component { let color: UIColor? let offset: CGFloat? - public init(context: AccountContext, theme: PresentationTheme, peers: [EnginePeer], photo: TelegramMediaWebFile? = nil, isVisible: Bool, hasIdleAnimations: Bool, hasScaleAnimation: Bool = true, avatarSize: CGFloat = 100.0, color: UIColor? = nil, offset: CGFloat? = nil) { + public init( + context: AccountContext, + theme: PresentationTheme, + peers: [EnginePeer], + photo: TelegramMediaWebFile? = nil, + starsPeer: StarsContext.State.Transaction.Peer? = nil, + isVisible: Bool, + hasIdleAnimations: Bool, + hasScaleAnimation: Bool = true, + avatarSize: CGFloat = 100.0, + color: UIColor? = nil, + offset: CGFloat? = nil + ) { self.context = context self.theme = theme self.peers = peers self.photo = photo + self.starsPeer = starsPeer self.isVisible = isVisible self.hasIdleAnimations = hasIdleAnimations self.hasScaleAnimation = hasScaleAnimation @@ -76,6 +90,9 @@ public final class GiftAvatarComponent: Component { private var mergedAvatarsNode: MergedAvatarsNode? private var imageNode: TransformImageNode? + private var iconBackgroundView: UIImageView? + private var iconView: UIImageView? + private let badgeBackground = ComponentView() private let badge = ComponentView() @@ -321,6 +338,82 @@ public final class GiftAvatarComponent: Component { imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(radius: imageSize.width / 2.0), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()))() self.avatarNode.isHidden = true + } else if let starsPeer = component.starsPeer { + let iconBackgroundView: UIImageView + let iconView: UIImageView + if let currentBackground = self.iconBackgroundView, let current = self.iconView { + iconBackgroundView = currentBackground + iconView = current + } else { + iconBackgroundView = UIImageView() + iconView = UIImageView() + + self.addSubview(iconBackgroundView) + self.addSubview(iconView) + + self.iconBackgroundView = iconBackgroundView + self.iconView = iconView + + let size = CGSize(width: component.avatarSize, height: component.avatarSize) + var iconInset: CGFloat = 9.0 + var iconOffset: CGFloat = 0.0 + + switch starsPeer { + case .appStore: + iconBackgroundView.image = generateGradientFilledCircleImage( + diameter: size.width, + colors: [ + UIColor(rgb: 0x2a9ef1).cgColor, + UIColor(rgb: 0x72d5fd).cgColor + ], + direction: .mirroredDiagonal + ) + iconView.image = UIImage(bundleImageName: "Premium/Stars/Apple") + case .playMarket: + iconBackgroundView.image = generateGradientFilledCircleImage( + diameter: size.width, + colors: [ + UIColor(rgb: 0x54cb68).cgColor, + UIColor(rgb: 0xa0de7e).cgColor + ], + direction: .mirroredDiagonal + ) + iconView.image = UIImage(bundleImageName: "Premium/Stars/Google") + case .fragment: + iconBackgroundView.image = generateFilledCircleImage(diameter: size.width, color: UIColor(rgb: 0x1b1f24)) + iconView.image = UIImage(bundleImageName: "Premium/Stars/Fragment") + iconOffset = 5.0 + case .premiumBot: + iconInset = 15.0 + iconBackgroundView.image = generateGradientFilledCircleImage( + diameter: size.width, + colors: [ + UIColor(rgb: 0x6b93ff).cgColor, + UIColor(rgb: 0x6b93ff).cgColor, + UIColor(rgb: 0x8d77ff).cgColor, + UIColor(rgb: 0xb56eec).cgColor, + UIColor(rgb: 0xb56eec).cgColor + ], + direction: .mirroredDiagonal + ) + iconView.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/EntityInputPremiumIcon"), color: .white) + case .peer, .unsupported: + iconInset = 15.0 + iconBackgroundView.image = generateGradientFilledCircleImage( + diameter: size.width, + colors: [ + UIColor(rgb: 0xb1b1b1).cgColor, + UIColor(rgb: 0xcdcdcd).cgColor + ], + direction: .mirroredDiagonal + ) + iconView.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Media/EntityInputPremiumIcon"), color: .white) + } + + let imageFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - size.width) / 2.0), y: 113.0 - size.height / 2.0), size: size) + iconBackgroundView.frame = imageFrame + iconView.frame = imageFrame.insetBy(dx: iconInset, dy: iconInset).offsetBy(dx: 0.0, dy: iconOffset) + } } else if component.peers.count > 1 { let avatarSize = CGSize(width: 60.0, height: 60.0) diff --git a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/BUILD b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/BUILD index 3a16bf04b3..a8c55ae20a 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/BUILD +++ b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/BUILD @@ -38,6 +38,7 @@ swift_library( "//submodules/Components/SolidRoundedButtonComponent", "//submodules/TelegramUI/Components/AnimatedTextComponent", "//submodules/AvatarNode", + "//submodules/PhotoResources", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionScreen.swift b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionScreen.swift index 249f5fbca8..ed1b5bb082 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionScreen.swift @@ -170,6 +170,7 @@ private final class StarsTransactionSheetContent: CombinedComponent { let date: Int32 let via: String? let toPeer: EnginePeer? + let transactionPeer: StarsContext.State.Transaction.Peer? let photo: TelegramMediaWebFile? var delayedCloseOnOpenPeer = true @@ -205,6 +206,7 @@ private final class StarsTransactionSheetContent: CombinedComponent { } else { toPeer = nil } + transactionPeer = transaction.peer photo = transaction.photo case let .receipt(receipt): titleText = receipt.invoiceMedia.title @@ -218,6 +220,7 @@ private final class StarsTransactionSheetContent: CombinedComponent { } else { toPeer = nil } + transactionPeer = nil photo = receipt.invoiceMedia.photo delayedCloseOnOpenPeer = false } @@ -252,6 +255,7 @@ private final class StarsTransactionSheetContent: CombinedComponent { theme: theme, peers: toPeer.flatMap { [$0] } ?? [], photo: photo, + starsPeer: transactionPeer, isVisible: true, hasIdleAnimations: true, hasScaleAnimation: false, @@ -1090,11 +1094,30 @@ private final class TransactionCellComponent: Component { containerSize: CGSize(width: availableSize.width, height: availableSize.height) ) + func brokenLine(_ string: String) -> String { + let middleIndex = string.index(string.startIndex, offsetBy: string.count / 2) + var newString = string + newString.insert("\n", at: middleIndex) + return newString + } + + let text: String + if availableSize.width > 230.0 { + text = component.transactionId + } else { + text = brokenLine(component.transactionId) + } + let textSize = self.text.update( transition: .immediate, component: AnyComponent( MultilineTextComponent( - text: .plain(NSAttributedString(string: component.transactionId, font: Font.monospace(15.0), textColor: component.textColor, paragraphAlignment: .left)), + text: .plain(NSAttributedString( + string: text, + font: Font.monospace(15.0), + textColor: component.textColor, + paragraphAlignment: .left + )), maximumNumberOfLines: 0, lineSpacing: 0.2 ) @@ -1103,9 +1126,9 @@ private final class TransactionCellComponent: Component { containerSize: CGSize(width: availableSize.width - buttonSize.width - spacing, height: availableSize.height) ) - let size = CGSize(width: textSize.width + spacing + buttonSize.width, height: textSize.height) + let size = CGSize(width: availableSize.width, height: textSize.height) - let buttonFrame = CGRect(origin: CGPoint(x: textSize.width + spacing, y: floorToScreenPixels((size.height - buttonSize.height) / 2.0)), size: buttonSize) + let buttonFrame = CGRect(origin: CGPoint(x: availableSize.width - buttonSize.width - 2.0, y: floorToScreenPixels((size.height - buttonSize.height) / 2.0)), size: buttonSize) if let buttonView = self.button.view { if buttonView.superview == nil { self.addSubview(buttonView) diff --git a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsListPanelComponent.swift b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsListPanelComponent.swift index d080c4e5da..98f3ec0fbf 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsListPanelComponent.swift +++ b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsListPanelComponent.swift @@ -14,6 +14,7 @@ import ListActionItemComponent import TelegramStringFormatting import AvatarNode import BundleIconComponent +import PhotoResources final class StarsTransactionsListPanelComponent: Component { typealias EnvironmentType = StarsTransactionsPanelEnvironment @@ -150,7 +151,7 @@ final class StarsTransactionsListPanelComponent: Component { if #available(iOS 13.0, *) { self.scrollView.automaticallyAdjustsScrollIndicatorInsets = false } - self.scrollView.showsVerticalScrollIndicator = true + self.scrollView.showsVerticalScrollIndicator = false self.scrollView.showsHorizontalScrollIndicator = false self.scrollView.alwaysBounceHorizontal = false self.scrollView.scrollsToTop = false @@ -215,8 +216,13 @@ final class StarsTransactionsListPanelComponent: Component { let itemDate: String switch item.transaction.peer { case let .peer(peer): - itemTitle = peer.displayTitle(strings: environment.strings, displayOrder: .firstLast) - itemSubtitle = item.transaction.title + if let title = item.transaction.title { + itemTitle = title + itemSubtitle = peer.displayTitle(strings: environment.strings, displayOrder: .firstLast) + } else { + itemTitle = peer.displayTitle(strings: environment.strings, displayOrder: .firstLast) + itemSubtitle = nil + } case .appStore: itemTitle = environment.strings.Stars_Intro_Transaction_AppleTopUp_Title itemSubtitle = environment.strings.Stars_Intro_Transaction_AppleTopUp_Subtitle @@ -286,7 +292,7 @@ final class StarsTransactionsListPanelComponent: Component { theme: environment.theme, title: AnyComponent(VStack(titleComponents, alignment: .left, spacing: 2.0)), contentInsets: UIEdgeInsets(top: 9.0, left: environment.containerInsets.left, bottom: 8.0, right: environment.containerInsets.right), - leftIcon: .custom(AnyComponentWithIdentity(id: "avatar", component: AnyComponent(AvatarComponent(context: component.context, theme: environment.theme, peer: item.transaction.peer))), false), + leftIcon: .custom(AnyComponentWithIdentity(id: "avatar", component: AnyComponent(AvatarComponent(context: component.context, theme: environment.theme, peer: item.transaction.peer, photo: item.transaction.photo))), false), icon: nil, accessory: .custom(ListActionItemComponent.CustomAccessory(component: AnyComponentWithIdentity(id: "label", component: AnyComponent(LabelComponent(text: itemLabel))), insets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 16.0))), action: { [weak self] _ in @@ -442,11 +448,13 @@ private final class AvatarComponent: Component { let context: AccountContext let theme: PresentationTheme let peer: StarsContext.State.Transaction.Peer + let photo: TelegramMediaWebFile? - init(context: AccountContext, theme: PresentationTheme, peer: StarsContext.State.Transaction.Peer) { + init(context: AccountContext, theme: PresentationTheme, peer: StarsContext.State.Transaction.Peer, photo: TelegramMediaWebFile?) { self.context = context self.theme = theme self.peer = peer + self.photo = photo } static func ==(lhs: AvatarComponent, rhs: AvatarComponent) -> Bool { @@ -459,6 +467,9 @@ private final class AvatarComponent: Component { if lhs.peer != rhs.peer { return false } + if lhs.photo != rhs.photo { + return false + } return true } @@ -466,6 +477,9 @@ private final class AvatarComponent: Component { private let avatarNode: AvatarNode private let backgroundView = UIImageView() private let iconView = UIImageView() + private var imageNode: TransformImageNode? + + private let fetchDisposable = MetaDisposable() private var component: AvatarComponent? private weak var state: EmptyComponentState? @@ -486,6 +500,10 @@ private final class AvatarComponent: Component { fatalError("init(coder:) has not been implemented") } + deinit { + self.fetchDisposable.dispose() + } + func update(component: AvatarComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: Transition) -> CGSize { self.component = component self.state = state @@ -496,15 +514,36 @@ private final class AvatarComponent: Component { switch component.peer { case let .peer(peer): - self.avatarNode.setPeer( - context: component.context, - theme: component.theme, - peer: peer, - synchronousLoad: true - ) - self.backgroundView.isHidden = true - self.iconView.isHidden = true - self.avatarNode.isHidden = false + if let photo = component.photo { + let imageNode: TransformImageNode + if let current = self.imageNode { + imageNode = current + } else { + imageNode = TransformImageNode() + self.addSubview(imageNode.view) + self.imageNode = imageNode + + imageNode.setSignal(chatWebFileImage(account: component.context.account, file: photo)) + self.fetchDisposable.set(chatMessageWebFileInteractiveFetched(account: component.context.account, userLocation: .other, image: photo).startStrict()) + } + + imageNode.frame = CGRect(origin: .zero, size: size) + imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(radius: size.width / 2.0), imageSize: size, boundingSize: size, intrinsicInsets: UIEdgeInsets()))() + + self.backgroundView.isHidden = true + self.iconView.isHidden = true + self.avatarNode.isHidden = true + } else { + self.avatarNode.setPeer( + context: component.context, + theme: component.theme, + peer: peer, + synchronousLoad: true + ) + self.backgroundView.isHidden = true + self.iconView.isHidden = true + self.avatarNode.isHidden = false + } case .appStore: self.backgroundView.image = generateGradientFilledCircleImage( diameter: size.width, diff --git a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsScreen.swift b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsScreen.swift index d28c3f34ce..cb03ef8dc6 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsScreen.swift @@ -725,7 +725,7 @@ public final class StarsTransactionsScreen: ViewControllerComponentContainer { let resultController = UndoOverlayController( presentationData: presentationData, content: .image( - image: UIImage(bundleImageName: "Premium/Stars/StarMedium")!, + image: UIImage(bundleImageName: "Premium/Stars/StarLarge")!, title: presentationData.strings.Stars_Intro_PurchasedTitle, text: presentationData.strings.Stars_Intro_PurchasedText(presentationData.strings.Stars_Intro_PurchasedText_Stars(Int32(stars))).string, round: false, @@ -740,6 +740,10 @@ public final class StarsTransactionsScreen: ViewControllerComponentContainer { } self.starsContext.load() + + Queue.mainQueue().after(0.5, { + self.starsContext.loadMore() + }) } required public init(coder aDecoder: NSCoder) { diff --git a/submodules/TelegramUI/Components/Stars/StarsTransferScreen/Sources/StarsTransferScreen.swift b/submodules/TelegramUI/Components/Stars/StarsTransferScreen/Sources/StarsTransferScreen.swift index 027842be37..1e1ea46f37 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransferScreen/Sources/StarsTransferScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsTransferScreen/Sources/StarsTransferScreen.swift @@ -341,7 +341,7 @@ private final class SheetContent: CombinedComponent { transition: .immediate ) let balanceIcon = balanceIcon.update( - component: BundleIconComponent(name: "Premium/Stars/StarMedium", tintColor: nil), + component: BundleIconComponent(name: "Premium/Stars/StarLarge", tintColor: nil), availableSize: context.availableSize, transition: .immediate ) diff --git a/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarLarge.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarLarge.imageset/Contents.json index 653a52e723..46aa1a67a6 100644 --- a/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarLarge.imageset/Contents.json +++ b/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarLarge.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "Star20.pdf", + "filename" : "Star20 (3).pdf", "idiom" : "universal" } ], diff --git a/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarLarge.imageset/Star20.pdf b/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarLarge.imageset/Star20 (3).pdf similarity index 87% rename from submodules/TelegramUI/Images.xcassets/Premium/Stars/StarLarge.imageset/Star20.pdf rename to submodules/TelegramUI/Images.xcassets/Premium/Stars/StarLarge.imageset/Star20 (3).pdf index ad28ef79f1..11a9fc5e3b 100644 Binary files a/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarLarge.imageset/Star20.pdf and b/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarLarge.imageset/Star20 (3).pdf differ diff --git a/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarMedium.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarMedium.imageset/Contents.json index bea582e947..da87fd09d2 100644 --- a/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarMedium.imageset/Contents.json +++ b/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarMedium.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "star_18.pdf", + "filename" : "star_18 (3).pdf", "idiom" : "universal" } ], diff --git a/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarMedium.imageset/star_18.pdf b/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarMedium.imageset/star_18 (3).pdf similarity index 87% rename from submodules/TelegramUI/Images.xcassets/Premium/Stars/StarMedium.imageset/star_18.pdf rename to submodules/TelegramUI/Images.xcassets/Premium/Stars/StarMedium.imageset/star_18 (3).pdf index 3f23ba8d2b..04a33dabef 100644 Binary files a/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarMedium.imageset/star_18.pdf and b/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarMedium.imageset/star_18 (3).pdf differ diff --git a/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarSmall.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarSmall.imageset/Contents.json index 0c43076025..e283fcf416 100644 --- a/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarSmall.imageset/Contents.json +++ b/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarSmall.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "star_16 (2).pdf", + "filename" : "star_16 (3).pdf", "idiom" : "universal" } ], diff --git a/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarSmall.imageset/star_16 (2).pdf b/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarSmall.imageset/star_16 (3).pdf similarity index 74% rename from submodules/TelegramUI/Images.xcassets/Premium/Stars/StarSmall.imageset/star_16 (2).pdf rename to submodules/TelegramUI/Images.xcassets/Premium/Stars/StarSmall.imageset/star_16 (3).pdf index ea68a6d380..60349a9d90 100644 Binary files a/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarSmall.imageset/star_16 (2).pdf and b/submodules/TelegramUI/Images.xcassets/Premium/Stars/StarSmall.imageset/star_16 (3).pdf differ diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index 64a2f5080d..36b396b27e 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -3035,10 +3035,17 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto if self.chatHistoryLocationValue == historyView.locationInput { self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Navigation(index: .upperBound, anchorIndex: .upperBound, count: historyMessageCount, highlight: false), id: self.takeNextHistoryLocationId()) } - } else if mathesLast && historyView.originalView.earlierId != nil { + } else if mathesLast { let locationInput: ChatHistoryLocation = .Navigation(index: .message(firstEntry.index), anchorIndex: .message(firstEntry.index), count: historyMessageCount, highlight: false) - if self.chatHistoryLocationValue?.content != locationInput { - self.chatHistoryLocationValue = ChatHistoryLocationInput(content: locationInput, id: self.takeNextHistoryLocationId()) + if historyView.originalView.earlierId != nil { + if self.chatHistoryLocationValue?.content != locationInput { + self.chatHistoryLocationValue = ChatHistoryLocationInput(content: locationInput, id: self.takeNextHistoryLocationId()) + } + } else if case let .customChatContents(customChatContents) = self.subject, case .hashTagSearch = customChatContents.kind { + if self.chatHistoryLocationValue?.content != locationInput { + self.chatHistoryLocationValue = ChatHistoryLocationInput(content: locationInput, id: self.takeNextHistoryLocationId()) + customChatContents.loadMore() + } } } } @@ -4260,37 +4267,58 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto loop: for i in 0 ..< historyView.filteredEntries.count { switch historyView.filteredEntries[i] { - case let .MessageEntry(message, presentationData, read, location, selection, attributes): - if message.id == id { - let index = historyView.filteredEntries.count - 1 - i - let item: ListViewItem - switch self.mode { - case .bubbles: - item = ChatMessageItemImpl(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, associatedData: associatedData, controllerInteraction: self.controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes, location: location), disableDate: disableFloatingDateHeaders) - case let .list(_, _, _, displayHeaders, hintLinks, isGlobalSearch): - let displayHeader: Bool - switch displayHeaders { - case .none: - displayHeader = false - case .all: - displayHeader = true - case .allButLast: - displayHeader = listMessageDateHeaderId(timestamp: message.timestamp) != historyView.lastHeaderId - } - item = ListMessageItem(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, interaction: ListMessageItemInteraction(controllerInteraction: self.controllerInteraction), message: message, translateToLanguage: associatedData.translateToLanguage, selection: selection, displayHeader: displayHeader, hintIsLink: hintLinks, isGlobalSearchResult: isGlobalSearch) + case let .MessageEntry(message, presentationData, read, location, selection, attributes): + if message.id == id { + let index = historyView.filteredEntries.count - 1 - i + let item: ListViewItem + switch self.mode { + case .bubbles: + item = ChatMessageItemImpl(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, associatedData: associatedData, controllerInteraction: self.controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes, location: location), disableDate: disableFloatingDateHeaders) + case let .list(_, _, _, displayHeaders, hintLinks, isGlobalSearch): + let displayHeader: Bool + switch displayHeaders { + case .none: + displayHeader = false + case .all: + displayHeader = true + case .allButLast: + displayHeader = listMessageDateHeaderId(timestamp: message.timestamp) != historyView.lastHeaderId } - let updateItem = ListViewUpdateItem(index: index, previousIndex: index, item: item, directionHint: nil) - - var scrollToItem: ListViewScrollToItem? - if scroll { - scrollToItem = ListViewScrollToItem(index: index, position: .center(.top), animated: true, curve: .Spring(duration: 0.4), directionHint: .Down, displayLink: true) - } - - self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [updateItem], options: [.AnimateInsertion], scrollToItem: scrollToItem, additionalScrollDistance: 0.0, updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) - break loop + item = ListMessageItem(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, interaction: ListMessageItemInteraction(controllerInteraction: self.controllerInteraction), message: message, translateToLanguage: associatedData.translateToLanguage, selection: selection, displayHeader: displayHeader, hintIsLink: hintLinks, isGlobalSearchResult: isGlobalSearch) } - default: - break + let updateItem = ListViewUpdateItem(index: index, previousIndex: index, item: item, directionHint: nil) + + var scrollToItem: ListViewScrollToItem? + if scroll { + scrollToItem = ListViewScrollToItem(index: index, position: .center(.top), animated: true, curve: .Spring(duration: 0.4), directionHint: .Down, displayLink: true) + } + + self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [updateItem], options: [.AnimateInsertion], scrollToItem: scrollToItem, additionalScrollDistance: 0.0, updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) + break loop + } + case let .MessageGroupEntry(_, messages, presentationData): + if messages.contains(where: { $0.0.id == id }) { + let index = historyView.filteredEntries.count - 1 - i + let item: ListViewItem + switch self.mode { + case .bubbles: + item = ChatMessageItemImpl(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, associatedData: associatedData, controllerInteraction: self.controllerInteraction, content: .group(messages: messages), disableDate: disableFloatingDateHeaders) + case .list: + assertionFailure() + item = ListMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, interaction: ListMessageItemInteraction(controllerInteraction: controllerInteraction), message: messages[0].0, selection: .none, displayHeader: false) + } + let updateItem = ListViewUpdateItem(index: index, previousIndex: index, item: item, directionHint: nil) + + var scrollToItem: ListViewScrollToItem? + if scroll { + scrollToItem = ListViewScrollToItem(index: index, position: .center(.top), animated: true, curve: .Spring(duration: 0.4), directionHint: .Down, displayLink: true) + } + + self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [updateItem], options: [.AnimateInsertion], scrollToItem: scrollToItem, additionalScrollDistance: 0.0, updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) + break loop + } + default: + break } } } diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift index 4e523d99df..932855e496 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift @@ -281,10 +281,12 @@ private func canViewReadStats(message: Message, participantCount: Int?, isMessag } func canReplyInChat(_ chatPresentationInterfaceState: ChatPresentationInterfaceState, accountPeerId: PeerId) -> Bool { + if case let .customChatContents(contents) = chatPresentationInterfaceState.subject, case .hashTagSearch = contents.kind { + return false + } if case .customChatContents = chatPresentationInterfaceState.chatLocation { return true } - guard let peer = chatPresentationInterfaceState.renderedPeer?.peer else { return false } diff --git a/submodules/TelegramUI/Sources/ChatTagSearchInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatTagSearchInputPanelNode.swift index ae0a6a3767..d1d04db7e9 100644 --- a/submodules/TelegramUI/Sources/ChatTagSearchInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTagSearchInputPanelNode.swift @@ -228,7 +228,15 @@ final class ChatTagSearchInputPanelNode: ChatInputPanelNode { if let currentId = results.currentId, let index = results.messageIndices.firstIndex(where: { $0.id == currentId }) { canChangeListMode = true - if params.interfaceState.displayHistoryFilterAsList || self.alwaysShowTotalMessagesCount { + if self.alwaysShowTotalMessagesCount { + let value = presentationStringsFormattedNumber(Int32(displayTotalCount), params.interfaceState.dateTimeFormat.groupingSeparator) + let suffix = params.interfaceState.strings.Chat_BottomSearchPanel_MessageCount(Int32(displayTotalCount)) + resultsTextString = [AnimatedTextComponent.Item( + id: "text", + isUnbreakable: true, + content: .text(params.interfaceState.strings.Chat_BottomSearchPanel_MessageCountFormat(value, suffix).string) + )] + } else if params.interfaceState.displayHistoryFilterAsList { resultsTextString = extractAnimatedTextString(string: params.interfaceState.strings.Chat_BottomSearchPanel_MessageCountFormat( ".", "."