260 lines
8.9 KiB
Swift
260 lines
8.9 KiB
Swift
//
|
|
// RemoteConfigViewController.swift
|
|
// ClashX
|
|
//
|
|
// Created by yicheng on 2019/7/28.
|
|
// Copyright © 2019 west2online. All rights reserved.
|
|
//
|
|
|
|
import Cocoa
|
|
import RxSwift
|
|
|
|
class RemoteConfigViewController: NSViewController {
|
|
@IBOutlet var tableView: NSTableView!
|
|
@IBOutlet var deleteButton: NSButton!
|
|
@IBOutlet var updateButton: NSButton!
|
|
|
|
private var latestAddedConfig: RemoteConfigModel?
|
|
|
|
let disposeBag = DisposeBag()
|
|
|
|
deinit {
|
|
print("RemoteConfigViewController deinit")
|
|
}
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
updateButtonStatus()
|
|
tableView.doubleAction = #selector(tableViewDidDoubleClick(tableView:))
|
|
|
|
NotificationCenter.default
|
|
.rx.notification(Notification.Name("didGetUrl")).bind {
|
|
[weak self] note in
|
|
guard let self = self else { return }
|
|
guard let url = note.userInfo?["url"] as? String else { return }
|
|
|
|
let name = note.userInfo?["name"] as? String
|
|
self.showAdd(defaultUrl: url, name: name, allowAlt: true)
|
|
}.disposed(by: disposeBag)
|
|
}
|
|
|
|
override func viewWillAppear() {
|
|
super.viewWillAppear()
|
|
view.window?.level = .floating
|
|
NSApp.activate(ignoringOtherApps: true)
|
|
}
|
|
|
|
override func viewWillDisappear() {
|
|
super.viewWillDisappear()
|
|
RemoteConfigManager.shared.saveConfigs()
|
|
}
|
|
|
|
// MARK: Actions
|
|
|
|
@IBAction func actionAdd(_ sender: Any) {
|
|
showAdd()
|
|
}
|
|
|
|
@IBAction func actionDelete(_ sender: Any) {
|
|
RemoteConfigManager.shared.configs.safeRemove(at: tableView.selectedRow)
|
|
tableView.reloadData()
|
|
updateButtonStatus()
|
|
}
|
|
|
|
@IBAction func actionUpdate(_ sender: Any) {
|
|
guard let model = RemoteConfigManager.shared.configs[safe: tableView.selectedRow] else { return }
|
|
requestUpdate(config: model)
|
|
tableView.reloadDataKeepingSelection()
|
|
}
|
|
}
|
|
|
|
extension RemoteConfigViewController {
|
|
func updateButtonStatus() {
|
|
let selectIdx = tableView.selectedRow
|
|
if selectIdx == -1 {
|
|
deleteButton.isEnabled = false
|
|
updateButton.isEnabled = false
|
|
return
|
|
}
|
|
|
|
guard let config = RemoteConfigManager.shared.configs[safe: selectIdx] else { return }
|
|
deleteButton.isEnabled = true
|
|
updateButton.isEnabled = !config.updating
|
|
}
|
|
|
|
func showAdd(defaultUrl: String? = nil,
|
|
defaultName: String? = nil,
|
|
name: String? = nil,
|
|
allowAlt: Bool = false) {
|
|
let alertView = NSAlert()
|
|
alertView.addButton(withTitle: NSLocalizedString("OK", comment: ""))
|
|
alertView.addButton(withTitle: NSLocalizedString("Cancel", comment: ""))
|
|
alertView.messageText = NSLocalizedString("Add a remote config", comment: "")
|
|
let remoteConfigInputView = RemoteConfigAddView.createFromNib()
|
|
if let defaultUrl = defaultUrl {
|
|
remoteConfigInputView.setUrl(string: defaultUrl, name: name, defaultName: defaultName)
|
|
}
|
|
alertView.accessoryView = remoteConfigInputView
|
|
let response = alertView.runModal()
|
|
|
|
guard response == .alertFirstButtonReturn else { return }
|
|
guard remoteConfigInputView.isVaild() else {
|
|
let alert = NSAlert()
|
|
alert.messageText = NSLocalizedString("Invalid input", comment: "")
|
|
alert.alertStyle = .warning
|
|
alert.runModal()
|
|
return
|
|
}
|
|
|
|
let configName = remoteConfigInputView.getConfigName().0
|
|
let isPlaceHolderName = remoteConfigInputView.getConfigName().1
|
|
let configUrl = remoteConfigInputView.getUrlString()
|
|
|
|
if let existed = RemoteConfigManager.shared.configs.first(where: { $0.name == configName }) {
|
|
guard allowAlt else {
|
|
NSAlert.alert(with: NSLocalizedString("The remote config name is duplicated", comment: ""))
|
|
return
|
|
}
|
|
existed.url = configUrl
|
|
latestAddedConfig = existed
|
|
requestUpdate(config: existed)
|
|
} else {
|
|
let remoteConfig = RemoteConfigModel(url: configUrl,
|
|
name: configName,
|
|
updateTime: nil)
|
|
remoteConfig.isPlaceHolderName = !isPlaceHolderName
|
|
RemoteConfigManager.shared.configs.append(remoteConfig)
|
|
requestUpdate(config: remoteConfig)
|
|
latestAddedConfig = remoteConfig
|
|
}
|
|
|
|
tableView.reloadData()
|
|
updateButtonStatus()
|
|
}
|
|
|
|
func requestUpdate(config: RemoteConfigModel) {
|
|
guard !config.updating else { return }
|
|
config.updating = true
|
|
RemoteConfigManager.updateConfig(config: config) {
|
|
[weak self, weak config] errorString in
|
|
guard let self = self, let config = config else { return }
|
|
config.updating = false
|
|
if let errorString = errorString {
|
|
let alert = NSAlert()
|
|
alert.messageText = errorString
|
|
alert.alertStyle = .warning
|
|
alert.runModal()
|
|
} else {
|
|
config.updateTime = Date()
|
|
RemoteConfigManager.shared.saveConfigs()
|
|
|
|
if config == self.latestAddedConfig {
|
|
AppDelegate.shared.updateConfig(configName: config.name)
|
|
} else if config.name == ConfigManager.selectConfigName {
|
|
AppDelegate.shared.updateConfig()
|
|
}
|
|
}
|
|
self.tableView.reloadDataKeepingSelection()
|
|
}
|
|
}
|
|
}
|
|
|
|
extension RemoteConfigViewController: NSTableViewDelegate {
|
|
func tableViewSelectionDidChange(_ notification: Notification) {
|
|
updateButtonStatus()
|
|
}
|
|
|
|
@objc func tableViewDidDoubleClick(tableView: NSTableView) {
|
|
let row = tableView.clickedRow
|
|
guard let config = RemoteConfigManager.shared.configs[safe: row] else { return }
|
|
if config.isPlaceHolderName {
|
|
showAdd(defaultUrl: config.url, defaultName: config.name, name: nil, allowAlt: true)
|
|
} else {
|
|
showAdd(defaultUrl: config.url, defaultName: nil, name: config.name, allowAlt: true)
|
|
}
|
|
}
|
|
}
|
|
|
|
extension RemoteConfigViewController: NSTableViewDataSource {
|
|
func numberOfRows(in tableView: NSTableView) -> Int {
|
|
return RemoteConfigManager.shared.configs.count
|
|
}
|
|
|
|
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
|
|
guard let config = RemoteConfigManager.shared.configs[safe: row] else { return nil }
|
|
|
|
func setupCell(withIdentifier: String, string: String, textFieldtag: Int = 1) -> NSView? {
|
|
let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: withIdentifier), owner: nil)
|
|
if let textField = cell?.viewWithTag(1) as? NSTextField {
|
|
textField.stringValue = string
|
|
} else {
|
|
assertionFailure()
|
|
}
|
|
|
|
return cell
|
|
}
|
|
|
|
switch tableColumn?.identifier.rawValue ?? "" {
|
|
case "url":
|
|
return setupCell(withIdentifier: "urlCell", string: config.url)
|
|
case "configName":
|
|
return setupCell(withIdentifier: "nameCell", string: config.name)
|
|
case "updateTime":
|
|
return setupCell(withIdentifier: "timeCell", string: config.displayingTimeString())
|
|
|
|
default: assertionFailure()
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
class RemoteConfigAddView: NSView, NibLoadable {
|
|
@IBOutlet private var urlTextField: NSTextField!
|
|
@IBOutlet private var configNameTextField: NSTextField!
|
|
|
|
func getUrlString() -> String {
|
|
return urlTextField.stringValue
|
|
}
|
|
|
|
/// Get the config name
|
|
/// - Returns: return (name, isUserInput)
|
|
func getConfigName() -> (String, Bool) {
|
|
if configNameTextField.stringValue.count > 0 {
|
|
return (configNameTextField.stringValue, true)
|
|
}
|
|
return (configNameTextField.placeholderString ?? "", false)
|
|
}
|
|
|
|
func isVaild() -> Bool {
|
|
return urlTextField.stringValue.isUrlVaild() && getConfigName().0.count > 0
|
|
}
|
|
|
|
func setUrl(string: String, name: String? = nil, defaultName: String?) {
|
|
urlTextField.stringValue = string
|
|
|
|
if let name = name, name.count > 0 {
|
|
configNameTextField.stringValue = name
|
|
}
|
|
|
|
if let defaultName = defaultName, defaultName.count > 0 {
|
|
configNameTextField.placeholderString = defaultName
|
|
}
|
|
|
|
if name == nil && defaultName == nil {
|
|
updateConfigName()
|
|
}
|
|
}
|
|
|
|
private func updateConfigName() {
|
|
guard urlTextField.stringValue.isUrlVaild() else { return }
|
|
let urlString = urlTextField.stringValue
|
|
configNameTextField.placeholderString = URL(string: urlString)?.host ?? "unknown"
|
|
}
|
|
}
|
|
|
|
extension RemoteConfigAddView: NSTextFieldDelegate {
|
|
func controlTextDidChange(_ obj: Notification) {
|
|
updateConfigName()
|
|
}
|
|
}
|