Files
ichmagmaus111andClaude Opus 5.5 0622057a4f Ghostgram: open-source release
Ghostgram for iOS, rebuilt from scratch on Telegram iOS 13.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 17:57:09 +01:00

139 lines
5.3 KiB
Swift
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.
import Foundation
import Display
import SwiftSignalKit
import AccountContext
import GGCore
import GGHooks
import GGSettingsUI
import GGFeaturesShared
/// Entry point of the GGVless feature module («Ещё › VPN по подписке»). Owner: W3-5.
public enum GGVlessModule {
static let serversTab = GGMenuTabID("vless.servers")
static let mainSection = GGMenuSectionID("vless.main")
static let optionsSection = GGMenuSectionID("vless.options")
/// Declares settings, menu rows, hook handlers and migrations. Called once on the main
/// thread from `GGFeatures.registerAll()`, before `GGHookRegistry.freeze()`.
public static func register() {
GGVlessSettings.declare()
let _ = GGVlessLegacy.loopbackPort
GGVlessModule.registerMenu()
// «О приложении › Сторонние компоненты» (requests/W3-5.md R5): the core is Xray-core
// (MPL-2.0) with its Go dependencies (BSD / MIT / Apache-2.0); listed only in builds that
// carry the core.
GGMenuRegistry.register(license: GGMenuLicense(
id: "vless.xrayCore",
name: "Xray-core",
license: "MPL-2.0",
url: "https://github.com/XTLS/Xray-core",
note: { GGStrings.Vless.License.note },
order: 100,
isVisible: {
return GGXrayCore.isBundled
}
))
GGLifecycleHooks.rootControllersDidLoad.register({ context, _ in
GGVlessController.shared.attach(context: context)
}, order: 0)
// Telegram's proxy screen links here: with the VPN on, Telegram's proxy is the core's loopback
// entry, which that screen does not list.
GGVpnEntryPoint.makeScreen = { context in
guard let context = context as? AccountContext else {
return nil
}
return ggVlessMakeServersController(context: context)
}
GGVpnEntryPoint.stateText = {
if !GGXrayCore.isBundled {
return GGStrings.Vless.ProxyEntry.notBundled
}
return GGVlessSettings.enabled.value ? GGStrings.Vless.ProxyEntry.on : GGStrings.Vless.ProxyEntry.off
}
GGVlessLegacy.registerMigration()
// Starts the core in the background if the VPN was on (nothing is loaded otherwise).
GGVlessController.shared.setup()
}
private static func registerMenu() {
GGMenuRegistry.register(section: GGMenuSectionDescriptor(
id: GGVlessModule.mainSection,
screen: .tab(.moreVpn),
order: 300,
footer: { _ in
return GGXrayCore.isBundled ? nil : GGStrings.Vless.Status.notBundled
}
))
GGMenuRegistry.register(section: GGMenuSectionDescriptor(
id: GGVlessModule.optionsSection,
screen: .tab(.moreVpn),
order: 400,
footer: { _ in GGStrings.Vless.Menu.footer }
))
GGMenuRegistry.register(GGMenuRow(
id: "vless.enabled",
section: GGVlessModule.mainSection,
order: 100,
title: { GGStrings.Vless.Menu.enable },
subtitle: { GGStrings.Vless.Menu.enableInfo },
kind: .toggle(.global(GGVlessSettings.enabled)),
searchKeywords: { [GGStrings.Vless.Menu.keywords] },
isEnabled: { _ in
// Switching on needs the core in this build and a chosen server; switching off is
// always possible.
if GGVlessSettings.enabled.value {
return true
}
return GGXrayCore.isBundled && !GGVlessSettings.selectedServer.value.isEmpty
}
))
GGMenuRegistry.register(
tab: GGMenuTabDescriptor(
id: GGVlessModule.serversTab,
parent: .tab(.moreVpn),
title: { GGStrings.Vless.Menu.servers },
makeScreen: { context in
return ggVlessMakeServersController(context: context.context)
},
searchKeywords: { [GGStrings.Vless.Menu.keywords] }
),
linkIn: GGVlessModule.mainSection,
order: 200,
subtitle: { GGStrings.Vless.Menu.serversInfo },
icon: .bundle("Chat/Context Menu/Globe"),
label: { _ in
let id = GGVlessSettings.selectedServer.value
if id.isEmpty {
return GGStrings.Vless.Menu.noServer
}
return GGVlessStore.shared.server(id: id)?.1.name
}
)
GGMenuRegistry.register(GGMenuRow(
id: "vless.proxyBypassOnVpn",
section: GGVlessModule.optionsSection,
order: 100,
title: { GGStrings.Vless.Menu.bypass },
subtitle: { GGStrings.Vless.Menu.bypassInfo },
kind: .toggle(.global(GGNetworkSpoofSharedSettings.proxyBypassOnVpn))
))
GGMenuRegistry.register(GGMenuRow(
id: "vless.sendHwid",
section: GGVlessModule.optionsSection,
order: 200,
title: { GGStrings.Vless.Menu.hwid },
subtitle: { GGStrings.Vless.Menu.hwidInfo },
kind: .toggle(.global(GGVlessSettings.sendHwid))
))
}
}