Files
GLEGram-iOS/docs/LOCAL_PREMIUM_GUIDE.md
Leeksov 4647310322 GLEGram 12.5 — Initial public release
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.
2026-04-06 09:48:12 +03:00

1008 lines
45 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Local Premium (Emulate Premium) - Полная документация реализации
## 📋 Описание
Local Premium — это функция, которая эмулирует Premium подписку Telegram локально на устройстве без реальной подписки.
**Важно**: Все функции работают только на стороне клиента и видны только вам. Сервер Telegram не видит эти изменения.
---
## 🎯 Реализованная функциональность
### ✅ Основные функции
1. **Premium Badge** - Показывает значок Premium рядом с вашим именем везде в приложении
2. **Безлимитные закрепленные чаты** - Закрепляйте сколько угодно чатов (вместо лимита 5)
3. **Безлимитные папки** - Создавайте сколько угодно папок (вместо лимита 10)
4. **Безлимитные чаты в папке** - Добавляйте сколько угодно чатов в папку (вместо лимита 100)
5. **Безлимитные теги в Избранном** - Добавляйте теги к сообщениям в Saved Messages
6. **Переупорядочивание папок** - Перемещайте любую папку на первую позицию (включая "Все чаты")
### ✅ Отключение серверной синхронизации
- **Закрепленные чаты**: Сервер не будет откреплять чаты при превышении лимита
- **Папки**: Сервер не будет удалять папки при превышении лимита
- **Чаты в папках**: Сервер не будет удалять чаты из папок при превышении лимита
- **Порядок папок**: Сервер не будет изменять порядок папок
- **Теги в Избранном**: Сервер не будет синхронизировать теги
### ✅ Расположение настроек
**Settings → IAppsGram → Local Premium:**
- Один переключатель "Emulate Premium"
- Подробное описание всех включенных функций
- Предупреждение о клиентской природе функций
---
## 🏗️ Архитектура решения
### Ключевая инновация: Модификация Peer.isPremium
**Главное архитектурное решение** - модификация свойства `Peer.isPremium` в `PeerUtils.swift`:
```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`
### Полный код класса
```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`
```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`
```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`
```swift
public var maxPinnedChatCount: Int32 {
// MARK: Swiftgram Local Premium - Unlimited pinned chats
return SGLocalPremium.shared.getMaxPinnedChatCount(
self.isPremium ? self.defaultMaxPremiumPinnedChatCount : self.defaultMaxPinnedChatCount
)
}
```
**Метод в SGLocalPremium:**
```swift
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`
```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`
```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`
```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`
```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`
```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`
```swift
public final class HorizontalTabsComponent: Component {
public let canReorderAllChats: Bool
public init(
// ... другие параметры
canReorderAllChats: Bool = true
) {
self.canReorderAllChats = canReorderAllChats
// ...
}
}
```
**Проверка возможности переупорядочивания:**
```swift
// 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`
```swift
let tabsComponent = HorizontalTabsComponent(
// ... другие параметры
canReorderAllChats: SGLocalPremium.shared.canReorderAllChats(isPremium: self.context.isPremium)
)
```
**Метод в SGLocalPremium:**
```swift
public func canReorderAllChats(isPremium: Bool) -> Bool {
if isPremium {
return true
}
return allowFolderReordering
}
```
---
## 🎨 UI компоненты
### Контроллер настроек IAppsGram
**Файл**: `Telegram-iOS/Swiftgram/IAppsGramSettings/Sources/IAppsGramSettingsController.swift`
### Секция Local Premium в UI
```swift
// MARK: - Local Premium Section
case localPremiumHeader(PresentationTheme, String)
case localPremiumEmulate(PresentationTheme, String, Bool)
case localPremiumInfo(PresentationTheme, String)
```
### Генерация UI элементов
```swift
// 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."
))
```
### Обработчик переключателя
```swift
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` | Панель поиска по тегам |
**Пример изменения:**
```swift
// Было:
if !hasPremium {
showPremiumPaywall()
}
// Стало:
if !hasPremium && !SGLocalPremium.shared.unlimitedSavedMessageTags {
showPremiumPaywall()
}
```
#### 2. Локальное сохранение тегов
**Файл**: `Telegram-iOS/submodules/TelegramCore/Sources/State/MessageReactions.swift`
```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`
```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`
```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`
```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 файл:
```python
deps = [
"//Swiftgram/SGLocalPremium:SGLocalPremium",
# ... другие зависимости
]
```
### Список модулей с добавленной зависимостью
1. `TelegramCore` - для `PeerUtils.swift`, `UserLimitsConfiguration.swift`, `MessageReactions.swift`, `SavedMessageTags.swift`, `Holes.swift`
2. `TelegramUI` - для `AccountContext.swift`, `ChatController.swift`, `ChatControllerLoadDisplayNode.swift`, `ChatControllerContentData.swift`
3. `ChatTitleView` - для `ChatTitleComponent.swift`
4. `PeerInfoScreen` - для `PeerInfoHeaderNode.swift`, `PeerInfoScreen.swift`
5. `ItemListAvatarAndNameInfoItem` - для `ItemListAvatarAndNameItem.swift`
6. `ContactsPeerItem` - для `ContactsPeerItem.swift`
7. `CallListUI` - для `CallListCallItem.swift`
8. `TelegramCallsUI` - для `VoiceChatParticipantItem.swift`
9. `ReactionListContextMenuContent` - для `ReactionListContextMenuContent.swift`
10. `ChatListUI` - для `ChatListItem.swift`, `ChatListControllerNode.swift`
11. `HorizontalTabsComponent` - для `HorizontalTabsComponent.swift`
12. `IAppsGramSettings` - для `IAppsGramSettingsController.swift`
### Импорт модуля
В каждом файле, использующем `SGLocalPremium`, добавлен импорт:
```swift
import SGLocalPremium
```
---
## 🔍 Критические детали реализации
### 1. Per-Account настройки
Настройки хранятся отдельно для каждого аккаунта:
```swift
// Установка текущего аккаунта
SGLocalPremium.shared.setAccountPeerId(peerId, namespace: namespace)
// Ключ в UserDefaults
"localPremiumEmulate_<namespace>_<peerId>"
```
**Преимущества:**
- Настройки не сбрасываются при перезапуске
- Каждый аккаунт имеет независимые настройки
- Простое переключение между аккаунтами
### 2. Одна настройка для всех функций
Вместо отдельных переключателей используется одна настройка `emulatePremium`:
```swift
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. Отключение серверной синхронизации
Ключевая особенность - отключение синхронизации с сервером:
```swift
public var shouldDisableServerSync: Bool {
return emulatePremium
}
```
**Что отключается:**
1. **Синхронизация закрепленных чатов** - сервер не откреплит чаты
2. **Синхронизация папок** - сервер не удалит папки
3. **Синхронизация чатов в папках** - сервер не удалит чаты из папок
4. **Синхронизация порядка папок** - сервер не изменит порядок папок
5. **Синхронизация тегов** - сервер не будет синхронизировать теги
**Как это работает:**
- Функции синхронизации проверяют `shouldDisableServerSync`
- Если `true`, функция возвращает `.complete()` без выполнения
- Локальные изменения остаются только на устройстве
### 4. Переопределение лимитов
Лимиты переопределяются через методы в `SGLocalPremium`:
```swift
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`:
```swift
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
}
}
```
**Проверки:**
1. Является ли пользователь текущим аккаунтом?
2. Есть ли реальный Premium (`user.flags.contains(.isPremium)`)?
3. Включен ли Local Premium (`SGLocalPremium.shared.showPremiumBadge`)?
**Результат:**
- Значок показывается только рядом с вашим именем
- Другие пользователи не видят значок
- Значок виден только на вашем устройстве
- **Не исчезает после обновлений с сервера** (сервер возвращает `isPremium = false`, но проверка `|| SGLocalPremium.shared.showPremiumBadge` сохраняет его)
---
## 📊 Полный список измененных файлов
### Основной модуль
1. `Telegram-iOS/Swiftgram/SGLocalPremium/Sources/SGLocalPremium.swift` - Главный менеджер
### Core изменения
2. `Telegram-iOS/submodules/TelegramCore/Sources/Utils/PeerUtils.swift` - **КЛЮЧЕВОЙ** - Модификация `Peer.isPremium`
3. `Telegram-iOS/submodules/TelegramCore/Sources/State/UserLimitsConfiguration.swift` - Лимиты (3 места)
4. `Telegram-iOS/submodules/TelegramCore/Sources/State/ManagedSynchronizePinnedChatsOperations.swift` - Bypass синхронизации закрепленных чатов
5. `Telegram-iOS/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChatListFiltering.swift` - Bypass синхронизации папок (2 места)
6. `Telegram-iOS/submodules/TelegramCore/Sources/State/MessageReactions.swift` - Локальное сохранение тегов
7. `Telegram-iOS/submodules/TelegramCore/Sources/State/SavedMessageTags.swift` - Bypass синхронизации тегов (2 места)
8. `Telegram-iOS/submodules/TelegramCore/Sources/State/ManagedConsumePersonalMessagesActions.swift` - Bypass с маркером кэширования
9. `Telegram-iOS/submodules/TelegramCore/Sources/State/Holes.swift` - **КЛЮЧЕВОЙ** - Bypass заполнения holes для тегов
### UI изменения
10. `Telegram-iOS/submodules/TelegramUI/Sources/AccountContext.swift` - Инициализация аккаунта
11. `Telegram-iOS/submodules/TelegramUI/Sources/ChatController.swift` - Premium-проверка для тегов
12. `Telegram-iOS/submodules/TelegramUI/Sources/ChatControllerLoadDisplayNode.swift` - Bypass закрытия панели фильтрации
13. `Telegram-iOS/submodules/TelegramUI/Sources/ChatControllerContentData.swift` - Bypass `hasSearchTags` (2 места)
14. `Telegram-iOS/submodules/TelegramUI/Sources/ChatControllerOpenMessageReactionContextMenu.swift` - Premium-проверка
15. `Telegram-iOS/submodules/TelegramUI/Sources/ChatControllerOpenMessageContextMenu.swift` - Premium-проверка
16. `Telegram-iOS/submodules/TelegramUI/Sources/ChatSearchTitleAccessoryPanelNode.swift` - Premium-проверка (4 места)
### UI компоненты (продолжение)
17. `Telegram-iOS/submodules/TelegramUI/Components/ChatTitleView/Sources/ChatTitleComponent.swift` - Premium Badge в заголовке чата
18. `Telegram-iOS/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoHeaderNode.swift` - Premium Badge в заголовке профиля
19. `Telegram-iOS/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift` - Premium Badge в профиле
20. `Telegram-iOS/submodules/ItemListAvatarAndNameInfoItem/Sources/ItemListAvatarAndNameItem.swift` - Premium Badge в элементе списка
21. `Telegram-iOS/submodules/ContactsPeerItem/Sources/ContactsPeerItem.swift` - Premium Badge в контактах
22. `Telegram-iOS/submodules/CallListUI/Sources/CallListCallItem.swift` - Premium Badge в списке звонков
23. `Telegram-iOS/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift` - Premium Badge в голосовом чате
24. `Telegram-iOS/submodules/Components/ReactionListContextMenuContent/Sources/ReactionListContextMenuContent.swift` - Premium Badge в реакциях
25. `Telegram-iOS/submodules/ChatListUI/Sources/ChatListItem.swift` - Premium Badge в списке чатов (2 места)
26. `Telegram-iOS/submodules/ChatListUI/Sources/ChatListControllerNode.swift` - Передача `canReorderAllChats`
27. `Telegram-iOS/submodules/TelegramUI/Components/HorizontalTabsComponent/Sources/HorizontalTabsComponent.swift` - Переупорядочивание папок
### Настройки
28. `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
1. Откройте **Settings → IAppsGram → Local Premium**
2. Включите переключатель **"Emulate Premium"**
3. Все функции активированы!
### Проверка работы Premium Badge
1. Включите "Emulate Premium"
2. Откройте свой профиль
3. Проверьте наличие Premium значка рядом с именем
4. Откройте любой чат - значок должен быть в заголовке
5. Откройте список чатов - значок должен быть рядом с вашим именем
### Тестирование безлимитных закрепленных чатов
1. Включите "Emulate Premium"
2. Закрепите 6+ чатов (больше стандартного лимита 5)
3. Проверьте, что все чаты остаются закрепленными
4. Перезапустите приложение
5. Проверьте, что все чаты все еще закреплены
### Тестирование безлимитных папок
1. Включите "Emulate Premium"
2. Создайте 11+ папок (больше стандартного лимита 10)
3. Проверьте, что все папки созданы
4. Перезапустите приложение
5. Проверьте, что все папки все еще существуют
### Тестирование тегов в Избранном
1. Включите "Emulate Premium"
2. Откройте "Saved Messages" (Избранное)
3. Выберите любое сообщение
4. Нажмите на кнопку реакции
5. Выберите любую реакцию как тег
6. Проверьте, что тег добавлен к сообщению
7. Нажмите на тег в панели поиска
8. Проверьте, что отображаются только сообщения с этим тегом
### Тестирование переупорядочивания папок
1. Включите "Emulate Premium"
2. Создайте несколько папок
3. Зажмите любую папку и перетащите её на первую позицию
4. Проверьте, что папка переместилась
5. Попробуйте переместить папку "Все чаты" на другую позицию
6. Проверьте, что это работает
7. Перезапустите приложение
8. Проверьте, что порядок папок сохранился
---
## 🔧 Troubleshooting (Решение проблем)
### Premium Badge не отображается
**Проблема**: Premium Badge не виден в профиле или чатах.
**Решение:**
1. Проверьте, что "Emulate Premium" включен в настройках
2. Перезапустите приложение
3. Проверьте, что вы смотрите на свой профиль (не на профиль другого пользователя)
4. Проверьте, что `SGLocalPremium.shared.currentAccountPeerId` установлен правильно
### Закрепленные чаты откреплены после перезапуска
**Проблема**: Закрепленные чаты исчезают после перезапуска приложения.
**Решение:**
1. Проверьте, что "Emulate Premium" включен
2. Проверьте, что синхронизация отключена (`shouldDisableServerSync = true`)
3. Проверьте логи на наличие ошибок синхронизации
### Папки удалены после перезапуска
**Проблема**: Созданные папки исчезают после перезапуска.
**Решение:**
1. Проверьте, что "Emulate Premium" включен
2. Проверьте, что синхронизация отключена
3. Проверьте, что bypass в `ChatListFiltering.swift` работает
### Теги не сохраняются
**Проблема**: Добавленные теги исчезают или не отображаются.
**Решение:**
1. Проверьте, что "Emulate Premium" включен
2. Проверьте, что bypass в `MessageReactions.swift` работает
3. Проверьте, что bypass в `Holes.swift` работает (критически важно!)
4. Проверьте логи Postbox на наличие ошибок индексации
### Бесконечная загрузка при фильтрации по тегу
**Проблема**: При нажатии на тег в панели поиска появляется бесконечная загрузка.
**Решение:**
1. **КРИТИЧЕСКИ ВАЖНО**: Проверьте, что bypass в `Holes.swift` работает
2. Этот bypass предотвращает запросы к серверу для заполнения "holes"
3. Без него система ожидает ответ от сервера, который никогда не придет
4. Проверьте, что `case .customTag` обрабатывается правильно
### Настройки сбрасываются при переключении аккаунтов
**Проблема**: Настройки Local Premium сбрасываются при переключении между аккаунтами.
**Решение:**
1. Это нормальное поведение - настройки per-account
2. Каждый аккаунт имеет свои независимые настройки
3. Включите "Emulate Premium" для каждого аккаунта отдельно
---
## 📚 Дополнительные ресурсы
### Связанные документы
- `LOCAL_PREMIUM_GUIDE.md` - Старая версия документации (для справки)
- `LOCAL_PREMIUM_IMPLEMENTATION_PROGRESS.md` - История разработки
### Ключевые файлы для изучения
1. **SGLocalPremium.swift** - Главный менеджер, начните отсюда
2. **PeerUtils.swift** - Ключевая модификация `Peer.isPremium`
3. **UserLimitsConfiguration.swift** - Переопределение лимитов
4. **MessageReactions.swift** - Локальное сохранение тегов
5. **Holes.swift** - Критический bypass для фильтрации по тегам
### Архитектурные решения
**Почему модификация `Peer.isPremium` вместо проверок в UI?**
- ✅ Одно место изменения вместо 10+
- ✅ Автоматически работает везде
- ✅ Не исчезает после обновлений с сервера
- ✅ Проще поддерживать
- ✅ Меньше кода
**Почему одна настройка вместо отдельных переключателей?**
- ✅ Проще для пользователей
- ✅ Меньше путаницы
- ✅ Все функции работают вместе
- ✅ Проще тестировать
**Почему отключение серверной синхронизации?**
- ✅ Предотвращает откат изменений сервером
- ✅ Локальные данные остаются на устройстве
- ✅ Не нужно бороться с серверной валидацией
- ✅ Проще реализовать
---
## 🎓 Заключение
Local Premium - это комплексная функция, которая эмулирует Premium подписку Telegram локально на устройстве. Ключевые особенности реализации:
1. **Модификация `Peer.isPremium`** - главное архитектурное решение для Premium Badge
2. **Отключение серверной синхронизации** - защита от отката изменений
3. **Per-account настройки** - независимые настройки для каждого аккаунта
4. **Одна настройка для всех функций** - простой и понятный UI
Все функции работают только на стороне клиента и видны только вам. Сервер не знает о ваших локальных изменениях.