Based on Swiftgram 12.5 (Telegram iOS 12.5). All GLEGram features ported and organized in GLEGram/ folder. Features: Ghost Mode, Saved Deleted Messages, Content Protection Bypass, Font Replacement, Fake Profile, Chat Export, Plugin System, and more. See CHANGELOG_12.5.md for full details.
45 KiB
Local Premium (Emulate Premium) - Полная документация реализации
📋 Описание
Local Premium — это функция, которая эмулирует Premium подписку Telegram локально на устройстве без реальной подписки.
Важно: Все функции работают только на стороне клиента и видны только вам. Сервер Telegram не видит эти изменения.
🎯 Реализованная функциональность
✅ Основные функции
- Premium Badge - Показывает значок Premium рядом с вашим именем везде в приложении
- Безлимитные закрепленные чаты - Закрепляйте сколько угодно чатов (вместо лимита 5)
- Безлимитные папки - Создавайте сколько угодно папок (вместо лимита 10)
- Безлимитные чаты в папке - Добавляйте сколько угодно чатов в папку (вместо лимита 100)
- Безлимитные теги в Избранном - Добавляйте теги к сообщениям в Saved Messages
- Переупорядочивание папок - Перемещайте любую папку на первую позицию (включая "Все чаты")
✅ Отключение серверной синхронизации
- Закрепленные чаты: Сервер не будет откреплять чаты при превышении лимита
- Папки: Сервер не будет удалять папки при превышении лимита
- Чаты в папках: Сервер не будет удалять чаты из папок при превышении лимита
- Порядок папок: Сервер не будет изменять порядок папок
- Теги в Избранном: Сервер не будет синхронизировать теги
✅ Расположение настроек
Settings → IAppsGram → Local Premium:
- Один переключатель "Emulate Premium"
- Подробное описание всех включенных функций
- Предупреждение о клиентской природе функций
🏗️ Архитектура решения
Ключевая инновация: Модификация Peer.isPremium
Главное архитектурное решение - модификация свойства Peer.isPremium в PeerUtils.swift:
var isPremium: Bool {
switch self {
case let user as TelegramUser:
// MARK: Swiftgram Local Premium - Override isPremium for current user
if user.id.id._internalGetInt64Value() == SGLocalPremium.shared.currentAccountPeerId?.id &&
user.id.namespace._internalGetInt32Value() == SGLocalPremium.shared.currentAccountPeerId?.namespace {
return user.flags.contains(.isPremium) || SGLocalPremium.shared.showPremiumBadge
}
return user.flags.contains(.isPremium)
default:
return false
}
}
Почему это работает:
Peer.isPremiumиспользуется везде в приложении для проверки Premium статуса- Модификация в одном месте автоматически работает во всех UI компонентах
- Premium Badge отображается везде автоматически
- Не исчезает после обновлений с сервера (сервер возвращает
isPremium = false, но наша проверка добавляет|| SGLocalPremium.shared.showPremiumBadge)
📦 Модуль SGLocalPremium
Файл: Telegram-iOS/Swiftgram/SGLocalPremium/Sources/SGLocalPremium.swift
Полный код класса
import Foundation
import SwiftSignalKit
public class SGLocalPremium {
public static let shared = SGLocalPremium()
private var currentAccountId: String?
public var currentAccountPeerId: (id: Int64, namespace: Int32)?
private init() {}
// MARK: - Account Configuration
public func setAccountPeerId(_ peerId: Int64, namespace: Int32) {
self.currentAccountId = "\(namespace)_\(peerId)"
self.currentAccountPeerId = (id: peerId, namespace: namespace)
}
private func accountKey(_ key: String) -> String {
guard let accountId = currentAccountId else {
return key
}
return "\(key)_\(accountId)"
}
// MARK: - Main Setting (Per-Account)
public var emulatePremium: Bool {
get {
return UserDefaults.standard.bool(forKey: accountKey("localPremiumEmulate"))
}
set {
UserDefaults.standard.set(newValue, forKey: accountKey("localPremiumEmulate"))
UserDefaults.standard.synchronize()
}
}
// MARK: - Computed Properties
public var showPremiumBadge: Bool { return emulatePremium }
public var unlimitedPinnedChats: Bool { return emulatePremium }
public var unlimitedFolders: Bool { return emulatePremium }
public var unlimitedChatsPerFolder: Bool { return emulatePremium }
public var unlimitedSavedMessageTags: Bool { return emulatePremium }
public var allowFolderReordering: Bool { return emulatePremium }
public var shouldDisableServerSync: Bool { return emulatePremium }
}
Ключевые особенности:
- Singleton pattern:
SGLocalPremium.sharedдля глобального доступа - Per-account настройки: Каждый аккаунт имеет свои настройки через
accountKey() - Одна главная настройка:
emulatePremiumконтролирует все функции - Computed properties: Все функции возвращают значение
emulatePremium - currentAccountPeerId: Хранит ID текущего аккаунта для проверки в
Peer.isPremium
🔗 Точки интеграции
1. Инициализация аккаунта
Файл: Telegram-iOS/submodules/TelegramUI/Sources/AccountContext.swift
// MARK: Swiftgram Local Premium - Set current account
SGLocalPremium.shared.setAccountPeerId(
account.peerId.id._internalGetInt64Value(),
namespace: account.peerId.namespace._internalGetInt32Value()
)
Назначение: Устанавливает текущий аккаунт для per-account настроек и для проверки в Peer.isPremium.
2. Premium Badge - Ключевая модификация
Файл: Telegram-iOS/submodules/TelegramCore/Sources/Utils/PeerUtils.swift
var isPremium: Bool {
switch self {
case let user as TelegramUser:
// MARK: Swiftgram Local Premium - Override isPremium for current user
if user.id.id._internalGetInt64Value() == SGLocalPremium.shared.currentAccountPeerId?.id &&
user.id.namespace._internalGetInt32Value() == SGLocalPremium.shared.currentAccountPeerId?.namespace {
return user.flags.contains(.isPremium) || SGLocalPremium.shared.showPremiumBadge
}
return user.flags.contains(.isPremium)
default:
return false
}
}
Почему это критически важно:
- Это единственное место, где нужно добавить проверку для Premium Badge
- Все UI компоненты используют
peer.isPremiumдля проверки - Badge автоматически отображается везде:
- ✅ PeerInfoScreen - профиль пользователя
- ✅ PeerInfoHeaderNode - заголовок профиля
- ✅ ChatListItem - список чатов
- ✅ ChatTitleView - заголовок чата
- ✅ ChatTitleComponent - заголовок чата (компонент)
- ✅ ItemListAvatarAndNameItem - элемент списка с аватаром
- ✅ ContactsPeerItem - элемент контакта
- ✅ CallListCallItem - элемент списка звонков
- ✅ VoiceChatParticipantItem - участник голосового чата
- ✅ ReactionListContextMenuContent - контекстное меню реакций
- Badge не исчезает после обновлений с сервера (сервер возвращает
isPremium = false, но проверка|| SGLocalPremium.shared.showPremiumBadgeсохраняет его)
3. Лимиты закрепленных чатов
Файл: Telegram-iOS/submodules/TelegramCore/Sources/State/UserLimitsConfiguration.swift
public var maxPinnedChatCount: Int32 {
// MARK: Swiftgram Local Premium - Unlimited pinned chats
return SGLocalPremium.shared.getMaxPinnedChatCount(
self.isPremium ? self.defaultMaxPremiumPinnedChatCount : self.defaultMaxPinnedChatCount
)
}
Метод в SGLocalPremium:
public func getMaxPinnedChatCount(_ original: Int32) -> Int32 {
if unlimitedPinnedChats {
return Int32.max // Практически безлимит
}
return original
}
Назначение: Возвращает Int32.max если emulatePremium = true, иначе оригинальный лимит (5 для обычных, 10 для Premium).
4. Лимиты папок
Файл: Telegram-iOS/submodules/TelegramCore/Sources/State/UserLimitsConfiguration.swift
public var maxFoldersCount: Int32 {
// MARK: Swiftgram Local Premium - Unlimited folders
return SGLocalPremium.shared.getMaxFoldersCount(
self.isPremium ? self.defaultMaxPremiumFoldersCount : self.defaultMaxFoldersCount
)
}
Назначение: Возвращает Int32.max если emulatePremium = true, иначе оригинальный лимит (10 для обычных, 20 для Premium).
5. Лимиты чатов в папке
Файл: Telegram-iOS/submodules/TelegramCore/Sources/State/UserLimitsConfiguration.swift
public var maxFolderChatsCount: Int32 {
// MARK: Swiftgram Local Premium - Unlimited chats per folder
return SGLocalPremium.shared.getMaxFolderChatsCount(
self.isPremium ? self.defaultMaxPremiumFolderChatsCount : self.defaultMaxFolderChatsCount
)
}
Назначение: Возвращает Int32.max если emulatePremium = true, иначе оригинальный лимит (100 для обычных, 200 для Premium).
6. Отключение синхронизации закрепленных чатов
Файл: Telegram-iOS/submodules/TelegramCore/Sources/State/ManagedSynchronizePinnedChatsOperations.swift
func synchronizePinnedChats(
transaction: Transaction,
accountPeerId: PeerId
) -> Signal<Void, NoError> {
// MARK: Swiftgram Local Premium - Skip server sync if emulate premium is enabled
if SGLocalPremium.shared.shouldDisableServerSync {
return .complete()
}
// ... оригинальный код синхронизации
}
Назначение:
- Предотвращает отправку закрепленных чатов на сервер
- Сервер не будет откреплять чаты при превышении лимита
- Локальные изменения остаются только на устройстве
Что это дает:
- Можно закрепить больше 5 чатов (для обычных пользователей)
- Чаты не будут автоматически откреплены сервером
- Закрепленные чаты сохраняются между перезапусками
7. Отключение синхронизации папок
Файл: Telegram-iOS/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChatListFiltering.swift
public func _internal_synchronizeChatListFilters(
postbox: Postbox,
network: Network,
stateManager: AccountStateManager,
ignoreRemoteUpdates: Bool = false
) -> Signal<Void, NoError> {
// MARK: Swiftgram Local Premium - Skip server sync if emulate premium is enabled
if SGLocalPremium.shared.shouldDisableServerSync {
return .complete()
}
// ... оригинальный код синхронизации
}
Назначение:
- Предотвращает отправку папок на сервер
- Сервер не будет удалять папки при превышении лимита
- Сервер не будет удалять чаты из папок при превышении лимита
Что это дает:
- Можно создать больше 10 папок (для обычных пользователей)
- Можно добавить больше 100 чатов в папку
- Папки и чаты не будут автоматически удалены сервером
8. Отключение синхронизации порядка папок
Файл: Telegram-iOS/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChatListFiltering.swift
func _internal_requestUpdateChatListFilterOrder(
account: Account,
ids: [Int32]
) -> Signal<Never, RequestUpdateChatListFilterOrderError> {
// MARK: Swiftgram Local Premium - Skip server sync if emulate premium is enabled
if SGLocalPremium.shared.shouldDisableServerSync {
return .complete()
}
return account.network.request(Api.functions.messages.updateDialogFiltersOrder(order: ids))
|> mapError { _ -> RequestUpdateChatListFilterOrderError in
return .generic
}
|> mapToSignal { _ -> Signal<Never, RequestUpdateChatListFilterOrderError> in
return .complete()
}
}
Назначение:
- Предотвращает отправку порядка папок на сервер
- Сервер не будет изменять порядок папок
- Можно переместить любую папку на первую позицию (включая "Все чаты")
Что это дает:
- Можно переместить любую папку на первую позицию
- Папка "Все чаты" может быть не первой
- Порядок папок сохраняется между перезапусками
9. Переупорядочивание папок - UI компонент
Файл: Telegram-iOS/submodules/TelegramUI/Components/HorizontalTabsComponent/Sources/HorizontalTabsComponent.swift
public final class HorizontalTabsComponent: Component {
public let canReorderAllChats: Bool
public init(
// ... другие параметры
canReorderAllChats: Bool = true
) {
self.canReorderAllChats = canReorderAllChats
// ...
}
}
Проверка возможности переупорядочивания:
// MARK: Swiftgram Local Premium - Check if user can reorder all chats
if !self.canReorderAllChats, let reorderedItemIds = self.reorderedItemIds {
if let firstReorderedId = reorderedItemIds.first,
let firstOriginalTab = component.tabs.first,
firstReorderedId != firstOriginalTab.id {
self.reorderedItemIds = self.initialReorderedItemIds
}
}
Файл: Telegram-iOS/submodules/ChatListUI/Sources/ChatListControllerNode.swift
let tabsComponent = HorizontalTabsComponent(
// ... другие параметры
canReorderAllChats: SGLocalPremium.shared.canReorderAllChats(isPremium: self.context.isPremium)
)
Метод в SGLocalPremium:
public func canReorderAllChats(isPremium: Bool) -> Bool {
if isPremium {
return true
}
return allowFolderReordering
}
🎨 UI компоненты
Контроллер настроек IAppsGram
Файл: Telegram-iOS/Swiftgram/IAppsGramSettings/Sources/IAppsGramSettingsController.swift
Секция Local Premium в UI
// MARK: - Local Premium Section
case localPremiumHeader(PresentationTheme, String)
case localPremiumEmulate(PresentationTheme, String, Bool)
case localPremiumInfo(PresentationTheme, String)
Генерация UI элементов
// Local Premium Section
entries.append(.localPremiumHeader(presentationData.theme, "LOCAL PREMIUM"))
entries.append(.localPremiumEmulate(
presentationData.theme,
"Emulate Premium",
SGLocalPremium.shared.emulatePremium
))
entries.append(.localPremiumInfo(
presentationData.theme,
"Enables all Premium features locally:\n• Premium badge next to your name\n• Unlimited pinned chats\n• Unlimited folders\n• Unlimited chats per folder\n• Unlimited saved message tags\n• Folder reordering\n• Disables server sync validation\n\n⚠️ Warning: These features are client-side only and visible only to you. Server may reject some changes."
))
Обработчик переключателя
let arguments = IAppsGramSettingsControllerArguments(
context: context,
// ... другие обработчики
toggleLocalPremiumEmulate: { value in
SGLocalPremium.shared.emulatePremium = value
}
)
Особенности UI:
- Один переключатель для всех функций
- Подробное описание всех включенных функций
- Предупреждение о клиентской природе
- Простой и понятный интерфейс
- Настройки сохраняются автоматически в UserDefaults
🏷️ Saved Message Tags (Теги в Избранном)
Описание функции
Saved Message Tags — это функция, позволяющая добавлять теги (реакции) к сообщениям в "Избранном" для их организации и быстрого поиска. В оригинальном Telegram это Premium-функция.
Точки интеграции
1. UI Premium-проверки (4 файла)
Добавлена проверка !SGLocalPremium.shared.unlimitedSavedMessageTags во все места проверки Premium для тегов:
| Файл | Назначение |
|---|---|
ChatControllerOpenMessageReactionContextMenu.swift |
Меню выбора тега (реакции) |
ChatController.swift |
Основная Premium-проверка для тегов |
ChatControllerOpenMessageContextMenu.swift |
Контекстное меню сообщения |
ChatSearchTitleAccessoryPanelNode.swift |
Панель поиска по тегам |
Пример изменения:
// Было:
if !hasPremium {
showPremiumPaywall()
}
// Стало:
if !hasPremium && !SGLocalPremium.shared.unlimitedSavedMessageTags {
showPremiumPaywall()
}
2. Локальное сохранение тегов
Файл: Telegram-iOS/submodules/TelegramCore/Sources/State/MessageReactions.swift
// MARK: Swiftgram - Skip server sync for tags in Saved Messages when Local Premium is active
if isTags && SGLocalPremium.shared.shouldDisableServerSync {
return postbox.transaction { transaction -> Void in
// 1. Отменяем pending action (не отправляем на сервер)
transaction.setPendingMessageAction(type: .updateReaction, id: messageId, action: nil)
// 2. Объединяем pending и существующие реакции
let mergedReactions = mergedMessageReactions(attributes: currentMessage.attributes, isTags: true)
// 3. Обновляем сообщение с постоянными ReactionsMessageAttribute
transaction.updateMessage(messageId, update: { currentMessage in
// ... обновление атрибутов сообщения
return .update(StoreMessage(...))
})
// 4. Postbox автоматически индексирует customTags
// 5. Обновляем SavedMessageTags для UI
}
}
Ключевой момент: Postbox автоматически индексирует теги при вызове updateMessage.
3. Отключение серверной синхронизации тегов
Файл: Telegram-iOS/submodules/TelegramCore/Sources/State/SavedMessageTags.swift
// MARK: Swiftgram - Skip server sync for tags when Local Premium is active
if SGLocalPremium.shared.shouldDisableServerSync {
return .complete() // Не делаем polling с сервером
}
4. Bypass синхронизации при изменении тегов
Файл: Telegram-iOS/submodules/TelegramCore/Sources/State/ManagedConsumePersonalMessagesActions.swift
// MARK: Swiftgram - When Local Premium is active, skip server sync but mark as cached
if SGLocalPremium.shared.shouldDisableServerSync {
return postbox.transaction { transaction -> Void in
// Помечаем теги как закэшированные, чтобы UI их показывал
transaction.setPreferencesEntry(
key: PreferencesKeys.didCacheSavedMessageTags(threadId: threadId),
value: PreferencesEntry(data: Data())
)
}
|> ignoreValues
}
5. Bypass заполнения "holes" для фильтрации (КЛЮЧЕВОЙ!)
Файл: Telegram-iOS/submodules/TelegramCore/Sources/State/Holes.swift
// MARK: Swiftgram - Skip server requests for customTag holes when Local Premium is active
if case .customTag = space {
switch peerInput {
case let .direct(peerId, _):
if peerId == accountPeerId && SGLocalPremium.shared.shouldDisableServerSync {
return postbox.transaction { transaction -> FetchMessageHistoryHoleResult? in
// Помечаем hole как заполненный
transaction.removeHole(peerId: peerId, threadId: nil, namespace: namespace, space: space, range: minMaxRange)
// Возвращаем пустой результат - система использует локальные данные
return FetchMessageHistoryHoleResult(
removedIndices: IndexSet(integersIn: Int(minMaxRange.lowerBound) ... Int(minMaxRange.upperBound)),
strictRemovedIndices: IndexSet(),
actualPeerId: peerId,
actualThreadId: nil,
ids: []
)
}
}
}
}
Почему это критически важно:
- Без этого bypass система ожидает ответ от сервера на запрос
messages.searchс фильтром по тегу - Сервер либо не отвечает, либо возвращает ошибку Premium
- Результат: бесконечная загрузка
- С bypass: система сразу использует локально проиндексированные сообщения
📝 BUILD конфигурация
Добавление зависимости SGLocalPremium
Для каждого модуля, который использует SGLocalPremium, нужно добавить зависимость в BUILD файл:
deps = [
"//Swiftgram/SGLocalPremium:SGLocalPremium",
# ... другие зависимости
]
Список модулей с добавленной зависимостью
TelegramCore- дляPeerUtils.swift,UserLimitsConfiguration.swift,MessageReactions.swift,SavedMessageTags.swift,Holes.swiftTelegramUI- дляAccountContext.swift,ChatController.swift,ChatControllerLoadDisplayNode.swift,ChatControllerContentData.swiftChatTitleView- дляChatTitleComponent.swiftPeerInfoScreen- дляPeerInfoHeaderNode.swift,PeerInfoScreen.swiftItemListAvatarAndNameInfoItem- дляItemListAvatarAndNameItem.swiftContactsPeerItem- дляContactsPeerItem.swiftCallListUI- дляCallListCallItem.swiftTelegramCallsUI- дляVoiceChatParticipantItem.swiftReactionListContextMenuContent- дляReactionListContextMenuContent.swiftChatListUI- дляChatListItem.swift,ChatListControllerNode.swiftHorizontalTabsComponent- дляHorizontalTabsComponent.swiftIAppsGramSettings- дляIAppsGramSettingsController.swift
Импорт модуля
В каждом файле, использующем SGLocalPremium, добавлен импорт:
import SGLocalPremium
🔍 Критические детали реализации
1. Per-Account настройки
Настройки хранятся отдельно для каждого аккаунта:
// Установка текущего аккаунта
SGLocalPremium.shared.setAccountPeerId(peerId, namespace: namespace)
// Ключ в UserDefaults
"localPremiumEmulate_<namespace>_<peerId>"
Преимущества:
- Настройки не сбрасываются при перезапуске
- Каждый аккаунт имеет независимые настройки
- Простое переключение между аккаунтами
2. Одна настройка для всех функций
Вместо отдельных переключателей используется одна настройка emulatePremium:
public var emulatePremium: Bool // Главная настройка
// Все функции - computed properties
public var showPremiumBadge: Bool { return emulatePremium }
public var unlimitedPinnedChats: Bool { return emulatePremium }
public var unlimitedFolders: Bool { return emulatePremium }
public var unlimitedChatsPerFolder: Bool { return emulatePremium }
public var unlimitedSavedMessageTags: Bool { return emulatePremium }
public var allowFolderReordering: Bool { return emulatePremium }
Преимущества:
- Простой и понятный UI
- Все функции включаются одновременно
- Меньше путаницы для пользователей
3. Отключение серверной синхронизации
Ключевая особенность - отключение синхронизации с сервером:
public var shouldDisableServerSync: Bool {
return emulatePremium
}
Что отключается:
- Синхронизация закрепленных чатов - сервер не откреплит чаты
- Синхронизация папок - сервер не удалит папки
- Синхронизация чатов в папках - сервер не удалит чаты из папок
- Синхронизация порядка папок - сервер не изменит порядок папок
- Синхронизация тегов - сервер не будет синхронизировать теги
Как это работает:
- Функции синхронизации проверяют
shouldDisableServerSync - Если
true, функция возвращает.complete()без выполнения - Локальные изменения остаются только на устройстве
4. Переопределение лимитов
Лимиты переопределяются через методы в SGLocalPremium:
public func getMaxPinnedChatCount(_ original: Int32) -> Int32 {
if unlimitedPinnedChats {
return Int32.max // Безлимит
}
return original // Оригинальный лимит
}
Стратегия:
- Если
emulatePremium = true, возвращаетсяInt32.max - Если
emulatePremium = false, возвращается оригинальный лимит - Применяется ко всем типам лимитов
5. Premium Badge - Ключевое архитектурное решение
Premium значок работает через модификацию Peer.isPremium:
var isPremium: Bool {
switch self {
case let user as TelegramUser:
// Проверяем, является ли это текущим пользователем
if user.id.id._internalGetInt64Value() == SGLocalPremium.shared.currentAccountPeerId?.id &&
user.id.namespace._internalGetInt32Value() == SGLocalPremium.shared.currentAccountPeerId?.namespace {
// Возвращаем true если реальный Premium ИЛИ Local Premium включен
return user.flags.contains(.isPremium) || SGLocalPremium.shared.showPremiumBadge
}
return user.flags.contains(.isPremium)
default:
return false
}
}
Проверки:
- Является ли пользователь текущим аккаунтом?
- Есть ли реальный Premium (
user.flags.contains(.isPremium))? - Включен ли Local Premium (
SGLocalPremium.shared.showPremiumBadge)?
Результат:
- Значок показывается только рядом с вашим именем
- Другие пользователи не видят значок
- Значок виден только на вашем устройстве
- Не исчезает после обновлений с сервера (сервер возвращает
isPremium = false, но проверка|| SGLocalPremium.shared.showPremiumBadgeсохраняет его)
📊 Полный список измененных файлов
Основной модуль
Telegram-iOS/Swiftgram/SGLocalPremium/Sources/SGLocalPremium.swift- Главный менеджер
Core изменения
Telegram-iOS/submodules/TelegramCore/Sources/Utils/PeerUtils.swift- КЛЮЧЕВОЙ - МодификацияPeer.isPremiumTelegram-iOS/submodules/TelegramCore/Sources/State/UserLimitsConfiguration.swift- Лимиты (3 места)Telegram-iOS/submodules/TelegramCore/Sources/State/ManagedSynchronizePinnedChatsOperations.swift- Bypass синхронизации закрепленных чатовTelegram-iOS/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChatListFiltering.swift- Bypass синхронизации папок (2 места)Telegram-iOS/submodules/TelegramCore/Sources/State/MessageReactions.swift- Локальное сохранение теговTelegram-iOS/submodules/TelegramCore/Sources/State/SavedMessageTags.swift- Bypass синхронизации тегов (2 места)Telegram-iOS/submodules/TelegramCore/Sources/State/ManagedConsumePersonalMessagesActions.swift- Bypass с маркером кэшированияTelegram-iOS/submodules/TelegramCore/Sources/State/Holes.swift- КЛЮЧЕВОЙ - Bypass заполнения holes для тегов
UI изменения
Telegram-iOS/submodules/TelegramUI/Sources/AccountContext.swift- Инициализация аккаунтаTelegram-iOS/submodules/TelegramUI/Sources/ChatController.swift- Premium-проверка для теговTelegram-iOS/submodules/TelegramUI/Sources/ChatControllerLoadDisplayNode.swift- Bypass закрытия панели фильтрацииTelegram-iOS/submodules/TelegramUI/Sources/ChatControllerContentData.swift- BypasshasSearchTags(2 места)Telegram-iOS/submodules/TelegramUI/Sources/ChatControllerOpenMessageReactionContextMenu.swift- Premium-проверкаTelegram-iOS/submodules/TelegramUI/Sources/ChatControllerOpenMessageContextMenu.swift- Premium-проверкаTelegram-iOS/submodules/TelegramUI/Sources/ChatSearchTitleAccessoryPanelNode.swift- Premium-проверка (4 места)
UI компоненты (продолжение)
Telegram-iOS/submodules/TelegramUI/Components/ChatTitleView/Sources/ChatTitleComponent.swift- Premium Badge в заголовке чатаTelegram-iOS/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoHeaderNode.swift- Premium Badge в заголовке профиляTelegram-iOS/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift- Premium Badge в профилеTelegram-iOS/submodules/ItemListAvatarAndNameInfoItem/Sources/ItemListAvatarAndNameItem.swift- Premium Badge в элементе спискаTelegram-iOS/submodules/ContactsPeerItem/Sources/ContactsPeerItem.swift- Premium Badge в контактахTelegram-iOS/submodules/CallListUI/Sources/CallListCallItem.swift- Premium Badge в списке звонковTelegram-iOS/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift- Premium Badge в голосовом чатеTelegram-iOS/submodules/Components/ReactionListContextMenuContent/Sources/ReactionListContextMenuContent.swift- Premium Badge в реакцияхTelegram-iOS/submodules/ChatListUI/Sources/ChatListItem.swift- Premium Badge в списке чатов (2 места)Telegram-iOS/submodules/ChatListUI/Sources/ChatListControllerNode.swift- ПередачаcanReorderAllChatsTelegram-iOS/submodules/TelegramUI/Components/HorizontalTabsComponent/Sources/HorizontalTabsComponent.swift- Переупорядочивание папок
Настройки
Telegram-iOS/Swiftgram/IAppsGramSettings/Sources/IAppsGramSettingsController.swift- UI настроек
BUILD файлы
29-40. BUILD файлы для всех модулей выше (добавлена зависимость //Swiftgram/SGLocalPremium:SGLocalPremium)
Итого: 40+ файлов изменено
⚠️ Важные предупреждения и ограничения
1. Клиентская природа функций
Все функции работают только на вашем устройстве:
- Premium Badge виден только вам
- Другие пользователи не видят ваш Premium статус
- Сервер не знает о ваших локальных изменениях
2. Серверная валидация
Сервер может отклонить некоторые изменения:
- При синхронизации с другими устройствами
- При восстановлении из резервной копии
- При переустановке приложения
Что защищено от серверной валидации:
- ✅ Закрепленные чаты (синхронизация отключена)
- ✅ Папки (синхронизация отключена)
- ✅ Чаты в папках (синхронизация отключена)
- ✅ Порядок папок (синхронизация отключена)
- ✅ Теги в Избранном (синхронизация отключена)
3. Локальное хранение
Все данные хранятся локально:
- Настройки в UserDefaults
- Закрепленные чаты в Postbox
- Папки в Postbox
- Теги в Postbox
При удалении приложения:
- ❌ Все локальные данные будут потеряны
- ❌ Настройки Local Premium будут сброшены
- ❌ Локальные теги будут удалены
4. Синхронизация между устройствами
Local Premium НЕ синхронизируется между устройствами:
- Настройки нужно включать на каждом устройстве отдельно
- Закрепленные чаты не синхронизируются (синхронизация отключена)
- Папки не синхронизируются (синхронизация отключена)
- Теги не синхронизируются (синхронизация отключена)
5. Совместимость с реальным Premium
Если у вас есть реальный Premium:
- Local Premium не конфликтует с реальным Premium
- Все функции работают как обычно
- Можно включить Local Premium для дополнительных функций
- Отключение серверной синхронизации работает независимо от реального Premium
🚀 Руководство по использованию
Включение Local Premium
- Откройте Settings → IAppsGram → Local Premium
- Включите переключатель "Emulate Premium"
- Все функции активированы!
Проверка работы Premium Badge
- Включите "Emulate Premium"
- Откройте свой профиль
- Проверьте наличие Premium значка рядом с именем
- Откройте любой чат - значок должен быть в заголовке
- Откройте список чатов - значок должен быть рядом с вашим именем
Тестирование безлимитных закрепленных чатов
- Включите "Emulate Premium"
- Закрепите 6+ чатов (больше стандартного лимита 5)
- Проверьте, что все чаты остаются закрепленными
- Перезапустите приложение
- Проверьте, что все чаты все еще закреплены
Тестирование безлимитных папок
- Включите "Emulate Premium"
- Создайте 11+ папок (больше стандартного лимита 10)
- Проверьте, что все папки созданы
- Перезапустите приложение
- Проверьте, что все папки все еще существуют
Тестирование тегов в Избранном
- Включите "Emulate Premium"
- Откройте "Saved Messages" (Избранное)
- Выберите любое сообщение
- Нажмите на кнопку реакции
- Выберите любую реакцию как тег
- Проверьте, что тег добавлен к сообщению
- Нажмите на тег в панели поиска
- Проверьте, что отображаются только сообщения с этим тегом
Тестирование переупорядочивания папок
- Включите "Emulate Premium"
- Создайте несколько папок
- Зажмите любую папку и перетащите её на первую позицию
- Проверьте, что папка переместилась
- Попробуйте переместить папку "Все чаты" на другую позицию
- Проверьте, что это работает
- Перезапустите приложение
- Проверьте, что порядок папок сохранился
🔧 Troubleshooting (Решение проблем)
Premium Badge не отображается
Проблема: Premium Badge не виден в профиле или чатах.
Решение:
- Проверьте, что "Emulate Premium" включен в настройках
- Перезапустите приложение
- Проверьте, что вы смотрите на свой профиль (не на профиль другого пользователя)
- Проверьте, что
SGLocalPremium.shared.currentAccountPeerIdустановлен правильно
Закрепленные чаты откреплены после перезапуска
Проблема: Закрепленные чаты исчезают после перезапуска приложения.
Решение:
- Проверьте, что "Emulate Premium" включен
- Проверьте, что синхронизация отключена (
shouldDisableServerSync = true) - Проверьте логи на наличие ошибок синхронизации
Папки удалены после перезапуска
Проблема: Созданные папки исчезают после перезапуска.
Решение:
- Проверьте, что "Emulate Premium" включен
- Проверьте, что синхронизация отключена
- Проверьте, что bypass в
ChatListFiltering.swiftработает
Теги не сохраняются
Проблема: Добавленные теги исчезают или не отображаются.
Решение:
- Проверьте, что "Emulate Premium" включен
- Проверьте, что bypass в
MessageReactions.swiftработает - Проверьте, что bypass в
Holes.swiftработает (критически важно!) - Проверьте логи Postbox на наличие ошибок индексации
Бесконечная загрузка при фильтрации по тегу
Проблема: При нажатии на тег в панели поиска появляется бесконечная загрузка.
Решение:
- КРИТИЧЕСКИ ВАЖНО: Проверьте, что bypass в
Holes.swiftработает - Этот bypass предотвращает запросы к серверу для заполнения "holes"
- Без него система ожидает ответ от сервера, который никогда не придет
- Проверьте, что
case .customTagобрабатывается правильно
Настройки сбрасываются при переключении аккаунтов
Проблема: Настройки Local Premium сбрасываются при переключении между аккаунтами.
Решение:
- Это нормальное поведение - настройки per-account
- Каждый аккаунт имеет свои независимые настройки
- Включите "Emulate Premium" для каждого аккаунта отдельно
📚 Дополнительные ресурсы
Связанные документы
LOCAL_PREMIUM_GUIDE.md- Старая версия документации (для справки)LOCAL_PREMIUM_IMPLEMENTATION_PROGRESS.md- История разработки
Ключевые файлы для изучения
- SGLocalPremium.swift - Главный менеджер, начните отсюда
- PeerUtils.swift - Ключевая модификация
Peer.isPremium - UserLimitsConfiguration.swift - Переопределение лимитов
- MessageReactions.swift - Локальное сохранение тегов
- Holes.swift - Критический bypass для фильтрации по тегам
Архитектурные решения
Почему модификация Peer.isPremium вместо проверок в UI?
- ✅ Одно место изменения вместо 10+
- ✅ Автоматически работает везде
- ✅ Не исчезает после обновлений с сервера
- ✅ Проще поддерживать
- ✅ Меньше кода
Почему одна настройка вместо отдельных переключателей?
- ✅ Проще для пользователей
- ✅ Меньше путаницы
- ✅ Все функции работают вместе
- ✅ Проще тестировать
Почему отключение серверной синхронизации?
- ✅ Предотвращает откат изменений сервером
- ✅ Локальные данные остаются на устройстве
- ✅ Не нужно бороться с серверной валидацией
- ✅ Проще реализовать
🎓 Заключение
Local Premium - это комплексная функция, которая эмулирует Premium подписку Telegram локально на устройстве. Ключевые особенности реализации:
- Модификация
Peer.isPremium- главное архитектурное решение для Premium Badge - Отключение серверной синхронизации - защита от отката изменений
- Per-account настройки - независимые настройки для каждого аккаунта
- Одна настройка для всех функций - простой и понятный UI
Все функции работают только на стороне клиента и видны только вам. Сервер не знает о ваших локальных изменениях.