Files
i2p.i2p/launchers/macosx/I2PLauncher/userinterface/Style2019/ServiceTableViewController.swift

267 lines
8.1 KiB
Swift

//
// ServiceTableViewController.swift
// I2PLauncher
//
// Created by Mikal Villa on 20/04/2019.
// Copyright © 2019 The I2P Project. All rights reserved.
//
import Cocoa
import SnapKit
import MBPopup
class ServiceTableViewController: NSObject, SwitchableTableViewController {
let contentView = NSStackView(frame: CGRect(x: 0, y: 0, width: 220, height: 400))
let scrollView = CustomScrollView()
let tableView = NSTableView()
let bottomBar = BottomBar()
let addServicesNoticeField = NSTextField()
var editorTableViewController: EditorTableViewController
var services: [BaseService] = [I2PRouterService(),HttpTunnelService(),IrcTunnelService()] {
didSet {
addServicesNoticeField.isHidden = services.count > 0
}
}
var servicesBeingUpdated = [BaseService]()
var generalStatus: ServiceStatus {
let hasBadServices = services.first { $0.status > .stopped } != nil
return hasBadServices ? .killed : .started
}
var hidden: Bool = false
var updateCallback: (() -> Void)?
override init() {
self.editorTableViewController = EditorTableViewController(contentView: contentView, scrollView: scrollView)
super.init()
}
func setup() {
//bottomBar.reloadServicesCallback = (NSApp.delegate as? SwiftApplicationDelegate)!.updateServices
bottomBar.openSettingsCallback = { [weak self] in
self?.hide()
self?.editorTableViewController.show()
}
bottomBar.closeSettingsCallback = { [weak self] in
self?.editorTableViewController.hide()
self?.show()
}
contentView.snp.makeConstraints { make in
make.left.right.bottom.equalTo(0)
make.width.greaterThanOrEqualTo(220)
make.height.greaterThanOrEqualTo(40 + 30 + 2) // tableView.rowHeight + bottomBar.frame.size.height + 2
}
contentView.addSubview(scrollView)
contentView.addSubview(bottomBar)
scrollView.snp.makeConstraints { make in
scrollView.topConstraint = make.top.equalToSuperview().constraint
make.left.right.equalTo(0)
}
bottomBar.snp.makeConstraints { make in
make.width.equalToSuperview()
make.top.equalTo(scrollView.snp.bottom)
make.height.equalTo(30)
make.left.right.equalTo(0)
make.bottom.equalTo(0)
}
contentView.addSubview(addServicesNoticeField)
addServicesNoticeField.snp.makeConstraints { make in
make.height.equalTo(22)
make.left.right.equalTo(0)
make.centerY.equalToSuperview().offset(-14)
}
scrollView.borderType = .noBorder
scrollView.hasVerticalScroller = true
scrollView.hasHorizontalScroller = false
scrollView.autoresizesSubviews = true
scrollView.documentView = tableView
scrollView.drawsBackground = false
scrollView.wantsLayer = true
scrollView.layer?.cornerRadius = 6
tableView.frame = scrollView.bounds
let column = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: "serviceColumnIdentifier"))
column.width = tableView.frame.size.width
tableView.addTableColumn(column)
tableView.autoresizesSubviews = true
tableView.wantsLayer = true
tableView.layer?.cornerRadius = 6
tableView.headerView = nil
tableView.rowHeight = 40
tableView.gridStyleMask = NSTableView.GridLineStyle.init(rawValue: 0)
tableView.dataSource = self
tableView.delegate = self
tableView.selectionHighlightStyle = .none
tableView.backgroundColor = NSColor.clear
addServicesNoticeField.isEditable = false
addServicesNoticeField.isBordered = false
addServicesNoticeField.isSelectable = false
let italicFont = NSFontManager.shared.font(
withFamily: NSFont.systemFont(ofSize: 13).fontName,
traits: NSFontTraitMask.italicFontMask,
weight: 5,
size: 13
)
addServicesNoticeField.font = italicFont
addServicesNoticeField.textColor = NSColor.textColor
addServicesNoticeField.maximumNumberOfLines = 1
addServicesNoticeField.cell!.truncatesLastVisibleLine = true
addServicesNoticeField.alignment = .center
addServicesNoticeField.stringValue = "Oh, maybe too empty? :)"
addServicesNoticeField.backgroundColor = .clear
}
func willOpenPopup() {
resizeViews()
reloadData()
if case let .updated(date) = bottomBar.status {
if Date().timeIntervalSince1970 - date.timeIntervalSince1970 > 60 {
//(NSApp.delegate as? SwiftApplicationDelegate)?.updateServices()
}
}
}
func willShow() {
scrollView.topConstraint?.update(offset: 0)
scrollView.documentView = tableView
if editorTableViewController.selectionChanged {
//self.services = ["I2PRouter","HttpTunnel"]//Preferences.shared.selectedServices
reloadData()
//(NSApp.delegate as? SwiftApplicationDelegate)?.updateServices()
} else {
addServicesNoticeField.isHidden = services.count > 0
}
resizeViews()
}
func willHide() {
addServicesNoticeField.isHidden = true
}
func resizeViews() {
var frame = scrollView.frame
frame.size.height = min(tableView.intrinsicContentSize.height, 490)
scrollView.frame = frame
//(NSApp.delegate as? SwiftApplicationDelegate)?.popupController.resizePopup(height: scrollView.frame.size.height + bottomBar.frame.size.height)
}
func reloadData(at index: Int? = nil) {
services.sort()
bottomBar.updateStatusText()
guard index != nil else {
tableView.reloadData()
return
}
tableView.reloadData(forRowIndexes: IndexSet(integer: index!), columnIndexes: IndexSet(integer: 0))
}
func updateServices(updateCallback: @escaping () -> Void) {
self.servicesBeingUpdated = [Service]()
guard services.count > 0 else {
reloadData()
bottomBar.status = .updated(Date())
self.updateCallback?()
self.updateCallback = nil
return
}
self.updateCallback = updateCallback
let serviceCallback: ((BaseService) -> Void) = { [weak self] service in self?.updatedStatus(for: service) }
bottomBar.status = .updating
services.forEach {
servicesBeingUpdated.append($0)
$0.updateStatus(callback: serviceCallback)
}
}
func updatedStatus(for service: BaseService) {
if let index = servicesBeingUpdated.index(of: service) {
servicesBeingUpdated.remove(at: index)
}
DispatchQueue.main.async { [weak self] in
self?.reloadData()
if self?.servicesBeingUpdated.count == 0 {
self?.bottomBar.status = .updated(Date())
self?.updateCallback?()
self?.updateCallback = nil
}
}
}
}
extension ServiceTableViewController: NSTableViewDataSource {
func numberOfRows(in tableView: NSTableView) -> Int {
return services.count
}
func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
return nil
}
}
extension ServiceTableViewController: NSTableViewDelegate {
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let identifier = tableColumn?.identifier ?? NSUserInterfaceItemIdentifier(rawValue: "identifier")
let cell = tableView.makeView(withIdentifier: identifier, owner: self) ?? StatusTableCell()
guard let view = cell as? StatusTableCell else { return nil }
guard let service = services[row] as? Service else { return nil }
view.textField?.stringValue = service.name
view.statusField.stringValue = service.message
view.statusIndicator.status = service.status
return view
}
func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
let cellIdentifier = NSUserInterfaceItemIdentifier(rawValue: "rowView")
let cell = tableView.makeView(withIdentifier: cellIdentifier, owner: self) ?? ServiceTableRowView()
guard let view = cell as? ServiceTableRowView else { return nil }
view.showSeparator = row + 1 < services.count
return view
}
func tableView(_ tableView: NSTableView, shouldSelectRow row: Int) -> Bool {
guard let _ = services[row] as? Service else { return false }
//NSWorkspace.shared.open(service.url)
return false
}
}