392 lines
16 KiB
Swift
392 lines
16 KiB
Swift
//
|
|
// DeveloperViewController.swift
|
|
// Telegram
|
|
//
|
|
// Created by keepcoder on 30/11/2017.
|
|
// Copyright © 2017 Telegram. All rights reserved.
|
|
//
|
|
|
|
import Cocoa
|
|
import TGUIKit
|
|
import SwiftSignalKit
|
|
import TelegramCore
|
|
import ApiCredentials
|
|
import MtProtoKit
|
|
import Postbox
|
|
import ThemeSettings
|
|
|
|
private final class DeveloperArguments {
|
|
let importColors:()->Void
|
|
let exportColors:()->Void
|
|
let toggleLogs:(Bool)->Void
|
|
let navigateToLogs:()->Void
|
|
let addAccount:()->Void
|
|
let toggleMenu:(Bool)->Void
|
|
let toggleAnimatedInputEmoji:()->Void
|
|
let toggleNativeGraphicContext:()->Void
|
|
let toggleDebugWebApp:()->Void
|
|
let toggleNetwork:()->Void
|
|
let toggleDownloads:()->Void
|
|
let toggleCanViewPeerId:()->Void
|
|
init(importColors:@escaping()->Void, exportColors:@escaping()->Void, toggleLogs:@escaping(Bool)->Void, navigateToLogs:@escaping()->Void, addAccount: @escaping() -> Void, toggleMenu:@escaping(Bool)->Void, toggleDebugWebApp:@escaping()->Void, toggleAnimatedInputEmoji: @escaping()->Void, toggleNativeGraphicContext:@escaping()->Void, toggleNetwork:@escaping()->Void, toggleDownloads:@escaping()->Void, toggleCanViewPeerId:@escaping()->Void) {
|
|
self.importColors = importColors
|
|
self.exportColors = exportColors
|
|
self.toggleLogs = toggleLogs
|
|
self.navigateToLogs = navigateToLogs
|
|
self.addAccount = addAccount
|
|
self.toggleMenu = toggleMenu
|
|
self.toggleDebugWebApp = toggleDebugWebApp
|
|
self.toggleAnimatedInputEmoji = toggleAnimatedInputEmoji
|
|
self.toggleNativeGraphicContext = toggleNativeGraphicContext
|
|
self.toggleNetwork = toggleNetwork
|
|
self.toggleDownloads = toggleDownloads
|
|
self.toggleCanViewPeerId = toggleCanViewPeerId
|
|
}
|
|
}
|
|
|
|
private enum DeveloperEntryId : Hashable {
|
|
case importColors
|
|
case exportColors
|
|
case toggleLogs
|
|
case openLogs
|
|
case accounts
|
|
case enableFilters
|
|
case toggleMenu
|
|
case animateInputEmoji
|
|
case nativeGraphicContext
|
|
case crash
|
|
case debugWebApp
|
|
case network
|
|
case downloads
|
|
case showPeerId
|
|
case section(Int32)
|
|
var hashValue: Int {
|
|
switch self {
|
|
case .importColors:
|
|
return 0
|
|
case .exportColors:
|
|
return 1
|
|
case .toggleLogs:
|
|
return 2
|
|
case .openLogs:
|
|
return 3
|
|
case .accounts:
|
|
return 4
|
|
case .enableFilters:
|
|
return 5
|
|
case .toggleMenu:
|
|
return 6
|
|
case .animateInputEmoji:
|
|
return 7
|
|
case .nativeGraphicContext:
|
|
return 8
|
|
case .debugWebApp:
|
|
return 9
|
|
case .crash:
|
|
return 10
|
|
case .network:
|
|
return 11
|
|
case .downloads:
|
|
return 12
|
|
case .showPeerId:
|
|
return 13
|
|
case .section(let section):
|
|
return 14 + Int(section)
|
|
}
|
|
}
|
|
}
|
|
|
|
private enum DeveloperEntry : TableItemListNodeEntry {
|
|
|
|
case importColors(sectionId: Int32)
|
|
case exportColors(sectionId: Int32)
|
|
case toggleLogs(sectionId: Int32, enabled: Bool)
|
|
case openLogs(sectionId: Int32)
|
|
case accounts(sectionId: Int32)
|
|
case enableFilters(sectionId: Int32, enabled: Bool)
|
|
case toggleMenu(sectionId: Int32, enabled: Bool)
|
|
case animateInputEmoji(sectionId: Int32, enabled: Bool)
|
|
case nativeGraphicContext(sectionId: Int32, enabled: Bool)
|
|
case crash(sectionId: Int32)
|
|
case debugWebApp(sectionId: Int32)
|
|
case network(sectionId: Int32, enabled: Bool)
|
|
case downloads(sectionId: Int32, enabled: Bool)
|
|
case showPeerId(sectionId: Int32, enabled: Bool)
|
|
case section(Int32)
|
|
|
|
var stableId:DeveloperEntryId {
|
|
switch self {
|
|
case .importColors:
|
|
return .importColors
|
|
case .exportColors:
|
|
return .exportColors
|
|
case .toggleLogs:
|
|
return .toggleLogs
|
|
case .openLogs:
|
|
return .openLogs
|
|
case .accounts:
|
|
return .accounts
|
|
case .enableFilters:
|
|
return .enableFilters
|
|
case .toggleMenu:
|
|
return .toggleMenu
|
|
case .animateInputEmoji:
|
|
return .animateInputEmoji
|
|
case .nativeGraphicContext:
|
|
return .nativeGraphicContext
|
|
case .crash:
|
|
return .crash
|
|
case .debugWebApp:
|
|
return .debugWebApp
|
|
case .network:
|
|
return .network
|
|
case .downloads:
|
|
return .downloads
|
|
case .showPeerId:
|
|
return .showPeerId
|
|
case .section(let section):
|
|
return .section(section)
|
|
}
|
|
}
|
|
|
|
var index:Int32 {
|
|
switch self {
|
|
case .importColors(let sectionId):
|
|
return (sectionId * 1000) + Int32(stableId.hashValue)
|
|
case .exportColors(let sectionId):
|
|
return (sectionId * 1000) + Int32(stableId.hashValue)
|
|
case .toggleLogs(let sectionId, _):
|
|
return (sectionId * 1000) + Int32(stableId.hashValue)
|
|
case .openLogs(let sectionId):
|
|
return (sectionId * 1000) + Int32(stableId.hashValue)
|
|
case .accounts(let sectionId):
|
|
return (sectionId * 1000) + Int32(stableId.hashValue)
|
|
case .enableFilters(let sectionId, _):
|
|
return (sectionId * 1000) + Int32(stableId.hashValue)
|
|
case let .toggleMenu(sectionId, _):
|
|
return (sectionId * 1000) + Int32(stableId.hashValue)
|
|
case let .animateInputEmoji(sectionId, _):
|
|
return (sectionId * 1000) + Int32(stableId.hashValue)
|
|
case let .nativeGraphicContext(sectionId, _):
|
|
return (sectionId * 1000) + Int32(stableId.hashValue)
|
|
case let .crash(sectionId):
|
|
return (sectionId * 1000) + Int32(stableId.hashValue)
|
|
case let .debugWebApp(sectionId):
|
|
return (sectionId * 1000) + Int32(stableId.hashValue)
|
|
case let .network(sectionId, _):
|
|
return (sectionId * 1000) + Int32(stableId.hashValue)
|
|
case let .downloads(sectionId, _):
|
|
return (sectionId * 1000) + Int32(stableId.hashValue)
|
|
case let .showPeerId(sectionId, _):
|
|
return (sectionId * 1000) + Int32(stableId.hashValue)
|
|
case .section(let sectionId):
|
|
return (sectionId + 1) * 1000 - sectionId
|
|
}
|
|
}
|
|
|
|
static func <(lhs: DeveloperEntry, rhs: DeveloperEntry) -> Bool {
|
|
return lhs.index < rhs.index
|
|
}
|
|
|
|
|
|
func item(_ arguments: DeveloperArguments, initialSize: NSSize) -> TableRowItem {
|
|
switch self {
|
|
case .importColors:
|
|
return GeneralInteractedRowItem(initialSize, stableId: stableId, name: "Import Palette", type: .next, action: {
|
|
arguments.importColors()
|
|
})
|
|
case .exportColors:
|
|
return GeneralInteractedRowItem(initialSize, stableId: stableId, name: "Export Palette", type: .next, action: {
|
|
arguments.exportColors()
|
|
})
|
|
case .openLogs:
|
|
return GeneralInteractedRowItem(initialSize, stableId: stableId, name: "Open Logs", type: .next, action: {
|
|
arguments.navigateToLogs()
|
|
})
|
|
case .accounts:
|
|
return GeneralInteractedRowItem(initialSize, stableId: stableId, name: "Add Account", type: .next, action: {
|
|
arguments.addAccount()
|
|
})
|
|
case let .enableFilters(_, enabled):
|
|
return GeneralInteractedRowItem(initialSize, stableId: stableId, name: "Enable Filters", type: .switchable(enabled), action: {
|
|
})
|
|
case let .toggleLogs(_, enabled):
|
|
return GeneralInteractedRowItem(initialSize, stableId: stableId, name: "Enable Logs", type: .switchable(enabled), action: {
|
|
arguments.toggleLogs(!enabled)
|
|
})
|
|
case let .toggleMenu(_, enabled):
|
|
return GeneralInteractedRowItem(initialSize, stableId: stableId, name: "Native Context Menu (Get Ready for glitches)", type: .switchable(enabled), action: {
|
|
arguments.toggleMenu(!enabled)
|
|
})
|
|
case let .animateInputEmoji(_, enabled):
|
|
return GeneralInteractedRowItem(initialSize, stableId: stableId, name: "Animate Emoji to Input", type: .switchable(enabled), action: arguments.toggleAnimatedInputEmoji)
|
|
case let .nativeGraphicContext(_, enabled):
|
|
return GeneralInteractedRowItem(initialSize, stableId: stableId, name: "Use Native Graphic Context", type: .switchable(enabled), action: arguments.toggleNativeGraphicContext)
|
|
case .crash:
|
|
return GeneralInteractedRowItem(initialSize, stableId: stableId, name: "Crash App", type: .none, action: {
|
|
var array:[Int] = []
|
|
array[1] = 0
|
|
})
|
|
case .debugWebApp:
|
|
return GeneralInteractedRowItem(initialSize, stableId: stableId, name: "Debug Web App", type: .switchable(FastSettings.debugWebApp), action: arguments.toggleDebugWebApp)
|
|
case let .network(_, enabled):
|
|
return GeneralInteractedRowItem(initialSize, stableId: stableId, name: "Experimental Network", type: .switchable(enabled), action: arguments.toggleNetwork)
|
|
case let .downloads(_, enabled):
|
|
return GeneralInteractedRowItem(initialSize, stableId: stableId, name: "Experimental Downloads", type: .switchable(enabled), action: arguments.toggleDownloads)
|
|
case let .showPeerId(_, enabled):
|
|
return GeneralInteractedRowItem(initialSize, stableId: stableId, name: "Show Peer Id on Profile Page", type: .switchable(enabled), action: arguments.toggleCanViewPeerId)
|
|
case .section:
|
|
return GeneralRowItem(initialSize, height: 20, stableId: stableId)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
private func developerEntries(loginSettings: LoggingSettings, networkSettings: NetworkSettings) -> [DeveloperEntry] {
|
|
var entries:[DeveloperEntry] = []
|
|
|
|
var sectionId:Int32 = 1
|
|
|
|
entries.append(.section(sectionId))
|
|
sectionId += 1
|
|
|
|
entries.append(.accounts(sectionId: sectionId))
|
|
|
|
entries.append(.section(sectionId))
|
|
sectionId += 1
|
|
|
|
entries.append(.toggleLogs(sectionId: sectionId, enabled: loginSettings.logToFile))
|
|
|
|
entries.append(.openLogs(sectionId: sectionId))
|
|
entries.append(.toggleMenu(sectionId: sectionId, enabled: System.legacyMenu))
|
|
entries.append(.animateInputEmoji(sectionId: sectionId, enabled: FastSettings.animateInputEmoji))
|
|
entries.append(.nativeGraphicContext(sectionId: sectionId, enabled: FastSettings.useNativeGraphicContext))
|
|
entries.append(.debugWebApp(sectionId: sectionId))
|
|
entries.append(.network(sectionId: sectionId, enabled: networkSettings.useNetworkFramework ?? false))
|
|
entries.append(.downloads(sectionId: sectionId, enabled: networkSettings.useExperimentalDownload ?? false))
|
|
entries.append(.showPeerId(sectionId: sectionId, enabled: FastSettings.canViewPeerId))
|
|
|
|
entries.append(.crash(sectionId: sectionId))
|
|
|
|
entries.append(.section(sectionId))
|
|
sectionId += 1
|
|
|
|
|
|
entries.append(.section(sectionId))
|
|
sectionId += 1
|
|
return entries
|
|
}
|
|
|
|
fileprivate func prepareTransition(left:[AppearanceWrapperEntry<DeveloperEntry>], right: [AppearanceWrapperEntry<DeveloperEntry>], initialSize:NSSize, arguments:DeveloperArguments) -> TableUpdateTransition {
|
|
|
|
let (removed, inserted, updated) = proccessEntriesWithoutReverse(left, right: right) { entry -> TableRowItem in
|
|
return entry.entry.item(arguments, initialSize: initialSize)
|
|
}
|
|
|
|
return TableUpdateTransition(deleted: removed, inserted: inserted, updated: updated, animated: true)
|
|
}
|
|
|
|
class DeveloperViewController: TableViewController {
|
|
|
|
init(context: AccountContext) {
|
|
super.init(context)
|
|
}
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
|
|
genericView.getBackgroundColor = {
|
|
theme.colors.background
|
|
}
|
|
|
|
let context = self.context
|
|
let previousEntries:Atomic<[AppearanceWrapperEntry<DeveloperEntry>]> = Atomic(value: [])
|
|
let initialSize = self.atomicSize
|
|
let arguments = DeveloperArguments(importColors: {
|
|
filePanel(with: ["palette"], allowMultiple: false, for: context.window, completion: { list in
|
|
if let path = list?.first {
|
|
if let theme = importPalette(path) {
|
|
let palettesDir = ApiEnvironment.containerURL!.appendingPathComponent("Palettes").path
|
|
try? FileManager.default.createDirectory(atPath: palettesDir, withIntermediateDirectories: true, attributes: nil)
|
|
try? FileManager.default.removeItem(atPath: palettesDir + "/" + path.nsstring.lastPathComponent)
|
|
try? FileManager.default.copyItem(atPath: path, toPath: palettesDir + "/" + path.nsstring.lastPathComponent)
|
|
_ = updateThemeInteractivetly(accountManager: context.sharedContext.accountManager, f: { settings in
|
|
return settings.withUpdatedPalette(theme).withUpdatedCloudTheme(nil)
|
|
}).start()
|
|
} else {
|
|
alert(for: context.window, info: "Parsing Error")
|
|
}
|
|
}
|
|
})
|
|
}, exportColors: {
|
|
exportPalette(palette: theme.colors)
|
|
}, toggleLogs: { enabled in
|
|
MTLogSetEnabled(enabled)
|
|
_ = updateLoggingSettings(accountManager: context.sharedContext.accountManager, {
|
|
$0.withUpdatedLogToFile(enabled)
|
|
}).start()
|
|
Logger.shared.logToConsole = false
|
|
Logger.shared.logToFile = enabled
|
|
}, navigateToLogs: {
|
|
NSWorkspace.shared.activateFileViewerSelecting([ApiEnvironment.containerURL!.appendingPathComponent("logs")])
|
|
}, addAccount: {
|
|
let testingEnvironment = NSApp.currentEvent?.modifierFlags.contains(.command) == true
|
|
context.sharedContext.beginNewAuth(testingEnvironment: testingEnvironment)
|
|
}, toggleMenu: { value in
|
|
_ = updateThemeInteractivetly(accountManager: context.sharedContext.accountManager, f: { settings in
|
|
return settings.withUpdatedLegacyMenu(value)
|
|
}).start()
|
|
}, toggleDebugWebApp: {
|
|
FastSettings.toggleDebugWebApp()
|
|
}, toggleAnimatedInputEmoji: {
|
|
FastSettings.toggleAnimateInputEmoji()
|
|
}, toggleNativeGraphicContext: {
|
|
FastSettings.toggleNativeGraphicContext()
|
|
appDelegate?.updateGraphicContext()
|
|
}, toggleNetwork: {
|
|
_ = updateNetworkSettingsInteractively(postbox: context.account.postbox, network: context.account.network, { current in
|
|
var current = current
|
|
if let value = current.useNetworkFramework {
|
|
current.useNetworkFramework = !value
|
|
} else {
|
|
current.useNetworkFramework = true
|
|
}
|
|
return current
|
|
}).start()
|
|
}, toggleDownloads: {
|
|
_ = updateNetworkSettingsInteractively(postbox: context.account.postbox, network: context.account.network, { current in
|
|
var current = current
|
|
if let value = current.useExperimentalDownload {
|
|
current.useExperimentalDownload = !value
|
|
} else {
|
|
current.useExperimentalDownload = true
|
|
}
|
|
return current
|
|
}).start()
|
|
}, toggleCanViewPeerId: {
|
|
FastSettings.canViewPeerId = !FastSettings.canViewPeerId
|
|
})
|
|
|
|
let network = context.account.postbox.preferencesView(keys: [PreferencesKeys.networkSettings]) |> map {
|
|
return $0.values[PreferencesKeys.networkSettings]?.get(NetworkSettings.self) ?? .defaultSettings
|
|
}
|
|
|
|
let signal = combineLatest(queue: prepareQueue, context.sharedContext.accountManager.sharedData(keys: [SharedDataKeys.loggingSettings]), appearanceSignal, themeSettingsView(accountManager: context.sharedContext.accountManager), network)
|
|
|
|
|
|
|
|
|
|
genericView.merge(with: signal |> map { preferences, appearance, theme, network in
|
|
let entries = developerEntries(loginSettings: preferences.entries[SharedDataKeys.loggingSettings]?.get(LoggingSettings.self) ?? LoggingSettings.defaultSettings, networkSettings: network).map{AppearanceWrapperEntry(entry: $0, appearance: appearance)}
|
|
return prepareTransition(left: previousEntries.swap(entries), right: entries, initialSize: initialSize.modify({$0}), arguments: arguments)
|
|
} |> deliverOnMainQueue)
|
|
|
|
readyOnce()
|
|
}
|
|
|
|
override var defaultBarTitle: String {
|
|
return "Developer"
|
|
}
|
|
|
|
}
|