Files
GLEGram-iOS/GLEGram/GLESettingsUI/Sources/FakeProfileSettingsController.swift
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

260 lines
17 KiB
Swift
Executable File
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.
// MARK: Swiftgram Fake Profile settings: target user, name/username/phone/ID, badges
import Foundation
import UIKit
import Display
import SwiftSignalKit
import TelegramPresentationData
import ItemListUI
import PresentationDataUtils
import AccountContext
import SGItemListUI
import SGSimpleSettings
private enum FakeProfileSection: Int32, SGItemListSection {
case targetUser = 0
case personalData
case badges
}
private enum FakeProfileEntry: ItemListNodeEntry {
case targetHeader(id: Int, text: String)
case targetUserId(id: Int, text: String, placeholder: String)
case targetNotice(id: Int, text: String)
case personalHeader(id: Int, text: String)
case firstName(id: Int, text: String, placeholder: String)
case lastName(id: Int, text: String, placeholder: String)
case username(id: Int, text: String, placeholder: String)
case phone(id: Int, text: String, placeholder: String)
case fakeId(id: Int, text: String, placeholder: String)
case personalNotice(id: Int, text: String)
case badgesHeader(id: Int, text: String)
case premium(id: Int, title: String, subtext: String?, value: Bool)
case verified(id: Int, title: String, subtext: String?, value: Bool)
case scam(id: Int, title: String, subtext: String?, value: Bool)
case fake(id: Int, title: String, subtext: String?, value: Bool)
case support(id: Int, title: String, subtext: String?, value: Bool)
case bot(id: Int, title: String, subtext: String?, value: Bool)
case badgesNotice(id: Int, text: String)
var id: Int { stableId }
var section: ItemListSectionId {
switch self {
case .targetHeader, .targetUserId, .targetNotice: return FakeProfileSection.targetUser.rawValue
case .personalHeader, .firstName, .lastName, .username, .phone, .fakeId, .personalNotice: return FakeProfileSection.personalData.rawValue
default: return FakeProfileSection.badges.rawValue
}
}
var stableId: Int {
switch self {
case .targetHeader(let i, _), .targetUserId(let i, _, _), .targetNotice(let i, _),
.personalHeader(let i, _), .firstName(let i, _, _), .lastName(let i, _, _), .username(let i, _, _),
.phone(let i, _, _), .fakeId(let i, _, _), .personalNotice(let i, _),
.badgesHeader(let i, _), .premium(let i, _, _, _), .verified(let i, _, _, _), .scam(let i, _, _, _),
.fake(let i, _, _, _), .support(let i, _, _, _), .bot(let i, _, _, _), .badgesNotice(let i, _): return i
}
}
static func < (lhs: FakeProfileEntry, rhs: FakeProfileEntry) -> Bool { lhs.stableId < rhs.stableId }
static func == (lhs: FakeProfileEntry, rhs: FakeProfileEntry) -> Bool {
switch (lhs, rhs) {
case let (.targetHeader(a, t1), .targetHeader(b, t2)): return a == b && t1 == t2
case let (.targetUserId(a, t1, p1), .targetUserId(b, t2, p2)): return a == b && t1 == t2 && p1 == p2
case let (.targetNotice(a, t1), .targetNotice(b, t2)): return a == b && t1 == t2
case let (.personalHeader(a, t1), .personalHeader(b, t2)): return a == b && t1 == t2
case let (.firstName(a, t1, p1), .firstName(b, t2, p2)): return a == b && t1 == t2 && p1 == p2
case let (.lastName(a, t1, p1), .lastName(b, t2, p2)): return a == b && t1 == t2 && p1 == p2
case let (.username(a, t1, p1), .username(b, t2, p2)): return a == b && t1 == t2 && p1 == p2
case let (.phone(a, t1, p1), .phone(b, t2, p2)): return a == b && t1 == t2 && p1 == p2
case let (.fakeId(a, t1, p1), .fakeId(b, t2, p2)): return a == b && t1 == t2 && p1 == p2
case let (.personalNotice(a, t1), .personalNotice(b, t2)): return a == b && t1 == t2
case let (.badgesHeader(a, t1), .badgesHeader(b, t2)): return a == b && t1 == t2
case let (.premium(a, t1, s1, v1), .premium(b, t2, s2, v2)): return a == b && t1 == t2 && s1 == s2 && v1 == v2
case let (.verified(a, t1, s1, v1), .verified(b, t2, s2, v2)): return a == b && t1 == t2 && s1 == s2 && v1 == v2
case let (.scam(a, t1, s1, v1), .scam(b, t2, s2, v2)): return a == b && t1 == t2 && s1 == s2 && v1 == v2
case let (.fake(a, t1, s1, v1), .fake(b, t2, s2, v2)): return a == b && t1 == t2 && s1 == s2 && v1 == v2
case let (.support(a, t1, s1, v1), .support(b, t2, s2, v2)): return a == b && t1 == t2 && s1 == s2 && v1 == v2
case let (.bot(a, t1, s1, v1), .bot(b, t2, s2, v2)): return a == b && t1 == t2 && s1 == s2 && v1 == v2
case let (.badgesNotice(a, t1), .badgesNotice(b, t2)): return a == b && t1 == t2
default: return false
}
}
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
let theme = presentationData.theme
let args = arguments as! FakeProfileArguments
switch self {
case .targetHeader(_, let text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: section)
case .targetUserId(_, let text, let placeholder):
return ItemListSingleLineInputItem(presentationData: presentationData, systemStyle: .glass, title: NSAttributedString(string: "ID", textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: placeholder, type: .regular(capitalization: false, autocorrection: false), clearType: .always, sectionId: section, textUpdated: { args.updateTargetUserId($0) }, action: {})
case .targetNotice(_, let text):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: section)
case .personalHeader(_, let text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: section)
case .firstName(_, let text, let placeholder):
return ItemListSingleLineInputItem(presentationData: presentationData, systemStyle: .glass, title: NSAttributedString(string: (presentationData.strings.baseLanguageCode == "ru" ? "Имя" : "First name"), textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: placeholder, type: .regular(capitalization: true, autocorrection: false), clearType: .always, sectionId: section, textUpdated: { args.updateFirstName($0) }, action: {})
case .lastName(_, let text, let placeholder):
return ItemListSingleLineInputItem(presentationData: presentationData, systemStyle: .glass, title: NSAttributedString(string: (presentationData.strings.baseLanguageCode == "ru" ? "Фамилия" : "Last name"), textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: placeholder, type: .regular(capitalization: true, autocorrection: false), clearType: .always, sectionId: section, textUpdated: { args.updateLastName($0) }, action: {})
case .username(_, let text, let placeholder):
return ItemListSingleLineInputItem(presentationData: presentationData, systemStyle: .glass, title: NSAttributedString(string: (presentationData.strings.baseLanguageCode == "ru" ? "Юзернейм (без @)" : "Username (no @)"), textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: placeholder, type: .regular(capitalization: false, autocorrection: false), clearType: .always, sectionId: section, textUpdated: { args.updateUsername($0) }, action: {})
case .phone(_, let text, let placeholder):
return ItemListSingleLineInputItem(presentationData: presentationData, systemStyle: .glass, title: NSAttributedString(string: (presentationData.strings.baseLanguageCode == "ru" ? "Телефон (без +)" : "Phone (no +)"), textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: placeholder, type: .number, clearType: .always, sectionId: section, textUpdated: { args.updatePhone($0) }, action: {})
case .fakeId(_, let text, let placeholder):
return ItemListSingleLineInputItem(presentationData: presentationData, systemStyle: .glass, title: NSAttributedString(string: "Telegram ID", textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: placeholder, type: .number, clearType: .always, sectionId: section, textUpdated: { args.updateFakeId($0) }, action: {})
case .personalNotice(_, let text):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: section)
case .badgesHeader(_, let text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: section)
case .premium(_, let title, let subtext, let value):
return ItemListSwitchItem(presentationData: presentationData, systemStyle: .glass, title: title, text: subtext, value: value, sectionId: section, style: .blocks, updated: { args.updatePremium($0) })
case .verified(_, let title, let subtext, let value):
return ItemListSwitchItem(presentationData: presentationData, systemStyle: .glass, title: title, text: subtext, value: value, sectionId: section, style: .blocks, updated: { args.updateVerified($0) })
case .scam(_, let title, let subtext, let value):
return ItemListSwitchItem(presentationData: presentationData, systemStyle: .glass, title: title, text: subtext, value: value, sectionId: section, style: .blocks, updated: { args.updateScam($0) })
case .fake(_, let title, let subtext, let value):
return ItemListSwitchItem(presentationData: presentationData, systemStyle: .glass, title: title, text: subtext, value: value, sectionId: section, style: .blocks, updated: { args.updateFake($0) })
case .support(_, let title, let subtext, let value):
return ItemListSwitchItem(presentationData: presentationData, systemStyle: .glass, title: title, text: subtext, value: value, sectionId: section, style: .blocks, updated: { args.updateSupport($0) })
case .bot(_, let title, let subtext, let value):
return ItemListSwitchItem(presentationData: presentationData, systemStyle: .glass, title: title, text: subtext, value: value, sectionId: section, style: .blocks, updated: { args.updateBot($0) })
case .badgesNotice(_, let text):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: section)
}
}
}
private final class FakeProfileArguments {
let reload: () -> Void
init(reload: @escaping () -> Void) { self.reload = reload }
func updateTargetUserId(_ value: String) {
SGSimpleSettings.shared.fakeProfileTargetUserId = value
reload()
}
func updateFirstName(_ value: String) {
SGSimpleSettings.shared.fakeProfileFirstName = value
reload()
}
func updateLastName(_ value: String) {
SGSimpleSettings.shared.fakeProfileLastName = value
reload()
}
func updateUsername(_ value: String) {
SGSimpleSettings.shared.fakeProfileUsername = value
reload()
}
func updatePhone(_ value: String) {
SGSimpleSettings.shared.fakeProfilePhone = value
reload()
}
func updateFakeId(_ value: String) {
SGSimpleSettings.shared.fakeProfileId = value
reload()
}
func updatePremium(_ value: Bool) {
SGSimpleSettings.shared.fakeProfilePremium = value
reload()
}
func updateVerified(_ value: Bool) {
SGSimpleSettings.shared.fakeProfileVerified = value
reload()
}
func updateScam(_ value: Bool) {
SGSimpleSettings.shared.fakeProfileScam = value
reload()
}
func updateFake(_ value: Bool) {
SGSimpleSettings.shared.fakeProfileFake = value
reload()
}
func updateSupport(_ value: Bool) {
SGSimpleSettings.shared.fakeProfileSupport = value
reload()
}
func updateBot(_ value: Bool) {
SGSimpleSettings.shared.fakeProfileBot = value
reload()
}
}
private func fakeProfileEntries(presentationData: PresentationData) -> [FakeProfileEntry] {
let lang = presentationData.strings.baseLanguageCode
let s = SGSimpleSettings.shared
var entries: [FakeProfileEntry] = []
var id = 0
entries.append(.targetHeader(id: id, text: lang == "ru" ? "ЦЕЛЕВОЙ ПОЛЬЗОВАТЕЛЬ" : "TARGET USER"))
id += 1
entries.append(.targetUserId(id: id, text: s.fakeProfileTargetUserId, placeholder: lang == "ru" ? "Оставьте пустым для своего профиля" : "Leave empty for your profile"))
id += 1
entries.append(.targetNotice(id: id, text: lang == "ru" ? "Чтобы узнать ID, используйте @userinfobot" : "Use @userinfobot to get user ID"))
id += 1
entries.append(.personalHeader(id: id, text: lang == "ru" ? "ЛИЧНЫЕ ДАННЫЕ" : "PERSONAL DATA"))
id += 1
entries.append(.firstName(id: id, text: s.fakeProfileFirstName, placeholder: lang == "ru" ? "Имя" : "First name"))
id += 1
entries.append(.lastName(id: id, text: s.fakeProfileLastName, placeholder: lang == "ru" ? "Фамилия" : "Last name"))
id += 1
entries.append(.username(id: id, text: s.fakeProfileUsername, placeholder: lang == "ru" ? "без @" : "no @"))
id += 1
entries.append(.phone(id: id, text: s.fakeProfilePhone, placeholder: lang == "ru" ? "без +" : "no +"))
id += 1
entries.append(.fakeId(id: id, text: s.fakeProfileId, placeholder: lang == "ru" ? "Визуально изменить ID" : "Override displayed ID"))
id += 1
entries.append(.personalNotice(id: id, text: lang == "ru" ? "Пустые поля — реальные данные." : "Empty = real data."))
id += 1
entries.append(.badgesHeader(id: id, text: lang == "ru" ? "СТАТУСЫ И ЗНАЧКИ" : "BADGES"))
id += 1
let premiumTitle = lang == "ru" ? "Premium" : "Premium"
let premiumSub = lang == "ru" ? "Визуально добавляет иконку Premium." : "Shows Premium badge."
entries.append(.premium(id: id, title: premiumTitle, subtext: premiumSub, value: s.fakeProfilePremium))
id += 1
let verifiedTitle = lang == "ru" ? "Верификация" : "Verified"
let verifiedSub = lang == "ru" ? "Визуально добавляет галочку." : "Shows verification badge."
entries.append(.verified(id: id, title: verifiedTitle, subtext: verifiedSub, value: s.fakeProfileVerified))
id += 1
let scamTitle = lang == "ru" ? "Scam" : "Scam"
let scamSub = lang == "ru" ? "Помечает как скам." : "Marks as scam."
entries.append(.scam(id: id, title: scamTitle, subtext: scamSub, value: s.fakeProfileScam))
id += 1
let fakeTitle = lang == "ru" ? "Fake" : "Fake"
let fakeSub = lang == "ru" ? "Помечает как фейк." : "Marks as fake."
entries.append(.fake(id: id, title: fakeTitle, subtext: fakeSub, value: s.fakeProfileFake))
id += 1
let supportTitle = lang == "ru" ? "Support" : "Support"
let supportSub = lang == "ru" ? "Официальная поддержка." : "Official support badge."
entries.append(.support(id: id, title: supportTitle, subtext: supportSub, value: s.fakeProfileSupport))
id += 1
let botTitle = lang == "ru" ? "Бот" : "Bot"
let botSub = lang == "ru" ? "Помечает как бота." : "Marks as bot."
entries.append(.bot(id: id, title: botTitle, subtext: botSub, value: s.fakeProfileBot))
id += 1
entries.append(.badgesNotice(id: id, text: lang == "ru" ? "Для полного применения может потребоваться перезапуск." : "Restart may be required for full effect."))
return entries
}
/// Fake Profile settings: target user ID, first/last name, username, phone, fake ID, badge toggles.
public func FakeProfileSettingsController(context: AccountContext, onSave: @escaping () -> Void) -> ViewController {
let reloadPromise = ValuePromise(true, ignoreRepeated: false)
let arguments = FakeProfileArguments(reload: { reloadPromise.set(true) })
let signal = combineLatest(reloadPromise.get(), context.sharedContext.presentationData)
|> map { _, presentationData -> (ItemListControllerState, (ItemListNodeState, FakeProfileArguments)) in
let lang = presentationData.strings.baseLanguageCode
let controllerState = ItemListControllerState(
presentationData: ItemListPresentationData(presentationData),
title: .text(lang == "ru" ? "Настройки Fake Profile" : "Fake Profile settings"),
leftNavigationButton: nil,
rightNavigationButton: nil,
backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back)
)
let entries = fakeProfileEntries(presentationData: presentationData)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: entries, style: .blocks, ensureVisibleItemTag: nil, initialScrollToItem: nil)
return (controllerState, (listState, arguments))
}
let controller = ItemListController(context: context, state: signal)
return controller
}