[WIP] Tags

This commit is contained in:
Isaac 2024-01-19 22:23:10 +04:00
parent 67fd1b6c2b
commit d1493c4abd
36 changed files with 906 additions and 170 deletions

View File

@ -10934,7 +10934,7 @@ Sorry for the inconvenience.";
"Chat.ContextMenuTagsTitle" = "Tag the message with an emoji for quick access later";
"Chat.ReactionContextMenu.FilterByTag" = "Fiter by Tag";
"Chat.ReactionContextMenu.FilterByTag" = "Filter by Tag";
"Chat.ReactionContextMenu.RemoveTag" = "Remove Tag";
"Chat.EmptyStateMessagingRestrictedToPremium.Text" = "Subscribe to **Premium**\nto message **%@**.";
@ -10974,3 +10974,5 @@ Sorry for the inconvenience.";
"Settings.Privacy.ReadTimePremiumActive" = "Subcribed to Telegram Premium";
"Settings.Privacy.ReadTimePremiumActiveFooter" = "Because you are a Telegram Premium subscriber, you will see the last seen and read time of all users who are sharing it with you even if you are hiding yours.";
"Privacy.VoiceMessages.NonPremiumHelp" = "Subscribe to Telegram Premium to restrict who can send you voice or video messages.\n\n[What is Telegram Premium?]()";

View File

@ -356,6 +356,7 @@ public enum ChatSearchDomain: Equatable {
case everything
case members
case member(Peer)
case tag(MessageReaction.Reaction)
public static func ==(lhs: ChatSearchDomain, rhs: ChatSearchDomain) -> Bool {
switch lhs {
@ -377,6 +378,12 @@ public enum ChatSearchDomain: Equatable {
} else {
return false
}
case let .tag(reaction):
if case .tag(reaction) = rhs {
return true
} else {
return false
}
}
}
}

View File

