mirror of
https://github.com/ichmagmaus111/ghostgram.git
synced 2026-11-03 14:17:19 +01:00
Ghostgram for iOS, rebuilt from scratch on Telegram iOS 13.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
139 lines
5.3 KiB
Swift
139 lines
5.3 KiB
Swift
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))
|
||
))
|
||
}
|
||
}
|