mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
[WIP] Tags
This commit is contained in:
parent
67fd1b6c2b
commit
d1493c4abd
@ -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?]()";
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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: {
|
||||
|
@ -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))
|
||||
|
@ -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):
|
||||
|
@ -214,6 +214,7 @@ public enum PresentationResourceKey: Int32 {
|
||||
case chatInputSearchPanelCalendarImage
|
||||
case chatInputSearchPanelMembersImage
|
||||
|
||||
case chatHistoryNavigationButtonBackground
|
||||
case chatHistoryNavigationButtonImage
|
||||
case chatHistoryNavigationUpButtonImage
|
||||
case chatHistoryMentionsButtonImage
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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?
|
||||
|
@ -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
|
||||
}
|
||||
|
12
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Tag.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Tag.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "tag_24.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
95
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Tag.imageset/tag_24.pdf
vendored
Normal file
95
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Tag.imageset/tag_24.pdf
vendored
Normal 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
|
12
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/TagFilter.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/TagFilter.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "tagfilter_24.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
258
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/TagFilter.imageset/tagfilter_24.pdf
vendored
Normal file
258
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/TagFilter.imageset/tagfilter_24.pdf
vendored
Normal 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
|
12
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/TagRemove.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/TagRemove.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "tagcrossed_24.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
109
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/TagRemove.imageset/tagcrossed_24.pdf
vendored
Normal file
109
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/TagRemove.imageset/tagcrossed_24.pdf
vendored
Normal 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
|
@ -519,4 +519,6 @@ func updateChatPresentationInterfaceStateImpl(
|
||||
} else {
|
||||
selfController.chatDisplayNode.historyNode.updateTag(tag: nil)
|
||||
}
|
||||
|
||||
selfController.updateDownButtonVisibility()
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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):
|
||||
|
@ -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() {
|
||||
|
@ -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] = []
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user