mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Merge commit '560c07af6b'
This commit is contained in:
commit
6ff4cd3681
19 changed files with 290 additions and 67 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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: [],
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Empty>()
|
||||
private let badge = ComponentView<Empty>()
|
||||
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ swift_library(
|
|||
"//submodules/Components/SolidRoundedButtonComponent",
|
||||
"//submodules/TelegramUI/Components/AnimatedTextComponent",
|
||||
"//submodules/AvatarNode",
|
||||
"//submodules/PhotoResources",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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<Empty>, 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,
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Star20.pdf",
|
||||
"filename" : "Star20 (3).pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "star_18.pdf",
|
||||
"filename" : "star_18 (3).pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "star_16 (2).pdf",
|
||||
"filename" : "star_16 (3).pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
".",
|
||||
"."
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue