mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
[WIP] Chatlist suggestions
This commit is contained in:
parent
084bb5bcd5
commit
e77402d7b3
@ -3368,6 +3368,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
||||
}, openAdInfo: { node, adPeer in
|
||||
interaction.openAdInfo(node, adPeer)
|
||||
}, openAccountFreezeInfo: {
|
||||
}, openUrl: { _ in
|
||||
})
|
||||
chatListInteraction.isSearchMode = true
|
||||
|
||||
@ -5363,6 +5364,7 @@ public final class ChatListSearchShimmerNode: ASDisplayNode {
|
||||
}, openPhotoSetup: {
|
||||
}, openAdInfo: { _, _ in
|
||||
}, openAccountFreezeInfo: {
|
||||
}, openUrl: { _ in
|
||||
})
|
||||
var isInlineMode = false
|
||||
if case .topics = key {
|
||||
|
@ -163,6 +163,7 @@ public final class ChatListShimmerNode: ASDisplayNode {
|
||||
}, openPhotoSetup: {
|
||||
}, openAdInfo: { _, _ in
|
||||
}, openAccountFreezeInfo: {
|
||||
}, openUrl: { _ in
|
||||
})
|
||||
interaction.isInlineMode = isInlineMode
|
||||
|
||||
|
@ -116,6 +116,7 @@ public final class ChatListNodeInteraction {
|
||||
let openPhotoSetup: () -> Void
|
||||
let openAdInfo: (ASDisplayNode, AdPeer) -> Void
|
||||
let openAccountFreezeInfo: () -> Void
|
||||
let openUrl: (String) -> Void
|
||||
|
||||
public var searchTextHighightState: String?
|
||||
var highlightedChatLocation: ChatListHighlightedLocation?
|
||||
@ -175,7 +176,8 @@ public final class ChatListNodeInteraction {
|
||||
openWebApp: @escaping (TelegramUser) -> Void,
|
||||
openPhotoSetup: @escaping () -> Void,
|
||||
openAdInfo: @escaping (ASDisplayNode, AdPeer) -> Void,
|
||||
openAccountFreezeInfo: @escaping () -> Void
|
||||
openAccountFreezeInfo: @escaping () -> Void,
|
||||
openUrl: @escaping (String) -> Void
|
||||
) {
|
||||
self.activateSearch = activateSearch
|
||||
self.peerSelected = peerSelected
|
||||
@ -223,6 +225,7 @@ public final class ChatListNodeInteraction {
|
||||
self.openPhotoSetup = openPhotoSetup
|
||||
self.openAdInfo = openAdInfo
|
||||
self.openAccountFreezeInfo = openAccountFreezeInfo
|
||||
self.openUrl = openUrl
|
||||
}
|
||||
}
|
||||
|
||||
@ -775,6 +778,8 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
||||
nodeInteraction?.openPhotoSetup()
|
||||
case .accountFreeze:
|
||||
nodeInteraction?.openAccountFreezeInfo()
|
||||
case let .link(url, _, _):
|
||||
nodeInteraction?.openUrl(url)
|
||||
}
|
||||
case .hide:
|
||||
nodeInteraction?.dismissNotice(notice)
|
||||
@ -1123,6 +1128,8 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
||||
nodeInteraction?.openPhotoSetup()
|
||||
case .accountFreeze:
|
||||
nodeInteraction?.openAccountFreezeInfo()
|
||||
case let .link(url, _, _):
|
||||
nodeInteraction?.openUrl(url)
|
||||
}
|
||||
case .hide:
|
||||
nodeInteraction?.dismissNotice(notice)
|
||||
@ -1906,6 +1913,12 @@ public final class ChatListNode: ListView {
|
||||
self?.openAdInfo?(node, adPeer)
|
||||
}, openAccountFreezeInfo: { [weak self] in
|
||||
self?.openAccountFreezeInfo?()
|
||||
}, openUrl: { [weak self] url in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
context.sharedContext.openExternalUrl(context: self.context, urlContext: .generic, url: url, forceExternal: false, presentationData: presentationData, navigationController: self.context.sharedContext.mainWindow?.viewController as? NavigationController, dismissInput: {})
|
||||
})
|
||||
nodeInteraction.isInlineMode = isInlineMode
|
||||
|
||||
@ -2134,6 +2147,8 @@ public final class ChatListNode: ListView {
|
||||
}
|
||||
return .birthdayPremiumGift(peers: todayBirthdayPeers, birthdays: birthdays)
|
||||
}
|
||||
} else if case let .link(url, title, subtitle) = suggestions.first(where: { if case .link = $0 { return true } else { return false} }) {
|
||||
return .single(.link(url: url, title: title, subtitle: subtitle))
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
|
@ -93,6 +93,7 @@ public enum ChatListNotice: Equatable {
|
||||
case starsSubscriptionLowBalance(amount: StarsAmount, peers: [EnginePeer])
|
||||
case setupPhoto(EnginePeer)
|
||||
case accountFreeze
|
||||
case link(url: String, title: String, subtitle: String)
|
||||
}
|
||||
|
||||
enum ChatListNodeEntry: Comparable, Identifiable {
|
||||
|
@ -291,6 +291,9 @@ final class ChatListNoticeItemNode: ItemListRevealOptionsItemNode {
|
||||
case .accountFreeze:
|
||||
titleString = NSAttributedString(string: item.strings.ChatList_FrozenAccount_Title, font: titleFont, textColor: item.theme.list.itemDestructiveColor)
|
||||
textString = NSAttributedString(string: item.strings.ChatList_FrozenAccount_Text, font: smallTextFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
|
||||
case let .link(_, title, subtitle):
|
||||
titleString = NSAttributedString(string: title, font: titleFont, textColor: item.theme.list.itemPrimaryTextColor)
|
||||
textString = NSAttributedString(string: subtitle, font: smallTextFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor)
|
||||
}
|
||||
|
||||
var leftInset: CGFloat = sideInset
|
||||
@ -383,7 +386,7 @@ final class ChatListNoticeItemNode: ItemListRevealOptionsItemNode {
|
||||
|
||||
let hasCloseButton: Bool
|
||||
switch item.notice {
|
||||
case .xmasPremiumGift, .setupBirthday, .birthdayPremiumGift, .premiumGrace, .starsSubscriptionLowBalance, .setupPhoto:
|
||||
case .xmasPremiumGift, .setupBirthday, .birthdayPremiumGift, .premiumGrace, .starsSubscriptionLowBalance, .setupPhoto, .link:
|
||||
hasCloseButton = true
|
||||
default:
|
||||
hasCloseButton = false
|
||||
|
@ -234,6 +234,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, ASScrollView
|
||||
}, openPhotoSetup: {
|
||||
}, openAdInfo: { _, _ in
|
||||
}, openAccountFreezeInfo: {
|
||||
}, openUrl: { _ in
|
||||
})
|
||||
|
||||
let chatListPresentationData = ChatListPresentationData(theme: self.presentationData.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: true)
|
||||
|
@ -383,6 +383,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
}, openPhotoSetup: {
|
||||
}, openAdInfo: { _, _ in
|
||||
}, openAccountFreezeInfo: {
|
||||
}, openUrl: { _ in
|
||||
})
|
||||
|
||||
func makeChatListItem(
|
||||
|
@ -72,6 +72,112 @@ public final class PromoChatListItem: AdditionalChatListItem {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public final class ServerSuggestionInfo: Codable, Equatable {
|
||||
public final class Item: Codable, Equatable {
|
||||
public final class Text: Codable, Equatable {
|
||||
public let string: String
|
||||
public let entities: [MessageTextEntity]
|
||||
|
||||
public init(string: String, entities: [MessageTextEntity]) {
|
||||
self.string = string
|
||||
self.entities = entities
|
||||
}
|
||||
|
||||
public static func ==(lhs: Text, rhs: Text) -> Bool {
|
||||
if lhs.string != rhs.string {
|
||||
return false
|
||||
}
|
||||
if lhs.entities != rhs.entities {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public enum Action: Codable, Equatable {
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case link
|
||||
}
|
||||
|
||||
case link(url: String)
|
||||
|
||||
public init(from decoder: any Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
self = .link(url: try container.decode(String.self, forKey: .link))
|
||||
}
|
||||
}
|
||||
|
||||
public let id: String
|
||||
public let title: Text
|
||||
public let text: Text
|
||||
public let action: Action
|
||||
|
||||
public init(id: String, title: Text, text: Text, action: Action) {
|
||||
self.id = id
|
||||
self.title = title
|
||||
self.text = text
|
||||
self.action = action
|
||||
}
|
||||
|
||||
public static func ==(lhs: Item, rhs: Item) -> Bool {
|
||||
if lhs.id != rhs.id {
|
||||
return false
|
||||
}
|
||||
if lhs.title != rhs.title {
|
||||
return false
|
||||
}
|
||||
if lhs.text != rhs.text {
|
||||
return false
|
||||
}
|
||||
if lhs.action != rhs.action {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public let legacyItems: [String]
|
||||
public let items: [Item]
|
||||
public let dismissedIds: [String]
|
||||
|
||||
public init(legacyItems: [String], items: [Item], dismissedIds: [String]) {
|
||||
self.legacyItems = legacyItems
|
||||
self.items = items
|
||||
self.dismissedIds = dismissedIds
|
||||
}
|
||||
|
||||
public static func ==(lhs: ServerSuggestionInfo, rhs: ServerSuggestionInfo) -> Bool {
|
||||
if lhs.items != rhs.items {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension ServerSuggestionInfo.Item.Text {
|
||||
convenience init(_ apiText: Api.TextWithEntities) {
|
||||
switch apiText {
|
||||
case let .textWithEntities(text, entities):
|
||||
self.init(string: text, entities: messageTextEntitiesFromApiEntities(entities))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ServerSuggestionInfo.Item {
|
||||
convenience init(_ apiItem: Api.PendingSuggestion) {
|
||||
switch apiItem {
|
||||
case let .pendingSuggestion(suggestion, title, description, url):
|
||||
self.init(
|
||||
id: suggestion,
|
||||
title: ServerSuggestionInfo.Item.Text(title),
|
||||
text: ServerSuggestionInfo.Item.Text(description),
|
||||
action: .link(url: url)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func managedPromoInfoUpdates(accountPeerId: PeerId, postbox: Postbox, network: Network, viewTracker: AccountViewTracker) -> Signal<Void, NoError> {
|
||||
return Signal { subscriber in
|
||||
let queue = Queue()
|
||||
@ -88,24 +194,38 @@ func managedPromoInfoUpdates(accountPeerId: PeerId, postbox: Postbox, network: N
|
||||
switch data {
|
||||
case .promoDataEmpty:
|
||||
transaction.replaceAdditionalChatListItems([])
|
||||
case let .promoData(_, _, peer, chats, users, psaType, psaMessage):
|
||||
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
|
||||
case let .promoData(flags, expires, peer, psaType, psaMessage, pendingSuggestions, dismissedSuggestions, customPendingSuggestion, chats, users):
|
||||
let _ = expires
|
||||
|
||||
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
|
||||
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
|
||||
|
||||
let kind: PromoChatListItem.Kind
|
||||
if let psaType = psaType {
|
||||
var kind: PromoChatListItem.Kind?
|
||||
if let psaType {
|
||||
kind = .psa(type: psaType, message: psaMessage)
|
||||
} else {
|
||||
} else if ((flags & 1) << 0) != 0 {
|
||||
kind = .proxy
|
||||
}
|
||||
|
||||
var additionalChatListItems: [AdditionalChatListItem] = []
|
||||
if let parsedPeer = transaction.getPeer(peer.peerId) {
|
||||
if let kind, let peer, let parsedPeer = transaction.getPeer(peer.peerId) {
|
||||
additionalChatListItems.append(PromoChatListItem(peerId: parsedPeer.id, kind: kind))
|
||||
}
|
||||
|
||||
transaction.replaceAdditionalChatListItems(additionalChatListItems)
|
||||
|
||||
var customItems: [ServerSuggestionInfo.Item] = []
|
||||
if let customPendingSuggestion {
|
||||
customItems.append(ServerSuggestionInfo.Item(customPendingSuggestion))
|
||||
}
|
||||
let suggestionInfo = ServerSuggestionInfo(
|
||||
legacyItems: pendingSuggestions,
|
||||
items: customItems,
|
||||
dismissedIds: dismissedSuggestions
|
||||
)
|
||||
|
||||
transaction.updatePreferencesEntry(key: PreferencesKeys.serverSuggestionInfo(), { _ in
|
||||
return PreferencesEntry(suggestionInfo)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,21 +3,124 @@ import Postbox
|
||||
import SwiftSignalKit
|
||||
import TelegramApi
|
||||
|
||||
public enum ServerProvidedSuggestion: String {
|
||||
case autoarchivePopular = "AUTOARCHIVE_POPULAR"
|
||||
case newcomerTicks = "NEWCOMER_TICKS"
|
||||
case validatePhoneNumber = "VALIDATE_PHONE_NUMBER"
|
||||
case validatePassword = "VALIDATE_PASSWORD"
|
||||
case setupPassword = "SETUP_PASSWORD"
|
||||
case upgradePremium = "PREMIUM_UPGRADE"
|
||||
case annualPremium = "PREMIUM_ANNUAL"
|
||||
case restorePremium = "PREMIUM_RESTORE"
|
||||
case xmasPremiumGift = "PREMIUM_CHRISTMAS"
|
||||
case setupBirthday = "BIRTHDAY_SETUP"
|
||||
case todayBirthdays = "BIRTHDAY_CONTACTS_TODAY"
|
||||
case gracePremium = "PREMIUM_GRACE"
|
||||
case starsSubscriptionLowBalance = "STARS_SUBSCRIPTION_LOW_BALANCE"
|
||||
case setupPhoto = "USERPIC_SETUP"
|
||||
public enum ServerProvidedSuggestion: Hashable {
|
||||
case autoarchivePopular
|
||||
case newcomerTicks
|
||||
case validatePhoneNumber
|
||||
case validatePassword
|
||||
case setupPassword
|
||||
case upgradePremium
|
||||
case annualPremium
|
||||
case restorePremium
|
||||
case xmasPremiumGift
|
||||
case setupBirthday
|
||||
case todayBirthdays
|
||||
case gracePremium
|
||||
case starsSubscriptionLowBalance
|
||||
case setupPhoto
|
||||
case link(url: String, title: String, subtitle: String)
|
||||
|
||||
public init?(string: String) {
|
||||
switch string {
|
||||
case "AUTOARCHIVE_POPULAR":
|
||||
self = .autoarchivePopular
|
||||
case "NEWCOMER_TICKS":
|
||||
self = .newcomerTicks
|
||||
case "VALIDATE_PHONE_NUMBER":
|
||||
self = .validatePhoneNumber
|
||||
case "VALIDATE_PASSWORD":
|
||||
self = .validatePassword
|
||||
case "SETUP_PASSWORD":
|
||||
self = .setupPassword
|
||||
case "PREMIUM_UPGRADE":
|
||||
self = .upgradePremium
|
||||
case "PREMIUM_ANNUAL":
|
||||
self = .annualPremium
|
||||
case "PREMIUM_RESTORE":
|
||||
self = .restorePremium
|
||||
case "PREMIUM_CHRISTMAS":
|
||||
self = .xmasPremiumGift
|
||||
case "BIRTHDAY_SETUP":
|
||||
self = .setupBirthday
|
||||
case "BIRTHDAY_CONTACTS_TODAY":
|
||||
self = .todayBirthdays
|
||||
case "PREMIUM_GRACE":
|
||||
self = .gracePremium
|
||||
case "STARS_SUBSCRIPTION_LOW_BALANCE":
|
||||
self = .starsSubscriptionLowBalance
|
||||
case "USERPIC_SETUP":
|
||||
self = .setupPhoto
|
||||
default:
|
||||
if string.hasPrefix("LINK_") {
|
||||
let rawString = string.dropFirst(Int("LINK_".count))
|
||||
if let dict = try? JSONSerialization.jsonObject(with: rawString.data(using: .utf8) ?? Data()) as? [String: Any] {
|
||||
var url: String?
|
||||
var title: String?
|
||||
var subtitle: String?
|
||||
|
||||
if let urlValue = dict["url"] as? String {
|
||||
url = urlValue
|
||||
}
|
||||
if let titleValue = dict["title"] as? String {
|
||||
title = titleValue
|
||||
}
|
||||
if let subtitleValue = dict["subtitle"] as? String {
|
||||
subtitle = subtitleValue
|
||||
}
|
||||
if let url = url, let title = title, let subtitle = subtitle {
|
||||
self = .link(url: url, title: title, subtitle: subtitle)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var stringValue: String {
|
||||
switch self {
|
||||
case .autoarchivePopular:
|
||||
return "AUTOARCHIVE_POPULAR"
|
||||
case .newcomerTicks:
|
||||
return "NEWCOMER_TICKS"
|
||||
case .validatePhoneNumber:
|
||||
return "VALIDATE_PHONE_NUMBER"
|
||||
case .validatePassword:
|
||||
return "VALIDATE_PASSWORD"
|
||||
case .setupPassword:
|
||||
return "SETUP_PASSWORD"
|
||||
case .upgradePremium:
|
||||
return "PREMIUM_UPGRADE"
|
||||
case .annualPremium:
|
||||
return "PREMIUM_ANNUAL"
|
||||
case .restorePremium:
|
||||
return "PREMIUM_RESTORE"
|
||||
case .xmasPremiumGift:
|
||||
return "PREMIUM_CHRISTMAS"
|
||||
case .setupBirthday:
|
||||
return "BIRTHDAY_SETUP"
|
||||
case .todayBirthdays:
|
||||
return "BIRTHDAY_CONTACTS_TODAY"
|
||||
case .gracePremium:
|
||||
return "PREMIUM_GRACE"
|
||||
case .starsSubscriptionLowBalance:
|
||||
return "STARS_SUBSCRIPTION_LOW_BALANCE"
|
||||
case .setupPhoto:
|
||||
return "USERPIC_SETUP"
|
||||
case let .link(url, title, subtitle):
|
||||
let dict: [String: String] = [
|
||||
"url": url,
|
||||
"title": title,
|
||||
"subtitle": subtitle
|
||||
]
|
||||
if let data = try? JSONSerialization.data(withJSONObject: dict, options: []), let string = String(data: data, encoding: .utf8) {
|
||||
return "LINK_\(string)"
|
||||
} else {
|
||||
// Fallback or error handling, though unlikely to fail with basic strings
|
||||
return "LINK_{}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var dismissedSuggestionsPromise = ValuePromise<[AccountRecordId: Set<ServerProvidedSuggestion>]>([:])
|
||||
@ -38,11 +141,20 @@ func _internal_getServerProvidedSuggestions(account: Account) -> Signal<[ServerP
|
||||
guard let appConfiguration = view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) else {
|
||||
return []
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
guard let data = appConfiguration.data, var listItems = data["pending_suggestions"] as? [String] else {
|
||||
return []
|
||||
}
|
||||
listItems.insert("LINK_{\"url\": \"https://t.me/durov\", \"title\": \"📣 Stay updated!\", \"subtitle\": \"Subscribe to the channel of Telegram's founder.\"}", at: 0)
|
||||
#else
|
||||
guard let data = appConfiguration.data, let listItems = data["pending_suggestions"] as? [String] else {
|
||||
return []
|
||||
}
|
||||
#endif
|
||||
|
||||
return listItems.compactMap { item -> ServerProvidedSuggestion? in
|
||||
return ServerProvidedSuggestion(rawValue: item)
|
||||
return ServerProvidedSuggestion(string: item)
|
||||
}.filter { !dismissedSuggestions.contains($0) }
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
@ -64,7 +176,7 @@ func _internal_getServerDismissedSuggestions(account: Account) -> Signal<[Server
|
||||
listItems.append(contentsOf: listItemsValues)
|
||||
}
|
||||
var items = listItems.compactMap { item -> ServerProvidedSuggestion? in
|
||||
return ServerProvidedSuggestion(rawValue: item)
|
||||
return ServerProvidedSuggestion(string: item)
|
||||
}
|
||||
items.append(contentsOf: dismissedSuggestions)
|
||||
return items
|
||||
@ -78,7 +190,7 @@ func _internal_dismissServerProvidedSuggestion(account: Account, suggestion: Ser
|
||||
} else {
|
||||
dismissedSuggestions[account.id] = Set([suggestion])
|
||||
}
|
||||
return account.network.request(Api.functions.help.dismissSuggestion(peer: .inputPeerEmpty, suggestion: suggestion.rawValue))
|
||||
return account.network.request(Api.functions.help.dismissSuggestion(peer: .inputPeerEmpty, suggestion: suggestion.stringValue))
|
||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||
return .single(.boolFalse)
|
||||
}
|
||||
|
@ -315,6 +315,7 @@ private enum PreferencesKeyValues: Int32 {
|
||||
case starGifts = 41
|
||||
case botStorageState = 42
|
||||
case secureBotStorageState = 43
|
||||
case serverSuggestionInfo = 44
|
||||
}
|
||||
|
||||
public func applicationSpecificPreferencesKey(_ value: Int32) -> ValueBoxKey {
|
||||
@ -558,6 +559,12 @@ public struct PreferencesKeys {
|
||||
key.setInt32(0, value: PreferencesKeyValues.secureBotStorageState.rawValue)
|
||||
return key
|
||||
}
|
||||
|
||||
public static func serverSuggestionInfo() -> ValueBoxKey {
|
||||
let key = ValueBoxKey(length: 4 + 8)
|
||||
key.setInt32(0, value: PreferencesKeyValues.serverSuggestionInfo.rawValue)
|
||||
return key
|
||||
}
|
||||
}
|
||||
|
||||
private enum SharedDataKeyValues: Int32 {
|
||||
|
@ -202,6 +202,7 @@ private enum ApplicationSpecificGlobalNotice: Int32 {
|
||||
case captionAboveMediaTooltip = 75
|
||||
case channelSendGiftTooltip = 76
|
||||
case starGiftWearTips = 77
|
||||
case channelSuggestTooltip = 78
|
||||
|
||||
var key: ValueBoxKey {
|
||||
let v = ValueBoxKey(length: 4)
|
||||
@ -559,6 +560,10 @@ private struct ApplicationSpecificNoticeKeys {
|
||||
static func starGiftWearTips() -> NoticeEntryKey {
|
||||
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.starGiftWearTips.key)
|
||||
}
|
||||
|
||||
static func channelSuggestTooltip() -> NoticeEntryKey {
|
||||
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.channelSuggestTooltip.key)
|
||||
}
|
||||
}
|
||||
|
||||
public struct ApplicationSpecificNotice {
|
||||
@ -2368,6 +2373,33 @@ public struct ApplicationSpecificNotice {
|
||||
}
|
||||
}
|
||||
|
||||
public static func getChannelSuggestTooltip(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Int32, NoError> {
|
||||
return accountManager.transaction { transaction -> Int32 in
|
||||
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.channelSuggestTooltip())?.get(ApplicationSpecificCounterNotice.self) {
|
||||
return value.value
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static func incrementChannelSuggestTooltip(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.channelSuggestTooltip())?.get(ApplicationSpecificCounterNotice.self) {
|
||||
currentValue = value.value
|
||||
}
|
||||
let previousValue = currentValue
|
||||
currentValue += Int32(count)
|
||||
|
||||
if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) {
|
||||
transaction.setNotice(ApplicationSpecificNoticeKeys.channelSuggestTooltip(), entry)
|
||||
}
|
||||
|
||||
return Int(previousValue)
|
||||
}
|
||||
}
|
||||
|
||||
public static func getStarGiftWearTips(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Int32, NoError> {
|
||||
return accountManager.transaction { transaction -> Int32 in
|
||||
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.starGiftWearTips())?.get(ApplicationSpecificCounterNotice.self) {
|
||||
|
@ -689,6 +689,7 @@ public final class ChatInlineSearchResultsListComponent: Component {
|
||||
openAdInfo: { _, _ in
|
||||
},
|
||||
openAccountFreezeInfo: {
|
||||
}, openUrl: { _ in
|
||||
}
|
||||
)
|
||||
self.chatListNodeInteraction = chatListNodeInteraction
|
||||
|
@ -189,6 +189,7 @@ public final class LoadingOverlayNode: ASDisplayNode {
|
||||
}, openPhotoSetup: {
|
||||
}, openAdInfo: { _, _ in
|
||||
}, openAccountFreezeInfo: {
|
||||
}, openUrl: { _ in
|
||||
})
|
||||
|
||||
let items = (0 ..< 1).map { _ -> ChatListItem in
|
||||
@ -551,6 +552,8 @@ private final class PeerInfoScreenPersonalChannelItemNode: PeerInfoScreenItemNod
|
||||
openAdInfo: { _, _ in
|
||||
},
|
||||
openAccountFreezeInfo: {
|
||||
},
|
||||
openUrl: { _ in
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -215,6 +215,8 @@ final class GreetingMessageListItemComponent: Component {
|
||||
openAdInfo: { _, _ in
|
||||
},
|
||||
openAccountFreezeInfo: {
|
||||
},
|
||||
openUrl: { _ in
|
||||
}
|
||||
)
|
||||
self.chatListNodeInteraction = chatListNodeInteraction
|
||||
|
@ -236,6 +236,8 @@ final class QuickReplySetupScreenComponent: Component {
|
||||
openAdInfo: { _, _ in
|
||||
},
|
||||
openAccountFreezeInfo: {
|
||||
},
|
||||
openUrl: { _ in
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -877,6 +877,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, ASScrollViewDelegate
|
||||
}, openPhotoSetup: {
|
||||
}, openAdInfo: { _, _ in
|
||||
}, openAccountFreezeInfo: {
|
||||
}, openUrl: { _ in
|
||||
})
|
||||
let chatListPresentationData = ChatListPresentationData(theme: self.presentationData.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: true)
|
||||
|
||||
|
@ -297,6 +297,7 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, ASScrollViewDe
|
||||
}, openPhotoSetup: {
|
||||
}, openAdInfo: { _, _ in
|
||||
}, openAccountFreezeInfo: {
|
||||
}, openUrl: { _ in
|
||||
})
|
||||
interaction.searchTextHighightState = searchQuery
|
||||
self.interaction = interaction
|
||||
|
@ -185,6 +185,8 @@ private struct CommandChatInputContextPanelEntry: Comparable, Identifiable {
|
||||
openAdInfo: { _, _ in
|
||||
},
|
||||
openAccountFreezeInfo: {
|
||||
},
|
||||
openUrl: { _ in
|
||||
}
|
||||
)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user