Files
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

136 lines
6.3 KiB
Swift

import Foundation
import UIKit
import Display
import AccountContext
import TelegramPresentationData
import SwiftSignalKit
import ContextUI
import TelegramCore
import AvatarNode
import AsyncDisplayKit
import ComponentFlow
import ComponentDisplayAdapters
import EmojiStatusComponent
extension PeerInfoScreenNode {
func accountContextMenuItems(context: AccountContext, logout: @escaping () -> Void) -> Signal<[ContextMenuItem], NoError> {
let strings = context.sharedContext.currentPresentationData.with({ $0 }).strings
return context.engine.messages.unreadChatListPeerIds(groupId: .root, filterPredicate: nil)
|> map { unreadChatListPeerIds -> [ContextMenuItem] in
var items: [ContextMenuItem] = []
if !unreadChatListPeerIds.isEmpty {
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_MarkAllAsRead, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MarkAsRead"), color: theme.contextMenu.primaryColor) }, action: { _, f in
let _ = (context.engine.messages.markAllChatsAsReadInteractively(items: [(groupId: .root, filterPredicate: nil)])
|> deliverOnMainQueue).startStandalone(completed: {
f(.default)
})
})))
}
items.append(.action(ContextMenuActionItem(text: strings.Settings_Context_Logout, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Logout"), color: theme.contextMenu.destructiveColor) }, action: { _, f in
logout()
f(.default)
})))
return items
}
}
func accountContextMenu(id: AccountRecordId, node: ASDisplayNode, gesture: ContextGesture?) {
var selectedAccount: Account?
let _ = (self.accountsAndPeers.get()
|> take(1)
|> deliverOnMainQueue).startStandalone(next: { accountsAndPeers in
for (account, _, _) in accountsAndPeers {
if account.account.id == id {
selectedAccount = account.account
break
}
}
})
if let selectedAccount = selectedAccount {
let accountContext = self.context.sharedContext.makeTempAccountContext(account: selectedAccount)
let chatListController = accountContext.sharedContext.makeChatListController(context: accountContext, location: .chatList(groupId: EngineChatList.Group(.root)), controlsHistoryPreload: false, hideNetworkActivityStatus: true, previewing: true, enableDebugActions: false)
let contextController = makeContextController(presentationData: self.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatListController, sourceNode: node)), items: accountContextMenuItems(context: accountContext, logout: { [weak self] in
self?.logoutAccount(id: id)
}) |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
self.controller?.presentInGlobalOverlay(contextController)
} else {
gesture?.cancel()
}
}
func switchToAccount(id: AccountRecordId) {
self.accountsAndPeers.set(.never())
self.context.sharedContext.switchToAccount(id: id, fromSettingsController: nil, withChatListController: nil)
}
func logoutAccount(id: AccountRecordId) {
let controller = ActionSheetController(presentationData: self.presentationData)
let dismissAction: () -> Void = { [weak controller] in
controller?.dismissAnimated()
}
var items: [ActionSheetItem] = []
items.append(ActionSheetTextItem(title: self.presentationData.strings.Settings_LogoutConfirmationText.trimmingCharacters(in: .whitespacesAndNewlines)))
items.append(ActionSheetButtonItem(title: self.presentationData.strings.Settings_Logout, color: .destructive, action: { [weak self] in
dismissAction()
if let strongSelf = self {
let _ = logoutFromAccount(id: id, accountManager: strongSelf.context.sharedContext.accountManager, alreadyLoggedOutRemotely: false).startStandalone()
}
}))
controller.setItemGroups([
ActionSheetItemGroup(items: items),
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
])
self.controller?.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}
}
final class PeerInfoControllerContextReferenceContentSource: ContextReferenceContentSource {
let controller: ViewController
let sourceView: UIView
let insets: UIEdgeInsets
let contentInsets: UIEdgeInsets
init(controller: ViewController, sourceView: UIView, insets: UIEdgeInsets, contentInsets: UIEdgeInsets = UIEdgeInsets()) {
self.controller = controller
self.sourceView = sourceView
self.insets = insets
self.contentInsets = contentInsets
}
func transitionInfo() -> ContextControllerReferenceViewInfo? {
return ContextControllerReferenceViewInfo(referenceView: self.sourceView, contentAreaInScreenSpace: UIScreen.main.bounds.inset(by: self.insets), insets: self.contentInsets)
}
}
final class HeaderContextReferenceContentSource: ContextReferenceContentSource {
private let controller: ViewController
private let sourceView: UIView
init(controller: ViewController, sourceView: UIView) {
self.controller = controller
self.sourceView = sourceView
}
func transitionInfo() -> ContextControllerReferenceViewInfo? {
return ContextControllerReferenceViewInfo(referenceView: self.sourceView, contentAreaInScreenSpace: UIScreen.main.bounds)
}
}
private func cancelContextGestures(view: UIView) {
if let gestureRecognizers = view.gestureRecognizers {
for gesture in gestureRecognizers {
if let gesture = gesture as? ContextGesture {
gesture.cancel()
}
}
}
for subview in view.subviews {
cancelContextGestures(view: subview)
}
}