@ -821,7 +821,7 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceView {
guard let layout = self.layout else {
return
}
layout.spec.component.action(layout.spec.component.reaction.value)
layout.spec.component.action(self, layout.spec.component.reaction.value)
}
fileprivate func apply(layout: Layout, animation: ListViewItemUpdateAnimation, arguments: ReactionButtonsAsyncLayoutContainer.Arguments) {
@ -1061,7 +1061,7 @@ public final class ReactionButtonComponent: Equatable {
public let isTag: Bool
public let count: Int
public let chosenOrder: Int?
public let action: (MessageReaction.Reaction) -> Void
public let action: (ReactionButtonAsyncNode, MessageReaction.Reaction) -> Void
public init(
context: AccountContext,
@ -1071,7 +1071,7 @@ public final class ReactionButtonComponent: Equatable {
isTag: Bool,
count: Int,
chosenOrder: Int?,
action: @escaping (MessageReaction.Reaction) -> Void
action: @escaping (ReactionButtonAsyncNode, MessageReaction.Reaction) -> Void
) {
self.context = context
self.colors = colors
@ -1218,7 +1218,7 @@ public final class ReactionButtonsAsyncLayoutContainer {
public func update(
context: AccountContext,
action: @escaping (MessageReaction.Reaction) -> Void,
action: @escaping (ReactionButtonAsyncNode, MessageReaction.Reaction) -> Void,
reactions: [ReactionButtonsAsyncLayoutContainer.Reaction],
colors: ReactionButtonComponent.Colors,
isTag: Bool,

View File

@ -1586,6 +1586,11 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
if self.reactionContextNodeIsAnimatingOut, let reactionContextNode = self.reactionContextNode {
reactionContextNode.bounds = reactionContextNode.bounds.offsetBy(dx: 0.0, dy: offset.y)
transition.animateOffsetAdditive(node: reactionContextNode, offset: -offset.y)
if let itemContentNode = self.itemContentNode {
itemContentNode.bounds = itemContentNode.bounds.offsetBy(dx: 0.0, dy: offset.y)
transition.animateOffsetAdditive(node: itemContentNode, offset: -offset.y)
}
}
}
}

View File

@ -1827,6 +1827,13 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
return ListViewState(insets: self.insets, visibleSize: self.visibleSize, invisibleInset: self.invisibleInset, nodes: nodes, scrollPosition: nil, stationaryOffset: nil, stackFromBottom: self.stackFromBottom)
}
public func addAfterTransactionsCompleted(_ f: @escaping () -> Void) {
self.transactionQueue.addTransaction({ transactionCompletion in
f()
transactionCompletion()
})
}
public func transaction(deleteIndices: [ListViewDeleteItem], insertIndicesAndItems: [ListViewInsertItem], updateIndicesAndItems: [ListViewUpdateItem], options: ListViewDeleteAndInsertOptions, scrollToItem: ListViewScrollToItem? = nil, additionalScrollDistance: CGFloat = 0.0, updateSizeAndInsets: ListViewUpdateSizeAndInsets? = nil, stationaryItemRange: (Int, Int)? = nil, updateOpaqueState: Any?, completion: @escaping (ListViewDisplayedItemRange) -> Void = { _ in }) {
if deleteIndices.isEmpty && insertIndicesAndItems.isEmpty && updateIndicesAndItems.isEmpty && scrollToItem == nil && updateSizeAndInsets == nil && additionalScrollDistance.isZero {
if let updateOpaqueState = updateOpaqueState {
@ -2640,6 +2647,9 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
if let updateSizeAndInsets = updateSizeAndInsets {
if updateSizeAndInsets.size != self.visibleSize || updateSizeAndInsets.insets != self.insets {
sizeOrInsetsUpdated = true
if updateSizeAndInsets.insets.top == 83.0 && updateSizeAndInsets.duration < 0.5 {
assert(true)
}
}
}

View File

@ -133,9 +133,16 @@ private final class TitleLabelView: UIView {
}
func update(size: CGSize, text: String, theme: PresentationTheme, transition: ContainedViewLayoutTransition) {
let foregroundColor: UIColor
if theme.overallDarkAppearance {
foregroundColor = UIColor(white: 1.0, alpha: 0.5)
} else {
foregroundColor = UIColor(white: 0.5, alpha: 0.9)
}
let contentSize = self.contentView.update(
transition: .immediate,
component: AnyComponent(Text(text: text, font: Font.regular(13.0), color: UIColor(white: 1.0, alpha: 0.2))),
component: AnyComponent(Text(text: text, font: Font.regular(13.0), color: foregroundColor)),
environment: {},
containerSize: size
)
@ -1903,6 +1910,10 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
itemNode.layer.animateAlpha(from: itemNode.alpha, to: 0.0, duration: 0.2, removeOnCompletion: false)
}
if let titleLabelView = self.titleLabelView {
titleLabelView.layer.animateAlpha(from: titleLabelView.alpha, to: 0.0, duration: 0.2, removeOnCompletion: false)
}
if let reactionComponentView = self.reactionSelectionComponentHost?.view {
reactionComponentView.alpha = 0.0
reactionComponentView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
@ -2470,6 +2481,10 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
}
public func highlightGestureMoved(location: CGPoint, hover: Bool) {
if self.allPresetReactionsAreAvailable {
return
}
let highlightedReaction = self.previewReaction(at: location)?.reaction
if self.highlightedReaction != highlightedReaction {
self.highlightedReaction = highlightedReaction
@ -2489,10 +2504,18 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
}
public func highlightGestureFinished(performAction: Bool) {
if self.allPresetReactionsAreAvailable {
return
}
self.highlightGestureFinished(performAction: performAction, isLarge: false)
}
private func highlightGestureFinished(performAction: Bool, isLarge: Bool) {
if self.allPresetReactionsAreAvailable {
return
}
if let highlightedReaction = self.highlightedReaction {
self.highlightedReaction = nil
if performAction {

View File

@ -391,7 +391,7 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry {
arguments.openGroupsPrivacy()
})
case let .voiceMessagePrivacy(theme, text, value, hasPremium):
return ItemListDisclosureItem(presentationData: presentationData, title: text, titleIcon: hasPremium ? PresentationResourcesItemList.premiumIcon(theme) : nil, label: value, labelStyle: !hasPremium ? .textWithIcon(UIImage(bundleImageName: "Chat/Input/Accessory Panels/TextLockIcon")!.precomposed()) : .text, sectionId: self.section, style: .blocks, action: {
return ItemListDisclosureItem(presentationData: presentationData, title: text, titleIcon: hasPremium ? PresentationResourcesItemList.premiumIcon(theme) : nil, label: value, labelStyle: .text, sectionId: self.section, style: .blocks, action: {
arguments.openVoiceMessagePrivacy()
})
case let .messagePrivacy(theme, value, hasPremium):
@ -933,7 +933,6 @@ public func privacyAndSecurityController(
}
}))
}, openVoiceMessagePrivacy: {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let signal = combineLatest(
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)),
privacySettingsPromise.get()
@ -941,42 +940,22 @@ public func privacyAndSecurityController(
|> take(1)
|> deliverOnMainQueue
currentInfoDisposable.set(signal.start(next: { [weak currentInfoDisposable] peer, info in
let isPremium = peer?.isPremium ?? false
if isPremium {
if let info = info {
pushControllerImpl?(selectivePrivacySettingsController(context: context, kind: .voiceMessages, current: info.voiceMessages, updated: { updated, _, _, _ in
if let currentInfoDisposable = currentInfoDisposable {
let applySetting: Signal<Void, NoError> = privacySettingsPromise.get()
|> filter { $0 != nil }
|> take(1)
|> deliverOnMainQueue
|> mapToSignal { value -> Signal<Void, NoError> in
if let value = value {
privacySettingsPromise.set(.single(AccountPrivacySettings(presence: value.presence, groupInvitations: value.groupInvitations, voiceCalls: value.voiceCalls, voiceCallsP2P: value.voiceCallsP2P, profilePhoto: value.profilePhoto, forwards: value.forwards, phoneNumber: value.phoneNumber, phoneDiscoveryEnabled: value.phoneDiscoveryEnabled, voiceMessages: updated, bio: value.bio, globalSettings: value.globalSettings, accountRemovalTimeout: value.accountRemovalTimeout, messageAutoremoveTimeout: value.messageAutoremoveTimeout)))
}
return .complete()
}
currentInfoDisposable.set(applySetting.start())
if let info = info {
pushControllerImpl?(selectivePrivacySettingsController(context: context, kind: .voiceMessages, current: info.voiceMessages, updated: { updated, _, _, _ in
if let currentInfoDisposable = currentInfoDisposable {
let applySetting: Signal<Void, NoError> = privacySettingsPromise.get()
|> filter { $0 != nil }
|> take(1)
|> deliverOnMainQueue
|> mapToSignal { value -> Signal<Void, NoError> in
if let value = value {
privacySettingsPromise.set(.single(AccountPrivacySettings(presence: value.presence, groupInvitations: value.groupInvitations, voiceCalls: value.voiceCalls, voiceCallsP2P: value.voiceCallsP2P, profilePhoto: value.profilePhoto, forwards: value.forwards, phoneNumber: value.phoneNumber, phoneDiscoveryEnabled: value.phoneDiscoveryEnabled, voiceMessages: updated, bio: value.bio, globalSettings: value.globalSettings, accountRemovalTimeout: value.accountRemovalTimeout, messageAutoremoveTimeout: value.messageAutoremoveTimeout)))
}
return .complete()
}
}), true)
}
} else {
let hapticFeedback = HapticFeedback()
hapticFeedback.impact()
var alreadyPresented = false
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.Privacy_VoiceMessages_Tooltip, timeout: nil, customUndoText: nil), elevatedLayout: false, animateInAsReplacement: false, action: { action in
if action == .info {
if !alreadyPresented {
let controller = PremiumIntroScreen(context: context, source: .settings)
pushControllerImpl?(controller, true)
alreadyPresented = true
}
return true
currentInfoDisposable.set(applySetting.start())
}
return false
}))
}), true)
}
}))
}, openBioPrivacy: {

View File

@ -59,6 +59,7 @@ private final class SelectivePrivacySettingsControllerArguments {
let removePublicPhoto: (() -> Void)?
let updateHideReadTime: ((Bool) -> Void)?
let openPremiumIntro: () -> Void
let displayLockedInfo: () -> Void
init(
context: AccountContext,
@ -71,7 +72,8 @@ private final class SelectivePrivacySettingsControllerArguments {
setPublicPhoto: (() -> Void)?,
removePublicPhoto: (() -> Void)?,
updateHideReadTime: ((Bool) -> Void)?,
openPremiumIntro: @escaping () -> Void
openPremiumIntro: @escaping () -> Void,
displayLockedInfo: @escaping () -> Void
) {
self.context = context
self.updateType = updateType
@ -84,6 +86,7 @@ private final class SelectivePrivacySettingsControllerArguments {
self.removePublicPhoto = removePublicPhoto
self.updateHideReadTime = updateHideReadTime
self.openPremiumIntro = openPremiumIntro
self.displayLockedInfo = displayLockedInfo
}
}
@ -116,9 +119,9 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
case forwardsPreviewHeader(PresentationTheme, String)
case forwardsPreview(PresentationTheme, TelegramWallpaper, PresentationFontSize, PresentationChatBubbleCorners, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, String, Bool, String)
case settingHeader(PresentationTheme, String)
case everybody(PresentationTheme, String, Bool)
case contacts(PresentationTheme, String, Bool)
case nobody(PresentationTheme, String, Bool)
case everybody(PresentationTheme, String, Bool, Bool)
case contacts(PresentationTheme, String, Bool, Bool)
case nobody(PresentationTheme, String, Bool, Bool)
case settingInfo(PresentationTheme, String, String)
case exceptionsHeader(PresentationTheme, String)
case disableFor(PresentationTheme, String, String)
@ -260,20 +263,20 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
} else {
return false
}
case let .everybody(lhsTheme, lhsText, lhsValue):
if case let .everybody(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
case let .everybody(lhsTheme, lhsText, lhsValue, lhsIsLocked):
if case let .everybody(rhsTheme, rhsText, rhsValue, rhsIsLocked) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsIsLocked == rhsIsLocked {
return true
} else {
return false
}
case let .contacts(lhsTheme, lhsText, lhsValue):
if case let .contacts(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
case let .contacts(lhsTheme, lhsText, lhsValue, lhsIsLocked):
if case let .contacts(rhsTheme, rhsText, rhsValue, rhsIsLocked) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsIsLocked == rhsIsLocked {
return true
} else {
return false
}
case let .nobody(lhsTheme, lhsText, lhsValue):
if case let .nobody(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
case let .nobody(lhsTheme, lhsText, lhsValue, lhsIsLocked):
if case let .nobody(rhsTheme, rhsText, rhsValue, rhsIsLocked) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsIsLocked == rhsIsLocked {
return true
} else {
return false
@ -450,17 +453,28 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
return ForwardPrivacyChatPreviewItem(context: arguments.context, theme: theme, strings: strings, sectionId: self.section, fontSize: fontSize, chatBubbleCorners: chatBubbleCorners, wallpaper: wallpaper, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, peerName: peerName, linkEnabled: linkEnabled, tooltipText: tooltipText)
case let .settingHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, multiline: true, sectionId: self.section)
case let .everybody(_, text, value):
return ItemListCheckboxItem(presentationData: presentationData, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
arguments.updateType(.everybody)
case let .everybody(_, text, value, isLocked):
return ItemListCheckboxItem(presentationData: presentationData, icon: !isLocked ? nil : generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/Lock"), color: presentationData.theme.list.itemSecondaryTextColor), iconPlacement: .check, title: text, style: .left, checked: value && !isLocked, zeroSeparatorInsets: false, sectionId: self.section, action: {
if isLocked {
} else {
arguments.updateType(.everybody)
}
})
case let .contacts(_, text, value):
return ItemListCheckboxItem(presentationData: presentationData, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
arguments.updateType(.contacts)
case let .contacts(_, text, value, isLocked):
return ItemListCheckboxItem(presentationData: presentationData, icon: !isLocked ? nil : generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/Lock"), color: presentationData.theme.list.itemSecondaryTextColor), iconPlacement: .check, title: text, style: .left, checked: value && !isLocked, zeroSeparatorInsets: false, sectionId: self.section, action: {
if isLocked {
arguments.displayLockedInfo()
} else {
arguments.updateType(.contacts)
}
})
case let .nobody(_, text, value):
return ItemListCheckboxItem(presentationData: presentationData, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
arguments.updateType(.nobody)
case let .nobody(_, text, value, isLocked):
return ItemListCheckboxItem(presentationData: presentationData, icon: !isLocked ? nil : generateTintedImage(image: UIImage(bundleImageName: "Chat/Stickers/Lock"), color: presentationData.theme.list.itemSecondaryTextColor), iconPlacement: .check, title: text, style: .left, checked: value && !isLocked, zeroSeparatorInsets: false, sectionId: self.section, action: {
if isLocked {
arguments.displayLockedInfo()
} else {
arguments.updateType(.contacts)
}
})
case let .settingInfo(_, text, link):
return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section, linkAction: { _ in
@ -696,10 +710,16 @@ private struct SelectivePrivacySettingsControllerState: Equatable {
private func selectivePrivacySettingsControllerEntries(presentationData: PresentationData, kind: SelectivePrivacySettingsKind, state: SelectivePrivacySettingsControllerState, peerName: String, phoneNumber: String, peer: EnginePeer?, publicPhoto: TelegramMediaImage?) -> [SelectivePrivacySettingsEntry] {
var entries: [SelectivePrivacySettingsEntry] = []
let isPremium = peer?.isPremium ?? false
let settingTitle: String
let settingInfoText: String?
let disableForText: String
let enableForText: String
let phoneLink = "https://t.me/+\(phoneNumber)"
var settingInfoLink = phoneLink
switch kind {
case .presence:
settingTitle = presentationData.strings.PrivacyLastSeenSettings_WhoCanSeeMyTimestamp
@ -737,7 +757,12 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
enableForText = presentationData.strings.PrivacyLastSeenSettings_AlwaysShareWith
case .voiceMessages:
settingTitle = presentationData.strings.Privacy_VoiceMessages_WhoCanSend
settingInfoText = presentationData.strings.Privacy_VoiceMessages_CustomHelp
if isPremium {
settingInfoText = presentationData.strings.Privacy_VoiceMessages_CustomHelp
} else {
settingInfoText = presentationData.strings.Privacy_VoiceMessages_NonPremiumHelp
settingInfoLink = "premium"
}
disableForText = presentationData.strings.Privacy_GroupsAndChannels_NeverAllow
enableForText = presentationData.strings.Privacy_GroupsAndChannels_AlwaysAllow
case .bio:
@ -767,13 +792,18 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
entries.append(.settingHeader(presentationData.theme, settingTitle))
entries.append(.everybody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenEverybody, state.setting == .everybody))
entries.append(.contacts(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenContacts, state.setting == .contacts))
entries.append(.nobody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenNobody, state.setting == .nobody))
let phoneLink = "https://t.me/+\(phoneNumber)"
if case .voiceMessages = kind {
entries.append(.everybody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenEverybody, state.setting == .everybody || !isPremium, false))
entries.append(.contacts(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenContacts, state.setting == .contacts && isPremium, !isPremium))
entries.append(.nobody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenNobody, state.setting == .nobody && isPremium, !isPremium))
} else {
entries.append(.everybody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenEverybody, state.setting == .everybody, false))
entries.append(.contacts(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenContacts, state.setting == .contacts, false))
entries.append(.nobody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenNobody, state.setting == .nobody, false))
}
if let settingInfoText = settingInfoText {
entries.append(.settingInfo(presentationData.theme, settingInfoText, phoneLink))
entries.append(.settingInfo(presentationData.theme, settingInfoText, settingInfoLink))
}
if case .phoneNumber = kind, state.setting == .nobody {
@ -782,32 +812,36 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
entries.append(.phoneDiscoveryMyContacts(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenContacts, state.phoneDiscoveryEnabled == false))
entries.append(.phoneDiscoveryInfo(presentationData.theme, state.phoneDiscoveryEnabled != false ? presentationData.strings.PrivacyPhoneNumberSettings_CustomPublicLink("+\(phoneNumber)").string : presentationData.strings.PrivacyPhoneNumberSettings_CustomDisabledHelp, phoneLink))
}
if case .voiceMessages = kind, !isPremium {
entries.append(.exceptionsHeader(presentationData.theme, presentationData.strings.GroupInfo_Permissions_Exceptions))
switch state.setting {
case .everybody:
entries.append(.disableFor(presentationData.theme, disableForText, stringForUserCount(state.disableFor, strings: presentationData.strings)))
case .contacts:
entries.append(.disableFor(presentationData.theme, disableForText, stringForUserCount(state.disableFor, strings: presentationData.strings)))
entries.append(.enableFor(presentationData.theme, enableForText, stringForUserCount(state.enableFor, strings: presentationData.strings)))
case .nobody:
entries.append(.enableFor(presentationData.theme, enableForText, stringForUserCount(state.enableFor, strings: presentationData.strings)))
}
let exceptionsInfo: String
if case .profilePhoto = kind {
switch state.setting {
case .nobody:
exceptionsInfo = presentationData.strings.Privacy_ProfilePhoto_CustomOverrideAddInfo
case .contacts:
exceptionsInfo = presentationData.strings.Privacy_ProfilePhoto_CustomOverrideBothInfo
case .everybody:
exceptionsInfo = presentationData.strings.Privacy_ProfilePhoto_CustomOverrideInfo
}
} else {
exceptionsInfo = presentationData.strings.PrivacyLastSeenSettings_CustomShareSettingsHelp
entries.append(.exceptionsHeader(presentationData.theme, presentationData.strings.GroupInfo_Permissions_Exceptions))
switch state.setting {
case .everybody:
entries.append(.disableFor(presentationData.theme, disableForText, stringForUserCount(state.disableFor, strings: presentationData.strings)))
case .contacts:
entries.append(.disableFor(presentationData.theme, disableForText, stringForUserCount(state.disableFor, strings: presentationData.strings)))
entries.append(.enableFor(presentationData.theme, enableForText, stringForUserCount(state.enableFor, strings: presentationData.strings)))
case .nobody:
entries.append(.enableFor(presentationData.theme, enableForText, stringForUserCount(state.enableFor, strings: presentationData.strings)))
}
let exceptionsInfo: String
if case .profilePhoto = kind {
switch state.setting {
case .nobody:
exceptionsInfo = presentationData.strings.Privacy_ProfilePhoto_CustomOverrideAddInfo
case .contacts:
exceptionsInfo = presentationData.strings.Privacy_ProfilePhoto_CustomOverrideBothInfo
case .everybody:
exceptionsInfo = presentationData.strings.Privacy_ProfilePhoto_CustomOverrideInfo
}
} else {
exceptionsInfo = presentationData.strings.PrivacyLastSeenSettings_CustomShareSettingsHelp
}
entries.append(.peersInfo(presentationData.theme, exceptionsInfo))
}
entries.append(.peersInfo(presentationData.theme, exceptionsInfo))
if case .voiceCalls = kind, let p2pMode = state.callP2PMode, let integrationAvailable = state.callIntegrationAvailable, let integrationEnabled = state.callIntegrationEnabled {
entries.append(.callsP2PHeader(presentationData.theme, presentationData.strings.Privacy_Calls_P2P.uppercased()))
@ -1149,10 +1183,15 @@ func selectivePrivacySettingsController(
return state.withUpdatedPhoneDiscoveryEnabled(value)
}
}, copyPhoneLink: { link in
UIPasteboard.general.string = link
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
if link == "premium" {
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .presence, forceDark: false, dismissed: nil)
pushControllerImpl?(controller, true)
} else {
UIPasteboard.general.string = link
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
}
}, setPublicPhoto: {
requestPublicPhotoSetup?({ result in
var result = result
@ -1183,6 +1222,16 @@ func selectivePrivacySettingsController(
}, openPremiumIntro: {
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .presence, forceDark: false, dismissed: nil)
pushControllerImpl?(controller, true)
}, displayLockedInfo: {
let presentationData = context.sharedContext.currentPresentationData.with({ $0 })
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .premiumPaywall(title: presentationData.strings.Privacy_Messages_PremiumToast_Title, text: presentationData.strings.Privacy_Messages_PremiumToast_Text, customUndoText: presentationData.strings.Privacy_Messages_PremiumToast_Action, timeout: nil, linkAction: { _ in
}), elevatedLayout: false, action: { action in
if case .undo = action {
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .presence, forceDark: false, dismissed: nil)
pushControllerImpl?(controller, true)
}
return false
}), nil)
})
let peer = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))

View File

@ -222,6 +222,11 @@ private func mergedResult(_ state: SearchMessagesState) -> SearchMessagesResult
}
func _internal_searchMessages(account: Account, location: SearchMessagesLocation, query: String, state: SearchMessagesState?, limit: Int32 = 100) -> Signal<(SearchMessagesResult, SearchMessagesState), NoError> {
if case let .peer(peerId, fromId, tags, reactions, threadId, minDate, maxDate) = location, fromId == nil, tags == nil, let reactions, !reactions.isEmpty, threadId == nil, minDate == nil, maxDate == 0 {
let _ = peerId
print("short cirquit")
}
let remoteSearchResult: Signal<(Api.messages.Messages?, Api.messages.Messages?), NoError>
switch location {
case let .peer(peerId, fromId, tags, reactions, threadId, minDate, maxDate):

View File

@ -214,6 +214,7 @@ public enum PresentationResourceKey: Int32 {
case chatInputSearchPanelCalendarImage
case chatInputSearchPanelMembersImage
case chatHistoryNavigationButtonBackground
case chatHistoryNavigationButtonImage
case chatHistoryNavigationUpButtonImage
case chatHistoryMentionsButtonImage

View File

@ -586,15 +586,24 @@ public struct PresentationResourcesChat {
})
}
public static func chatHistoryNavigationButtonBackground(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatHistoryNavigationButtonBackground.rawValue, { theme in
return generateImage(CGSize(width: 38.0, height: 38.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setLineWidth(0.5)
context.setStrokeColor(theme.chat.historyNavigation.strokeColor.cgColor)
context.strokeEllipse(in: CGRect(origin: CGPoint(x: 0.25, y: 0.25), size: CGSize(width: size.width - 0.5, height: size.height - 0.5)))
})
})
}
public static func chatHistoryNavigationButtonImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatHistoryNavigationButtonImage.rawValue, { theme in
return generateImage(CGSize(width: 38.0, height: 38.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setLineWidth(0.5)
context.setStrokeColor(theme.chat.historyNavigation.strokeColor.cgColor)
context.strokeEllipse(in: CGRect(origin: CGPoint(x: 0.25, y: 0.25), size: CGSize(width: size.width - 0.5, height: size.height - 0.5)))
context.setStrokeColor(theme.chat.historyNavigation.foregroundColor.cgColor)
context.setStrokeColor(theme.rootController.navigationBar.accentTextColor.cgColor)
context.setLineWidth(1.5)
let position = CGPoint(x: 9.0 - 0.5, y: 23.0)
@ -610,10 +619,8 @@ public struct PresentationResourcesChat {
return theme.image(PresentationResourceKey.chatHistoryNavigationUpButtonImage.rawValue, { theme in
return generateImage(CGSize(width: 38.0, height: 38.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setLineWidth(0.5)
context.setStrokeColor(theme.chat.historyNavigation.strokeColor.cgColor)
context.strokeEllipse(in: CGRect(origin: CGPoint(x: 0.25, y: 0.25), size: CGSize(width: size.width - 0.5, height: size.height - 0.5)))
context.setStrokeColor(theme.chat.historyNavigation.foregroundColor.cgColor)
context.setStrokeColor(theme.rootController.navigationBar.accentTextColor.cgColor)
context.setLineWidth(1.5)
context.translateBy(x: size.width * 0.5, y: size.height * 0.5)
@ -632,11 +639,6 @@ public struct PresentationResourcesChat {
return theme.image(PresentationResourceKey.chatHistoryMentionsButtonImage.rawValue, { theme in
return generateImage(CGSize(width: 38.0, height: 38.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(theme.chat.historyNavigation.fillColor.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(x: 0.5, y: 0.5), size: CGSize(width: size.width - 1.0, height: size.height - 1.0)))
context.setLineWidth(0.5)
context.setStrokeColor(theme.chat.historyNavigation.strokeColor.cgColor)
context.strokeEllipse(in: CGRect(origin: CGPoint(x: 0.25, y: 0.25), size: CGSize(width: size.width - 0.5, height: size.height - 0.5)))
if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/NavigateToMentions"), color: theme.chat.historyNavigation.foregroundColor), let cgImage = image.cgImage {
context.draw(cgImage, in: CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0)), size: image.size))
@ -649,11 +651,6 @@ public struct PresentationResourcesChat {
return theme.image(PresentationResourceKey.chatHistoryReactionsButtonImage.rawValue, { theme in
return generateImage(CGSize(width: 38.0, height: 38.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(theme.chat.historyNavigation.fillColor.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(x: 0.5, y: 0.5), size: CGSize(width: size.width - 1.0, height: size.height - 1.0)))
context.setLineWidth(0.5)
context.setStrokeColor(theme.chat.historyNavigation.strokeColor.cgColor)
context.strokeEllipse(in: CGRect(origin: CGPoint(x: 0.25, y: 0.25), size: CGSize(width: size.width - 0.5, height: size.height - 0.5)))
if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Reactions"), color: theme.chat.historyNavigation.foregroundColor), let cgImage = image.cgImage {
context.draw(cgImage, in: CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0)), size: image.size))

View File

@ -1279,7 +1279,7 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
self.statusNode = statusNode
self.addSubnode(statusNode)
statusNode.reactionSelected = { [weak self] value in
statusNode.reactionSelected = { [weak self] _, value in
guard let self, let message = self.message else {
return
}

View File

@ -55,7 +55,7 @@ public class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
self.addButtonNode.addTarget(self, action: #selector(self.addButtonPressed), forControlEvents: .touchUpInside)
self.messageButtonNode.addTarget(self, action: #selector(self.messageButtonPressed), forControlEvents: .touchUpInside)
self.dateAndStatusNode.reactionSelected = { [weak self] value in
self.dateAndStatusNode.reactionSelected = { [weak self] _, value in
guard let strongSelf = self, let item = strongSelf.item else {
return
}

View File

@ -316,7 +316,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
}
}
}
public var reactionSelected: ((MessageReaction.Reaction) -> Void)?
public var reactionSelected: ((ReactionButtonAsyncNode, MessageReaction.Reaction) -> Void)?
public var openReactionPreview: ((ContextGesture?, ContextExtractedContentContainingView, MessageReaction.Reaction) -> Void)?
override public init() {
@ -739,11 +739,11 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
resultingHeight = layoutSize.height
reactionButtonsResult = reactionButtonsContainer.update(
context: arguments.context,
action: { value in
action: { itemNode, value in
guard let strongSelf = self else {
return
}
strongSelf.reactionSelected?(value)
strongSelf.reactionSelected?(itemNode, value)
},
reactions: [],
colors: reactionColors,
@ -752,6 +752,8 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
)
case let .trailingContent(contentWidth, reactionSettings):
if let reactionSettings = reactionSettings, !reactionSettings.displayInline {
let isTag = arguments.areReactionsTags
var totalReactionCount: Int = 0
for reaction in arguments.reactions {
totalReactionCount += Int(reaction.count)
@ -759,11 +761,15 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
reactionButtonsResult = reactionButtonsContainer.update(
context: arguments.context,
action: { value in
action: { itemNode, value in
guard let strongSelf = self else {
return
}
strongSelf.reactionSelected?(value)
if isTag {
strongSelf.openReactionPreview?(nil, itemNode.containerView, value)
} else {
strongSelf.reactionSelected?(itemNode, value)
}
},
reactions: arguments.reactions.map { reaction in
var centerAnimation: TelegramMediaFile?
@ -815,11 +821,11 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
} else {
reactionButtonsResult = reactionButtonsContainer.update(
context: arguments.context,
action: { value in
action: { itemNode, value in
guard let strongSelf = self else {
return
}
strongSelf.reactionSelected?(value)
strongSelf.reactionSelected?(itemNode, value)
},
reactions: [],
colors: reactionColors,

View File

@ -64,7 +64,7 @@ public class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode {
}
}
self.interactiveFileNode.dateAndStatusNode.reactionSelected = { [weak self] value in
self.interactiveFileNode.dateAndStatusNode.reactionSelected = { [weak self] _, value in
guard let strongSelf = self, let item = strongSelf.item else {
return
}

View File

@ -130,7 +130,7 @@ public class ChatMessageGiveawayBubbleContentNode: ChatMessageBubbleContentNode,
self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
self.dateAndStatusNode.reactionSelected = { [weak self] value in
self.dateAndStatusNode.reactionSelected = { [weak self] _, value in
guard let strongSelf = self, let item = strongSelf.item else {
return
}

View File

@ -144,7 +144,7 @@ public class ChatMessageInstantVideoBubbleContentNode: ChatMessageBubbleContentN
}
}
self.interactiveFileNode.dateAndStatusNode.reactionSelected = { [weak self] value in
self.interactiveFileNode.dateAndStatusNode.reactionSelected = { [weak self] _, value in
guard let strongSelf = self, let item = strongSelf.item else {
return
}

View File

@ -120,11 +120,15 @@ public final class MessageReactionButtonsNode: ASDisplayNode {
let reactionButtonsResult = self.container.update(
context: context,
action: { [weak self] value in
guard let strongSelf = self else {
action: { [weak self] itemView, value in
guard let self else {
return
}
strongSelf.reactionSelected?(value)
if reactions.isTags {
self.openReactionPreview?(nil, itemView.containerView, value)
} else {
self.reactionSelected?(value)
}
},
reactions: reactions.reactions.map { reaction in
var centerAnimation: TelegramMediaFile?

View File

@ -714,7 +714,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
strongSelf.addSubnode(statusNode)
statusNode.reactionSelected = { [weak strongSelf] value in
statusNode.reactionSelected = { [weak strongSelf] _, value in
guard let strongSelf, let item = strongSelf.item else {
return
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "tag_24.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,95 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 2.334961 4.834961 cm
0.000000 0.000000 0.000000 scn
3.665000 14.330017 m
1.640877 14.330017 0.000000 12.689140 0.000000 10.665017 c
0.000000 3.665017 l
0.000000 1.640893 1.640876 0.000017 3.665000 0.000017 c
11.913676 0.000017 l
13.215668 0.000017 14.458418 0.544132 15.341534 1.500839 c
18.901434 5.357393 l
19.843767 6.378253 19.843767 7.951766 18.901438 8.972626 c
15.341534 12.829191 l
14.458418 13.785901 13.215667 14.330017 11.913673 14.330017 c
3.665000 14.330017 l
h
1.330000 10.665017 m
1.330000 11.954601 2.375415 13.000017 3.665000 13.000017 c
11.913673 13.000017 l
12.844466 13.000017 13.732906 12.611030 14.364244 11.927080 c
17.924149 8.070515 l
18.396196 7.559127 18.396196 6.770894 17.924147 6.259506 c
14.364245 2.402952 l
13.732907 1.719004 12.844467 1.330017 11.913676 1.330017 c
3.665000 1.330017 l
2.375415 1.330017 1.330000 2.375432 1.330000 3.665017 c
1.330000 10.665017 l
h
13.665039 5.665024 m
14.493466 5.665024 15.165039 6.336596 15.165039 7.165024 c
15.165039 7.993451 14.493466 8.665024 13.665039 8.665024 c
12.836612 8.665024 12.165039 7.993451 12.165039 7.165024 c
12.165039 6.336596 12.836612 5.665024 13.665039 5.665024 c
h
f*
n
Q
endstream
endobj
3 0 obj
1231
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000001321 00000 n
0000001344 00000 n
0000001517 00000 n
0000001591 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
1650
%%EOF

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "tagfilter_24.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,258 @@
%PDF-1.7
1 0 obj
<< /Type /XObject
/Length 2 0 R
/Group << /Type /Group
/S /Transparency
>>
/Subtype /Form
/Resources << >>
/BBox [ 0.000000 0.000000 24.000000 24.000000 ]
>>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 2.334961 4.834961 cm
0.000000 0.000000 0.000000 scn
7.665000 14.330017 m
7.297730 14.330017 7.000000 14.032287 7.000000 13.665017 c
7.000000 13.297748 7.297730 13.000017 7.665000 13.000017 c
11.913673 13.000017 l
12.844466 13.000017 13.732906 12.611030 14.364244 11.927080 c
17.924149 8.070515 l
18.396196 7.559127 18.396196 6.770894 17.924147 6.259506 c
14.364245 2.402952 l
13.732907 1.719004 12.844467 1.330017 11.913676 1.330017 c
3.665000 1.330017 l
2.375415 1.330017 1.330000 2.375432 1.330000 3.665016 c
1.330000 5.165009 l
1.330000 5.532279 1.032269 5.830009 0.665000 5.830009 c
0.297731 5.830009 0.000000 5.532279 0.000000 5.165009 c
0.000000 3.665016 l
0.000000 1.640892 1.640877 0.000017 3.665000 0.000017 c
11.913676 0.000017 l
13.215668 0.000017 14.458418 0.544132 15.341534 1.500839 c
18.901434 5.357393 l
19.843767 6.378253 19.843767 7.951766 18.901438 8.972626 c
15.341534 12.829191 l
14.458418 13.785901 13.215667 14.330017 11.913673 14.330017 c
7.665000 14.330017 l
h
13.665039 5.665024 m
14.493466 5.665024 15.165039 6.336596 15.165039 7.165024 c
15.165039 7.993451 14.493466 8.665024 13.665039 8.665024 c
12.836612 8.665024 12.165039 7.993451 12.165039 7.165024 c
12.165039 6.336596 12.836612 5.665024 13.665039 5.665024 c
h
f*
n
Q
q
1.000000 0.000000 -0.000000 1.000000 0.000000 10.080505 cm
0.000000 0.000000 0.000000 scn
3.445300 2.622628 m
3.076424 2.069314 l
3.445300 2.622628 l
h
4.445300 1.955961 m
4.076425 1.402648 l
4.445300 1.955961 l
h
6.240744 6.700362 m
6.745649 6.267586 l
6.240744 6.700362 l
h
1.414964 8.268703 m
0.910058 7.835927 l
1.414964 8.268703 l
h
2.174221 9.254495 m
6.825779 9.254495 l
6.825779 10.584495 l
2.174221 10.584495 l
2.174221 9.254495 l
h
7.080131 8.701480 m
5.735838 7.133138 l
6.745649 6.267586 l
8.089942 7.835927 l
7.080131 8.701480 l
h
5.335000 6.049571 m
5.335000 2.788012 l
6.665000 2.788012 l
6.665000 6.049571 l
5.335000 6.049571 l
h
4.814176 2.509274 m
3.814175 3.175941 l
3.076424 2.069314 l
4.076425 1.402648 l
4.814176 2.509274 l
h
3.665000 3.454679 m
3.665000 6.049571 l
2.335000 6.049571 l
2.335000 3.454679 l
3.665000 3.454679 l
h
3.264162 7.133138 m
1.919870 8.701480 l
0.910058 7.835927 l
2.254351 6.267586 l
3.264162 7.133138 l
h
3.665000 6.049571 m
3.665000 6.447025 3.522822 6.831368 3.264162 7.133138 c
2.254351 6.267586 l
2.306394 6.206869 2.335000 6.129539 2.335000 6.049571 c
3.665000 6.049571 l
h
3.814175 3.175941 m
3.720979 3.238072 3.665000 3.342670 3.665000 3.454679 c
2.335000 3.454679 l
2.335000 2.897980 2.613223 2.378115 3.076424 2.069314 c
3.814175 3.175941 l
h
5.335000 2.788012 m
5.335000 2.520448 5.036801 2.360857 4.814176 2.509274 c
4.076425 1.402648 l
5.182908 0.664992 6.665000 1.458183 6.665000 2.788012 c
5.335000 2.788012 l
h
5.735838 7.133138 m
5.477178 6.831368 5.335000 6.447025 5.335000 6.049571 c
6.665000 6.049571 l
6.665000 6.129539 6.693606 6.206869 6.745649 6.267586 c
5.735838 7.133138 l
h
6.825779 9.254495 m
7.111988 9.254495 7.266392 8.918785 7.080131 8.701480 c
8.089942 7.835927 l
9.015692 8.915968 8.248278 10.584495 6.825779 10.584495 c
6.825779 9.254495 l
h
2.174221 10.584495 m
0.751723 10.584495 -0.015691 8.915968 0.910058 7.835927 c
1.919870 8.701480 l
1.733608 8.918785 1.888012 9.254495 2.174221 9.254495 c
2.174221 10.584495 l
h
f
n
Q
endstream
endobj
2 0 obj
3329
endobj
3 0 obj
<< /Type /XObject
/Length 4 0 R
/Group << /Type /Group
/S /Transparency
>>
/Subtype /Form
/Resources << >>
/BBox [ 0.000000 0.000000 24.000000 24.000000 ]
>>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
0.000000 0.000000 0.000000 scn
0.000000 24.000000 m
24.000000 24.000000 l
24.000000 0.000000 l
0.000000 0.000000 l
0.000000 24.000000 l
h
f
n
Q
endstream
endobj
4 0 obj
232
endobj
5 0 obj
<< /XObject << /X1 1 0 R >>
/ExtGState << /E1 << /SMask << /Type /Mask
/G 3 0 R
/S /Alpha
>>
/Type /ExtGState
>> >>
>>
endobj
6 0 obj
<< /Length 7 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
/E1 gs
/X1 Do
Q
endstream
endobj
7 0 obj
46
endobj
8 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
/Resources 5 0 R
/Contents 6 0 R
/Parent 9 0 R
>>
endobj
9 0 obj
<< /Kids [ 8 0 R ]
/Count 1
/Type /Pages
>>
endobj
10 0 obj
<< /Pages 9 0 R
/Type /Catalog
>>
endobj
xref
0 11
0000000000 65535 f
0000000010 00000 n
0000003587 00000 n
0000003610 00000 n
0000004090 00000 n
0000004112 00000 n
0000004410 00000 n
0000004512 00000 n
0000004533 00000 n
0000004706 00000 n
0000004780 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 10 0 R
/Size 11
>>
startxref
4840
%%EOF

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "tagcrossed_24.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,109 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 2.334961 3.205139 cm
0.000000 0.000000 0.000000 scn
1.135265 17.265064 m
0.875566 17.524763 0.454512 17.524763 0.194813 17.265064 c
-0.064886 17.005365 -0.064886 16.584312 0.194813 16.324614 c
16.194813 0.324612 l
16.454512 0.064913 16.875566 0.064913 17.135265 0.324612 c
17.394964 0.584311 17.394964 1.005365 17.135265 1.265064 c
15.306840 3.093491 l
15.318465 3.105813 15.330030 3.118204 15.341534 3.130667 c
18.901434 6.987221 l
19.843767 8.008080 19.843767 9.581594 18.901438 10.602453 c
15.341534 14.459019 l
14.458418 15.415730 13.215667 15.959845 11.913673 15.959845 c
3.665000 15.959845 l
3.293929 15.959845 2.935738 15.904698 2.598176 15.802155 c
1.135265 17.265064 l
h
3.770485 14.629845 m
14.365832 4.034498 l
17.924147 7.889334 l
18.396196 8.400722 18.396196 9.188954 17.924149 9.700342 c
14.364244 13.556908 l
13.732906 14.240857 12.844466 14.629845 11.913673 14.629845 c
3.770485 14.629845 l
h
0.000000 12.294845 m
0.000000 13.066666 0.238580 13.782763 0.646016 14.373411 c
1.611738 13.407689 l
1.432060 13.076872 1.330000 12.697777 1.330000 12.294845 c
1.330000 5.294845 l
1.330000 4.005260 2.375415 2.959845 3.665000 2.959845 c
11.913676 2.959845 l
11.961413 2.959845 12.009040 2.960868 12.056525 2.962901 c
13.206793 1.812634 l
12.790398 1.692487 12.355447 1.629845 11.913676 1.629845 c
3.665000 1.629845 l
1.640876 1.629845 0.000000 3.270720 0.000000 5.294845 c
0.000000 12.294845 l
h
13.665039 7.294851 m
14.493466 7.294851 15.165039 7.966424 15.165039 8.794851 c
15.165039 9.623279 14.493466 10.294851 13.665039 10.294851 c
12.836612 10.294851 12.165039 9.623279 12.165039 8.794851 c
12.165039 7.966424 12.836612 7.294851 13.665039 7.294851 c
h
f*
n
Q
endstream
endobj
3 0 obj
1740
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000001830 00000 n
0000001853 00000 n
0000002026 00000 n
0000002100 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
2159
%%EOF

View File

@ -519,4 +519,6 @@ func updateChatPresentationInterfaceStateImpl(
} else {
selfController.chatDisplayNode.historyNode.updateTag(tag: nil)
}
selfController.updateDownButtonVisibility()
}

View File

@ -6953,7 +6953,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return
}
if self.presentationInterfaceState.search != nil && self.presentationInterfaceState.historyFilter != nil {
self.chatDisplayNode.dismissInput()
self.chatDisplayNode.historyNode.addAfterTransactionsCompleted { [weak self] in
guard let self else {
return
}
self.chatDisplayNode.dismissInput()
}
}
}
@ -6987,6 +6993,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.chatDisplayNode.loadingPlaceholderNode?.addContentOffset(offset: offset, transition: transition)
}
strongSelf.chatDisplayNode.messageTransitionNode.addExternalOffset(offset: offset, transition: transition, itemNode: itemNode)
}
self.chatDisplayNode.historyNode.hasPlentyOfMessagesUpdated = { [weak self] hasPlentyOfMessages in
@ -8170,22 +8177,37 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
self.chatDisplayNode.navigateButtons.downPressed = { [weak self] in
if let strongSelf = self, strongSelf.isNodeLoaded {
if let messageId = strongSelf.historyNavigationStack.removeLast() {
strongSelf.navigateToMessage(from: nil, to: .id(messageId.id, NavigateToMessageParams(timestamp: nil, quote: nil)), rememberInStack: false)
guard let self else {
return
}
if self.presentationInterfaceState.search?.resultsState != nil {
self.interfaceInteraction?.navigateMessageSearch(.later)
} else {
if let messageId = self.historyNavigationStack.removeLast() {
self.navigateToMessage(from: nil, to: .id(messageId.id, NavigateToMessageParams(timestamp: nil, quote: nil)), rememberInStack: false)
} else {
if case .known = strongSelf.chatDisplayNode.historyNode.visibleContentOffset() {
strongSelf.chatDisplayNode.historyNode.scrollToEndOfHistory()
} else if case .peer = strongSelf.chatLocation {
strongSelf.scrollToEndOfHistory()
} else if case .replyThread = strongSelf.chatLocation {
strongSelf.scrollToEndOfHistory()
if case .known = self.chatDisplayNode.historyNode.visibleContentOffset() {
self.chatDisplayNode.historyNode.scrollToEndOfHistory()
} else if case .peer = self.chatLocation {
self.scrollToEndOfHistory()
} else if case .replyThread = self.chatLocation {
self.scrollToEndOfHistory()
} else {
strongSelf.chatDisplayNode.historyNode.scrollToEndOfHistory()
self.chatDisplayNode.historyNode.scrollToEndOfHistory()
}
}
}
}
self.chatDisplayNode.navigateButtons.upPressed = { [weak self] in
guard let self else {
return
}
if self.presentationInterfaceState.search?.resultsState != nil {
self.interfaceInteraction?.navigateMessageSearch(.earlier)
}
}
self.chatDisplayNode.navigateButtons.mentionsPressed = { [weak self] in
if let strongSelf = self, strongSelf.isNodeLoaded, let peerId = strongSelf.chatLocation.peerId {
@ -9054,7 +9076,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return state.updatedSearch(ChatSearchData(query: "", domain: .members, domainSuggestionContext: .none, resultsState: nil))
} else if let search = state.search {
switch search.domain {
case .everything:
case .everything, .tag:
return state
case .members:
return state.updatedSearch(ChatSearchData(query: "", domain: .everything, domainSuggestionContext: .none, resultsState: nil))
@ -10800,7 +10822,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
}
return state.updatedHistoryFilter(updatedFilter)
var state = state.updatedHistoryFilter(updatedFilter)
if let updatedFilter, !updatedFilter.isActive, let reactionData = updatedFilter.customTags.first, let reaction = ReactionsMessageAttribute.reactionFromMessageTag(tag: reactionData) {
state = state.updatedSearch(ChatSearchData(domain: .tag(reaction)))
} else {
state = state.updatedSearch(ChatSearchData())
}
return state
})
}, requestLayout: { [weak self] transition in
if let strongSelf = self, let layout = strongSelf.validLayout {
@ -15665,8 +15693,34 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
func updateDownButtonVisibility() {
let recordingMediaMessage = self.audioRecorderValue != nil || self.videoRecorderValue != nil || self.presentationInterfaceState.recordedMediaPreview != nil
self.chatDisplayNode.navigateButtons.displayDownButton = self.shouldDisplayDownButton && !recordingMediaMessage
if let search = self.presentationInterfaceState.search, let results = search.resultsState {
let resultCount = results.messageIndices.count
var resultIndex: Int?
if let currentId = results.currentId, let index = results.messageIndices.firstIndex(where: { $0.id == currentId }) {
resultIndex = index
} else {
resultIndex = nil
}
if let resultIndex {
self.chatDisplayNode.navigateButtons.directionButtonState = ChatHistoryNavigationButtons.DirectionState(
up: ChatHistoryNavigationButtons.ButtonState(isEnabled: resultIndex != 0),
down: ChatHistoryNavigationButtons.ButtonState(isEnabled: resultIndex != resultCount - 1)
)
} else {
self.chatDisplayNode.navigateButtons.directionButtonState = ChatHistoryNavigationButtons.DirectionState(
up: ChatHistoryNavigationButtons.ButtonState(isEnabled: false),
down: ChatHistoryNavigationButtons.ButtonState(isEnabled: false)
)
}
} else {
let recordingMediaMessage = self.audioRecorderValue != nil || self.videoRecorderValue != nil || self.presentationInterfaceState.recordedMediaPreview != nil
self.chatDisplayNode.navigateButtons.directionButtonState = ChatHistoryNavigationButtons.DirectionState(
up: nil,
down: (self.shouldDisplayDownButton && !recordingMediaMessage) ? ChatHistoryNavigationButtons.ButtonState(isEnabled: true) : nil
)
}
}
func updateTextInputState(_ textInputState: ChatTextInputState) {

View File

@ -920,6 +920,11 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if hasChatThemeScreen {
return true
}
if strongSelf.chatPresentationInterfaceState.search != nil {
return true
}
return false
}
@ -2655,7 +2660,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if let _ = self.chatPresentationInterfaceState.search, let interfaceInteraction = self.interfaceInteraction {
var activate = false
if self.searchNavigationNode == nil {
activate = true
if !self.chatPresentationInterfaceState.hasSearchTags {
activate = true
}
self.searchNavigationNode = ChatSearchNavigationContentNode(context: self.context, theme: self.chatPresentationInterfaceState.theme, strings: self.chatPresentationInterfaceState.strings, chatLocation: self.chatPresentationInterfaceState.chatLocation, interaction: interfaceInteraction, presentationInterfaceState: self.chatPresentationInterfaceState)
}
self.navigationBar?.setContentNode(self.searchNavigationNode, animated: transitionIsAnimated)

View File

@ -19,23 +19,26 @@ extension ChatControllerImpl {
if message.areReactionsTags(accountPeerId: self.context.account.peerId) {
var items: [ContextMenuItem] = []
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_ReactionContextMenu_FilterByTag, icon: { _ in
return nil
}, action: { [weak self] _, a in
guard let self else {
let tags: [EngineMessage.CustomTag] = [ReactionsMessageAttribute.messageTag(reaction: value)]
if self.presentationInterfaceState.historyFilter?.customTags != tags {
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_ReactionContextMenu_FilterByTag, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/TagFilter"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, a in
guard let self else {
a(.default)
return
}
self.interfaceInteraction?.updateHistoryFilter { _ in
return ChatPresentationInterfaceState.HistoryFilter(customTags: tags, isActive: true)
}
a(.default)
return
}
self.updateChatPresentationInterfaceState(animated: true, interactive: true, { state in
return state
.updatedSearch(ChatSearchData())
.updatedHistoryFilter(ChatPresentationInterfaceState.HistoryFilter(customTags: [ReactionsMessageAttribute.messageTag(reaction: value)], isActive: true))
})
a(.default)
})))
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_ReactionContextMenu_RemoveTag, textColor: .destructive, icon: { _ in
return nil
})))
}
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_ReactionContextMenu_RemoveTag, textColor: .destructive, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/TagRemove"), color: theme.contextMenu.destructiveColor)
}, action: { [weak self] _, a in
a(.dismissWithoutContent)
guard let self else {

View File

@ -47,6 +47,8 @@ extension ChatControllerImpl {
switch search.domain {
case .everything:
derivedSearchState = ChatSearchState(query: search.query, location: .peer(peerId: peerId, fromId: nil, tags: nil, reactions: reactions, threadId: threadId, minDate: nil, maxDate: nil), loadMoreState: loadMoreStateFromResultsState(search.resultsState))
case let .tag(reaction):
derivedSearchState = ChatSearchState(query: search.query, location: .peer(peerId: peerId, fromId: nil, tags: nil, reactions: reactions ?? [reaction], threadId: threadId, minDate: nil, maxDate: nil), loadMoreState: loadMoreStateFromResultsState(search.resultsState))
case .members:
derivedSearchState = nil
case let .member(peer):

View File

@ -3684,6 +3684,11 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
}
public func updateLayout(transition: ContainedViewLayoutTransition, updateSizeAndInsets: ListViewUpdateSizeAndInsets, additionalScrollDistance: CGFloat, scrollToTop: Bool, completion: @escaping () -> Void) {
/*if updateSizeAndInsets.insets.top == 83.0 {
if !transition.isAnimated {
assert(true)
}
}*/
var scrollToItem: ListViewScrollToItem?
var postScrollToItem: ListViewScrollToItem?
if scrollToTop, case .known = self.visibleContentOffset() {

View File

@ -17,10 +17,11 @@ enum ChatHistoryNavigationButtonType {
class ChatHistoryNavigationButtonNode: ContextControllerSourceNode {
let containerNode: ContextExtractedContentContainingNode
private let buttonNode: HighlightTrackingButtonNode
let buttonNode: HighlightTrackingButtonNode
private let backgroundNode: NavigationBackgroundNode
private var backgroundContent: WallpaperBubbleBackgroundNode?
private let imageNode: ASImageNode
let backgroundImageNode: ASImageNode
let imageNode: ASImageNode
private let badgeBackgroundNode: ASImageNode
private let badgeTextNode: ImmediateAnimatedCountLabelNode
@ -56,6 +57,11 @@ class ChatHistoryNavigationButtonNode: ContextControllerSourceNode {
self.backgroundNode = NavigationBackgroundNode(color: theme.chat.inputPanel.panelBackgroundColor)
self.backgroundImageNode = ASImageNode()
self.backgroundImageNode.image = PresentationResourcesChat.chatHistoryNavigationButtonBackground(theme)
self.backgroundImageNode.isLayerBacked = true
self.backgroundImageNode.displayWithoutProcessing = true
self.imageNode = ASImageNode()
self.imageNode.displayWithoutProcessing = true
switch type {
@ -99,7 +105,9 @@ class ChatHistoryNavigationButtonNode: ContextControllerSourceNode {
self.backgroundNode.frame = CGRect(origin: CGPoint(), size: size)
self.backgroundNode.update(size: self.backgroundNode.bounds.size, cornerRadius: size.width / 2.0, transition: .immediate)
self.buttonNode.addSubnode(self.backgroundImageNode)
self.buttonNode.addSubnode(self.imageNode)
self.backgroundImageNode.frame = CGRect(origin: CGPoint(), size: size)
self.imageNode.frame = CGRect(origin: CGPoint(), size: size)
self.buttonNode.addSubnode(self.badgeBackgroundNode)
@ -123,6 +131,7 @@ class ChatHistoryNavigationButtonNode: ContextControllerSourceNode {
case .reactions:
self.imageNode.image = PresentationResourcesChat.chatHistoryReactionsButtonImage(theme)
}
self.backgroundImageNode.image = PresentationResourcesChat.chatHistoryNavigationButtonBackground(theme)
self.badgeBackgroundNode.image = PresentationResourcesChat.chatHistoryNavigationButtonBadgeImage(theme)
var segments: [AnimatedCountLabelNode.Segment] = []

View File

@ -1,4 +1,5 @@
import Foundation
import Foundation
import UIKit
import Display
import AsyncDisplayKit
@ -6,13 +7,32 @@ import TelegramPresentationData
import WallpaperBackgroundNode
final class ChatHistoryNavigationButtons: ASDisplayNode {
struct ButtonState: Equatable {
var isEnabled: Bool
init(isEnabled: Bool) {
self.isEnabled = isEnabled
}
}
struct DirectionState: Equatable {
var up: ButtonState?
var down: ButtonState?
init(up: ButtonState?, down: ButtonState?) {
self.up = up
self.down = down
}
}
private var theme: PresentationTheme
private var dateTimeFormat: PresentationDateTimeFormat
private let isChatRotated: Bool
let reactionsButton: ChatHistoryNavigationButtonNode
let mentionsButton: ChatHistoryNavigationButtonNode
private let downButton: ChatHistoryNavigationButtonNode
let downButton: ChatHistoryNavigationButtonNode
let upButton: ChatHistoryNavigationButtonNode
var downPressed: (() -> Void)? {
didSet {
@ -20,12 +40,18 @@ final class ChatHistoryNavigationButtons: ASDisplayNode {
}
}
var upPressed: (() -> Void)? {
didSet {
self.upButton.tapped = self.upPressed
}
}
var reactionsPressed: (() -> Void)?
var mentionsPressed: (() -> Void)?
var displayDownButton: Bool = false {
var directionButtonState: DirectionState = DirectionState(up: nil, down: nil) {
didSet {
if oldValue != self.displayDownButton {
if oldValue != self.directionButtonState {
let _ = self.updateLayout(transition: .animated(duration: 0.3, curve: .spring))
}
}
@ -86,11 +112,16 @@ final class ChatHistoryNavigationButtons: ASDisplayNode {
self.downButton.alpha = 0.0
self.downButton.isHidden = true
self.upButton = ChatHistoryNavigationButtonNode(theme: theme, backgroundNode: backgroundNode, type: isChatRotated ? .up : .down)
self.upButton.alpha = 0.0
self.upButton.isHidden = true
super.init()
self.addSubnode(self.reactionsButton)
self.addSubnode(self.mentionsButton)
self.addSubnode(self.downButton)
self.addSubnode(self.upButton)
self.reactionsButton.tapped = { [weak self] in
self?.reactionsPressed?()
@ -101,6 +132,7 @@ final class ChatHistoryNavigationButtons: ASDisplayNode {
}
self.downButton.isGestureEnabled = false
self.upButton.isGestureEnabled = false
}
override func didLoad() {
@ -114,6 +146,7 @@ final class ChatHistoryNavigationButtons: ASDisplayNode {
self.reactionsButton.updateTheme(theme: theme, backgroundNode: backgroundNode)
self.mentionsButton.updateTheme(theme: theme, backgroundNode: backgroundNode)
self.downButton.updateTheme(theme: theme, backgroundNode: backgroundNode)
self.upButton.updateTheme(theme: theme, backgroundNode: backgroundNode)
}
private var absoluteRect: (CGRect, CGSize)?
@ -130,6 +163,11 @@ final class ChatHistoryNavigationButtons: ASDisplayNode {
mentionsFrame.origin.y += rect.minY
self.mentionsButton.update(rect: mentionsFrame, within: containerSize, transition: transition)
var upFrame = self.upButton.frame
upFrame.origin.x += rect.minX
upFrame.origin.y += rect.minY
self.upButton.update(rect: upFrame, within: containerSize, transition: transition)
var downFrame = self.downButton.frame
downFrame.origin.x += rect.minX
downFrame.origin.y += rect.minY
@ -139,11 +177,16 @@ final class ChatHistoryNavigationButtons: ASDisplayNode {
func updateLayout(transition: ContainedViewLayoutTransition) -> CGSize {
let buttonSize = CGSize(width: 38.0, height: 38.0)
let completeSize = CGSize(width: buttonSize.width, height: buttonSize.height * 2.0 + 12.0)
var upOffset: CGFloat = 0.0
var mentionsOffset: CGFloat = 0.0
var reactionsOffset: CGFloat = 0.0
if self.displayDownButton {
if let down = self.directionButtonState.down {
self.downButton.imageNode.alpha = down.isEnabled ? 1.0 : 0.5
self.downButton.buttonNode.isEnabled = down.isEnabled
mentionsOffset += buttonSize.height + 12.0
upOffset += buttonSize.height + 12.0
self.downButton.isHidden = false
transition.updateAlpha(node: self.downButton, alpha: 1.0)
@ -158,6 +201,25 @@ final class ChatHistoryNavigationButtons: ASDisplayNode {
transition.updateTransformScale(node: self.downButton, scale: 0.2)
}
if let up = self.directionButtonState.up {
self.upButton.imageNode.alpha = up.isEnabled ? 1.0 : 0.5
self.upButton.buttonNode.isEnabled = up.isEnabled
mentionsOffset += buttonSize.height + 12.0
self.upButton.isHidden = false
transition.updateAlpha(node: self.upButton, alpha: 1.0)
transition.updateTransformScale(node: self.upButton, scale: 1.0)
} else {
transition.updateAlpha(node: self.upButton, alpha: 0.0, completion: { [weak self] completed in
guard let strongSelf = self, completed else {
return
}
strongSelf.upButton.isHidden = true
})
transition.updateTransformScale(node: self.upButton, scale: 0.2)
}
if self.mentionCount != 0 {
reactionsOffset += buttonSize.height + 12.0
@ -190,10 +252,12 @@ final class ChatHistoryNavigationButtons: ASDisplayNode {
if self.isChatRotated {
transition.updatePosition(node: self.downButton, position: CGRect(origin: CGPoint(x: 0.0, y: completeSize.height - buttonSize.height), size: buttonSize).center)
transition.updatePosition(node: self.upButton, position: CGRect(origin: CGPoint(x: 0.0, y: completeSize.height - buttonSize.height - upOffset), size: buttonSize).center)
transition.updatePosition(node: self.mentionsButton, position: CGRect(origin: CGPoint(x: 0.0, y: completeSize.height - buttonSize.height - mentionsOffset), size: buttonSize).center)
transition.updatePosition(node: self.reactionsButton, position: CGRect(origin: CGPoint(x: 0.0, y: completeSize.height - buttonSize.height - mentionsOffset - reactionsOffset), size: buttonSize).center)
} else {
transition.updatePosition(node: self.downButton, position: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: buttonSize).center)
transition.updatePosition(node: self.upButton, position: CGRect(origin: CGPoint(x: 0.0, y: upOffset), size: buttonSize).center)
transition.updatePosition(node: self.mentionsButton, position: CGRect(origin: CGPoint(x: 0.0, y: mentionsOffset), size: buttonSize).center)
transition.updatePosition(node: self.reactionsButton, position: CGRect(origin: CGPoint(x: 0.0, y: mentionsOffset + reactionsOffset), size: buttonSize).center)
}

View File

@ -65,8 +65,8 @@ final class ChatSearchInputPanelNode: ChatInputPanelNode {
super.init()
self.addSubnode(self.upButton)
self.addSubnode(self.downButton)
//self.addSubnode(self.upButton)
//self.addSubnode(self.downButton)
self.addSubnode(self.calendarButton)
self.addSubnode(self.membersButton)
self.addSubnode(self.resultsButton)

View File

@ -105,7 +105,7 @@ final class ChatSearchNavigationContentNode: NavigationBarContentNode {
self.searchBar.updateThemeAndStrings(theme: SearchBarNodeTheme(theme: presentationInterfaceState.theme, hasBackground: false, hasSeparator: false), strings: presentationInterfaceState.strings)
switch search.domain {
case .everything:
case .everything, .tag:
self.searchBar.tokens = []
self.searchBar.prefixString = nil
let placeholderText: String

View File

@ -372,6 +372,10 @@ final class ChatSearchTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode, UISc
return ChatPresentationInterfaceState.HistoryFilter(customTags: tags, isActive: filter?.isActive ?? true)
}
})
if let itemView = self.itemViews[reaction] {
self.scrollView.scrollRectToVisible(itemView.frame.insetBy(dx: -46.0, dy: 0.0), animated: true)
}
})
self.itemViews[itemId] = itemView
self.scrollView.addSubview(itemView)