mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various improvements
This commit is contained in:
parent
7ec1611c08
commit
f51b91aa77
@ -10992,3 +10992,5 @@ Sorry for the inconvenience.";
|
|||||||
"Premium.MessageTags" = "Tags for Messages";
|
"Premium.MessageTags" = "Tags for Messages";
|
||||||
"Premium.MessageTagsInfo" = "Organize your Saved Messages with tags for quicker access.";
|
"Premium.MessageTagsInfo" = "Organize your Saved Messages with tags for quicker access.";
|
||||||
"Premium.MessageTags.Proceed" = "About Telegram Premium";
|
"Premium.MessageTags.Proceed" = "About Telegram Premium";
|
||||||
|
|
||||||
|
"Chat.SavedMessagesTabInfoText" = "Messages you send to **Saved Messages**";
|
||||||
|
@ -196,6 +196,7 @@ private enum ApplicationSpecificGlobalNotice: Int32 {
|
|||||||
case incomingVideoMessagePlayOnceTip = 62
|
case incomingVideoMessagePlayOnceTip = 62
|
||||||
case outgoingVideoMessagePlayOnceTip = 63
|
case outgoingVideoMessagePlayOnceTip = 63
|
||||||
case dismissedMessageTagsBadge = 64
|
case dismissedMessageTagsBadge = 64
|
||||||
|
case savedMessageTagLabelSuggestion = 65
|
||||||
|
|
||||||
var key: ValueBoxKey {
|
var key: ValueBoxKey {
|
||||||
let v = ValueBoxKey(length: 4)
|
let v = ValueBoxKey(length: 4)
|
||||||
@ -509,6 +510,10 @@ private struct ApplicationSpecificNoticeKeys {
|
|||||||
static func dismissedMessageTagsBadge() -> NoticeEntryKey {
|
static func dismissedMessageTagsBadge() -> NoticeEntryKey {
|
||||||
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.dismissedMessageTagsBadge.key)
|
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.dismissedMessageTagsBadge.key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func savedMessageTagLabelSuggestion() -> NoticeEntryKey {
|
||||||
|
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.savedMessageTagLabelSuggestion.key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ApplicationSpecificNotice {
|
public struct ApplicationSpecificNotice {
|
||||||
@ -2106,4 +2111,31 @@ public struct ApplicationSpecificNotice {
|
|||||||
}
|
}
|
||||||
|> take(1)
|
|> take(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func getSavedMessageTagLabelSuggestion(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Int32, NoError> {
|
||||||
|
return accountManager.transaction { transaction -> Int32 in
|
||||||
|
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.savedMessageTagLabelSuggestion())?.get(ApplicationSpecificCounterNotice.self) {
|
||||||
|
return value.value
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func incrementSavedMessageTagLabelSuggestion(accountManager: AccountManager<TelegramAccountManagerTypes>, count: Int = 1) -> Signal<Int, NoError> {
|
||||||
|
return accountManager.transaction { transaction -> Int in
|
||||||
|
var currentValue: Int32 = 0
|
||||||
|
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.savedMessageTagLabelSuggestion())?.get(ApplicationSpecificCounterNotice.self) {
|
||||||
|
currentValue = value.value
|
||||||
|
}
|
||||||
|
let previousValue = currentValue
|
||||||
|
currentValue += Int32(count)
|
||||||
|
|
||||||
|
if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) {
|
||||||
|
transaction.setNotice(ApplicationSpecificNoticeKeys.savedMessageTagLabelSuggestion(), entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Int(previousValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -394,7 +394,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
|||||||
selectedForeground: themeColors.reactionActiveForeground.argb,
|
selectedForeground: themeColors.reactionActiveForeground.argb,
|
||||||
extractedBackground: arguments.presentationData.theme.theme.contextMenu.backgroundColor.argb,
|
extractedBackground: arguments.presentationData.theme.theme.contextMenu.backgroundColor.argb,
|
||||||
extractedForeground: arguments.presentationData.theme.theme.contextMenu.primaryColor.argb,
|
extractedForeground: arguments.presentationData.theme.theme.contextMenu.primaryColor.argb,
|
||||||
extractedSelectedForeground: arguments.presentationData.theme.theme.contextMenu.primaryColor.argb,
|
extractedSelectedForeground: arguments.presentationData.theme.theme.overallDarkAppearance ? themeColors.reactionActiveForeground.argb : arguments.presentationData.theme.theme.list.itemCheckColors.foregroundColor.argb,
|
||||||
deselectedMediaPlaceholder: themeColors.reactionInactiveMediaPlaceholder.argb,
|
deselectedMediaPlaceholder: themeColors.reactionInactiveMediaPlaceholder.argb,
|
||||||
selectedMediaPlaceholder: themeColors.reactionActiveMediaPlaceholder.argb
|
selectedMediaPlaceholder: themeColors.reactionActiveMediaPlaceholder.argb
|
||||||
)
|
)
|
||||||
@ -408,7 +408,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
|||||||
selectedForeground: themeColors.reactionActiveForeground.argb,
|
selectedForeground: themeColors.reactionActiveForeground.argb,
|
||||||
extractedBackground: arguments.presentationData.theme.theme.contextMenu.backgroundColor.argb,
|
extractedBackground: arguments.presentationData.theme.theme.contextMenu.backgroundColor.argb,
|
||||||
extractedForeground: arguments.presentationData.theme.theme.contextMenu.primaryColor.argb,
|
extractedForeground: arguments.presentationData.theme.theme.contextMenu.primaryColor.argb,
|
||||||
extractedSelectedForeground: arguments.presentationData.theme.theme.list.itemCheckColors.foregroundColor.argb,
|
extractedSelectedForeground: arguments.presentationData.theme.theme.overallDarkAppearance ? themeColors.reactionActiveForeground.argb : arguments.presentationData.theme.theme.list.itemCheckColors.foregroundColor.argb,
|
||||||
deselectedMediaPlaceholder: themeColors.reactionInactiveMediaPlaceholder.argb,
|
deselectedMediaPlaceholder: themeColors.reactionInactiveMediaPlaceholder.argb,
|
||||||
selectedMediaPlaceholder: themeColors.reactionActiveMediaPlaceholder.argb
|
selectedMediaPlaceholder: themeColors.reactionActiveMediaPlaceholder.argb
|
||||||
)
|
)
|
||||||
|
@ -79,7 +79,7 @@ public final class MessageReactionButtonsNode: ASDisplayNode {
|
|||||||
selectedForeground: themeColors.reactionActiveForeground.argb,
|
selectedForeground: themeColors.reactionActiveForeground.argb,
|
||||||
extractedBackground: presentationData.theme.theme.contextMenu.backgroundColor.argb,
|
extractedBackground: presentationData.theme.theme.contextMenu.backgroundColor.argb,
|
||||||
extractedForeground: presentationData.theme.theme.contextMenu.primaryColor.argb,
|
extractedForeground: presentationData.theme.theme.contextMenu.primaryColor.argb,
|
||||||
extractedSelectedForeground: presentationData.theme.theme.contextMenu.primaryColor.argb,
|
extractedSelectedForeground: presentationData.theme.theme.overallDarkAppearance ? themeColors.reactionActiveForeground.argb : presentationData.theme.theme.list.itemCheckColors.foregroundColor.argb,
|
||||||
deselectedMediaPlaceholder: themeColors.reactionInactiveMediaPlaceholder.argb,
|
deselectedMediaPlaceholder: themeColors.reactionInactiveMediaPlaceholder.argb,
|
||||||
selectedMediaPlaceholder: themeColors.reactionActiveMediaPlaceholder.argb
|
selectedMediaPlaceholder: themeColors.reactionActiveMediaPlaceholder.argb
|
||||||
)
|
)
|
||||||
@ -92,7 +92,7 @@ public final class MessageReactionButtonsNode: ASDisplayNode {
|
|||||||
selectedForeground: themeColors.reactionActiveForeground.argb,
|
selectedForeground: themeColors.reactionActiveForeground.argb,
|
||||||
extractedBackground: presentationData.theme.theme.contextMenu.backgroundColor.argb,
|
extractedBackground: presentationData.theme.theme.contextMenu.backgroundColor.argb,
|
||||||
extractedForeground: presentationData.theme.theme.contextMenu.primaryColor.argb,
|
extractedForeground: presentationData.theme.theme.contextMenu.primaryColor.argb,
|
||||||
extractedSelectedForeground: presentationData.theme.theme.list.itemCheckColors.foregroundColor.argb,
|
extractedSelectedForeground: presentationData.theme.theme.overallDarkAppearance ? themeColors.reactionActiveForeground.argb : presentationData.theme.theme.list.itemCheckColors.foregroundColor.argb,
|
||||||
deselectedMediaPlaceholder: themeColors.reactionInactiveMediaPlaceholder.argb,
|
deselectedMediaPlaceholder: themeColors.reactionInactiveMediaPlaceholder.argb,
|
||||||
selectedMediaPlaceholder: themeColors.reactionActiveMediaPlaceholder.argb
|
selectedMediaPlaceholder: themeColors.reactionActiveMediaPlaceholder.argb
|
||||||
)
|
)
|
||||||
@ -110,7 +110,7 @@ public final class MessageReactionButtonsNode: ASDisplayNode {
|
|||||||
selectedForeground: themeColors.reactionActiveForeground.argb,
|
selectedForeground: themeColors.reactionActiveForeground.argb,
|
||||||
extractedBackground: presentationData.theme.theme.contextMenu.backgroundColor.argb,
|
extractedBackground: presentationData.theme.theme.contextMenu.backgroundColor.argb,
|
||||||
extractedForeground: presentationData.theme.theme.contextMenu.primaryColor.argb,
|
extractedForeground: presentationData.theme.theme.contextMenu.primaryColor.argb,
|
||||||
extractedSelectedForeground: presentationData.theme.theme.list.itemCheckColors.foregroundColor.argb,
|
extractedSelectedForeground: presentationData.theme.theme.contextMenu.primaryColor.argb,
|
||||||
deselectedMediaPlaceholder: themeColors.reactionInactiveMediaPlaceholder.argb,
|
deselectedMediaPlaceholder: themeColors.reactionInactiveMediaPlaceholder.argb,
|
||||||
selectedMediaPlaceholder: themeColors.reactionActiveMediaPlaceholder.argb
|
selectedMediaPlaceholder: themeColors.reactionActiveMediaPlaceholder.argb
|
||||||
)
|
)
|
||||||
|
@ -16,6 +16,7 @@ import TextNodeWithEntities
|
|||||||
import PremiumUI
|
import PremiumUI
|
||||||
import TooltipUI
|
import TooltipUI
|
||||||
import TopMessageReactions
|
import TopMessageReactions
|
||||||
|
import TelegramNotices
|
||||||
|
|
||||||
extension ChatControllerImpl {
|
extension ChatControllerImpl {
|
||||||
func openMessageContextMenu(message: Message, selectAll: Bool, node: ASDisplayNode, frame: CGRect, anyRecognizer: UIGestureRecognizer?, location: CGPoint?) -> Void {
|
func openMessageContextMenu(message: Message, selectAll: Bool, node: ASDisplayNode, frame: CGRect, anyRecognizer: UIGestureRecognizer?, location: CGPoint?) -> Void {
|
||||||
@ -396,13 +397,31 @@ extension ChatControllerImpl {
|
|||||||
standaloneReactionAnimation.frame = self.chatDisplayNode.bounds
|
standaloneReactionAnimation.frame = self.chatDisplayNode.bounds
|
||||||
self.chatDisplayNode.addSubnode(standaloneReactionAnimation)
|
self.chatDisplayNode.addSubnode(standaloneReactionAnimation)
|
||||||
}, completion: { [weak self, weak itemNode, weak targetView] in
|
}, completion: { [weak self, weak itemNode, weak targetView] in
|
||||||
guard let self, let itemNode = itemNode, let targetView = targetView else {
|
guard let self, let itemNode, let targetView else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = (ApplicationSpecificNotice.getSavedMessageTagLabelSuggestion(accountManager: self.context.sharedContext.accountManager)
|
||||||
|
|> take(1)
|
||||||
|
|> deliverOnMainQueue).startStandalone(next: { [weak self, weak targetView, weak itemNode] value in
|
||||||
|
guard let self, let targetView, let itemNode else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if value >= 3 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = self
|
|
||||||
let _ = itemNode
|
let _ = itemNode
|
||||||
let _ = targetView
|
|
||||||
|
//TODO:localize
|
||||||
|
let rect = self.chatDisplayNode.view.convert(targetView.bounds, from: targetView).insetBy(dx: -8.0, dy: -8.0)
|
||||||
|
let tooltipScreen = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: .plain(text: "Tap and hold to add a name to your tag"), location: .point(rect, .bottom), displayDuration: .custom(5.0), shouldDismissOnTouch: { point, _ in
|
||||||
|
return .ignore
|
||||||
|
})
|
||||||
|
self.present(tooltipScreen, in: .current)
|
||||||
|
|
||||||
|
let _ = ApplicationSpecificNotice.incrementSavedMessageTagLabelSuggestion(accountManager: self.context.sharedContext.accountManager).startStandalone()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
controller.dismiss()
|
controller.dismiss()
|
||||||
|
@ -1901,6 +1901,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
let current = listInsets
|
let current = listInsets
|
||||||
listInsets.top = current.bottom
|
listInsets.top = current.bottom
|
||||||
listInsets.bottom = current.top
|
listInsets.bottom = current.top
|
||||||
|
listInsets.top += 8.0
|
||||||
}
|
}
|
||||||
|
|
||||||
var displayTopDimNode = false
|
var displayTopDimNode = false
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
import UIKit
|
||||||
import Postbox
|
import Postbox
|
||||||
import TelegramCore
|
import TelegramCore
|
||||||
import TemporaryCachedPeerDataManager
|
import TemporaryCachedPeerDataManager
|
||||||
@ -7,6 +8,9 @@ import AccountContext
|
|||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import ChatHistoryEntry
|
import ChatHistoryEntry
|
||||||
import ChatMessageItemCommon
|
import ChatMessageItemCommon
|
||||||
|
import TextFormat
|
||||||
|
import Markdown
|
||||||
|
import Display
|
||||||
|
|
||||||
func chatHistoryEntriesForView(
|
func chatHistoryEntriesForView(
|
||||||
location: ChatLocation,
|
location: ChatLocation,
|
||||||
@ -15,6 +19,7 @@ func chatHistoryEntriesForView(
|
|||||||
includeEmptyEntry: Bool,
|
includeEmptyEntry: Bool,
|
||||||
includeChatInfoEntry: Bool,
|
includeChatInfoEntry: Bool,
|
||||||
includeSearchEntry: Bool,
|
includeSearchEntry: Bool,
|
||||||
|
includeEmbeddedSavedChatInfo: Bool,
|
||||||
reverse: Bool,
|
reverse: Bool,
|
||||||
groupMessages: Bool,
|
groupMessages: Bool,
|
||||||
reverseGroupedMessages: Bool,
|
reverseGroupedMessages: Bool,
|
||||||
@ -454,6 +459,56 @@ func chatHistoryEntriesForView(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if includeEmbeddedSavedChatInfo, let peerId = location.peerId {
|
||||||
|
if !view.isLoading && view.laterId == nil {
|
||||||
|
let string = presentationData.strings.Chat_SavedMessagesTabInfoText
|
||||||
|
let formattedString = parseMarkdownIntoAttributedString(
|
||||||
|
string,
|
||||||
|
attributes: MarkdownAttributes(
|
||||||
|
body: MarkdownAttributeSet(font: Font.regular(15.0), textColor: .black),
|
||||||
|
bold: MarkdownAttributeSet(font: Font.regular(15.0), textColor: .white),
|
||||||
|
link: MarkdownAttributeSet(font: Font.regular(15.0), textColor: .black),
|
||||||
|
linkAttribute: { url in
|
||||||
|
return ("URL", url)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
var entities: [MessageTextEntity] = []
|
||||||
|
formattedString.enumerateAttribute(.foregroundColor, in: NSRange(location: 0, length: formattedString.length), options: [], using: { value, range, _ in
|
||||||
|
if let value = value as? UIColor, value == .white {
|
||||||
|
entities.append(MessageTextEntity(range: range.lowerBound ..< range.upperBound, type: .Bold))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
let message = Message(
|
||||||
|
stableId: UInt32.max - 1001,
|
||||||
|
stableVersion: 0,
|
||||||
|
id: MessageId(peerId: peerId, namespace: Namespaces.Message.Local, id: 123),
|
||||||
|
globallyUniqueId: nil,
|
||||||
|
groupingKey: nil,
|
||||||
|
groupInfo: nil,
|
||||||
|
threadId: nil,
|
||||||
|
timestamp: Int32.max - 1,
|
||||||
|
flags: [.Incoming],
|
||||||
|
tags: [],
|
||||||
|
globalTags: [],
|
||||||
|
localTags: [],
|
||||||
|
customTags: [],
|
||||||
|
forwardInfo: nil,
|
||||||
|
author: nil,
|
||||||
|
text: "",
|
||||||
|
attributes: [],
|
||||||
|
media: [TelegramMediaAction(action: .customText(text: formattedString.string, entities: entities, additionalAttributes: nil))],
|
||||||
|
peers: SimpleDictionary<PeerId, Peer>(),
|
||||||
|
associatedMessages: SimpleDictionary<MessageId, Message>(),
|
||||||
|
associatedMessageIds: [],
|
||||||
|
associatedMedia: [:],
|
||||||
|
associatedThreadInfo: nil,
|
||||||
|
associatedStories: [:]
|
||||||
|
)
|
||||||
|
entries.append(.MessageEntry(message, presentationData, false, nil, .none, ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false, isCentered: false, authorStoryStats: nil)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if reverse {
|
if reverse {
|
||||||
return entries.reversed()
|
return entries.reversed()
|
||||||
|
@ -1697,6 +1697,11 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
|||||||
|
|
||||||
let associatedData = extractAssociatedData(chatLocation: chatLocation, view: view, automaticDownloadNetworkType: networkType, animatedEmojiStickers: animatedEmojiStickers, additionalAnimatedEmojiStickers: additionalAnimatedEmojiStickers, subject: subject, currentlyPlayingMessageId: currentlyPlayingMessageIdAndType?.0, isCopyProtectionEnabled: isCopyProtectionEnabled, availableReactions: availableReactions, savedMessageTags: savedMessageTags, defaultReaction: defaultReaction, isPremium: isPremium, alwaysDisplayTranscribeButton: alwaysDisplayTranscribeButton, accountPeer: accountPeer, topicAuthorId: topicAuthorId, hasBots: chatHasBots, translateToLanguage: translateToLanguage, maxReadStoryId: maxReadStoryId, recommendedChannels: recommendedChannels, audioTranscriptionTrial: audioTranscriptionTrial, chatThemes: chatThemes, deviceContactsNumbers: deviceContactsNumbers, isInline: !rotated)
|
let associatedData = extractAssociatedData(chatLocation: chatLocation, view: view, automaticDownloadNetworkType: networkType, animatedEmojiStickers: animatedEmojiStickers, additionalAnimatedEmojiStickers: additionalAnimatedEmojiStickers, subject: subject, currentlyPlayingMessageId: currentlyPlayingMessageIdAndType?.0, isCopyProtectionEnabled: isCopyProtectionEnabled, availableReactions: availableReactions, savedMessageTags: savedMessageTags, defaultReaction: defaultReaction, isPremium: isPremium, alwaysDisplayTranscribeButton: alwaysDisplayTranscribeButton, accountPeer: accountPeer, topicAuthorId: topicAuthorId, hasBots: chatHasBots, translateToLanguage: translateToLanguage, maxReadStoryId: maxReadStoryId, recommendedChannels: recommendedChannels, audioTranscriptionTrial: audioTranscriptionTrial, chatThemes: chatThemes, deviceContactsNumbers: deviceContactsNumbers, isInline: !rotated)
|
||||||
|
|
||||||
|
var includeEmbeddedSavedChatInfo = false
|
||||||
|
if case let .replyThread(message) = chatLocation, message.peerId == context.account.peerId, !rotated {
|
||||||
|
includeEmbeddedSavedChatInfo = true
|
||||||
|
}
|
||||||
|
|
||||||
let filteredEntries = chatHistoryEntriesForView(
|
let filteredEntries = chatHistoryEntriesForView(
|
||||||
location: chatLocation,
|
location: chatLocation,
|
||||||
view: view,
|
view: view,
|
||||||
@ -1704,6 +1709,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
|||||||
includeEmptyEntry: mode == .bubbles && tag == nil,
|
includeEmptyEntry: mode == .bubbles && tag == nil,
|
||||||
includeChatInfoEntry: mode == .bubbles,
|
includeChatInfoEntry: mode == .bubbles,
|
||||||
includeSearchEntry: includeSearchEntry && tag != nil,
|
includeSearchEntry: includeSearchEntry && tag != nil,
|
||||||
|
includeEmbeddedSavedChatInfo: includeEmbeddedSavedChatInfo,
|
||||||
reverse: reverse,
|
reverse: reverse,
|
||||||
groupMessages: mode == .bubbles,
|
groupMessages: mode == .bubbles,
|
||||||
reverseGroupedMessages: reverseGroups,
|
reverseGroupedMessages: reverseGroups,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user