import AppKit import VoiceCatCore final class PermissionsSheet: NSViewController { var onComplete: ((Permissions?) -> Void)? private let targetNickname: String private let initial: Permissions private let canCreateTempChannelCB = NSButton(checkboxWithTitle: "Create temporary channels", target: nil, action: nil) private let canKickCB = NSButton(checkboxWithTitle: "Kick users", target: nil, action: nil) private let canBanCB = NSButton(checkboxWithTitle: "Ban users", target: nil, action: nil) private let canMoveUsersCB = NSButton(checkboxWithTitle: "Move users between channels", target: nil, action: nil) private let canAdminAccountsCB = NSButton(checkboxWithTitle: "Manage accounts", target: nil, action: nil) private let isAdminCB = NSButton(checkboxWithTitle: "Full administrator", target: nil, action: nil) init(nickname: String, current: Permissions) { self.targetNickname = nickname self.initial = current super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { fatalError() } override func loadView() { view = NSView(frame: NSRect(x: 0, y: 0, width: 340, height: 250)) } override func viewDidLoad() { super.viewDidLoad() buildUI() applyInitial() } private func buildUI() { let titleLabel = NSTextField(labelWithString: "Permissions — \(targetNickname)") titleLabel.font = .boldSystemFont(ofSize: 13) let checkboxes = [canCreateTempChannelCB, canKickCB, canBanCB, canMoveUsersCB, canAdminAccountsCB, isAdminCB] for cb in checkboxes { cb.setAccessibilityLabel(cb.title) } let cancelButton = NSButton(title: "Cancel", target: self, action: #selector(cancelClicked)) cancelButton.bezelStyle = .rounded let saveButton = NSButton(title: "Save", target: self, action: #selector(saveClicked)) saveButton.bezelStyle = .rounded; saveButton.keyEquivalent = "\r" saveButton.setAccessibilityLabel("Save permissions for \(targetNickname)") let buttonRow = NSStackView(views: [NSView(), cancelButton, saveButton]) buttonRow.orientation = .horizontal; buttonRow.spacing = 8 var views: [NSView] = [titleLabel] views.append(contentsOf: checkboxes) views.append(buttonRow) let stack = NSStackView(views: views) stack.orientation = .vertical; stack.spacing = 8 stack.alignment = .leading stack.edgeInsets = NSEdgeInsets(top: 16, left: 16, bottom: 16, right: 16) stack.translatesAutoresizingMaskIntoConstraints = false view.addSubview(stack) NSLayoutConstraint.activate([ stack.topAnchor.constraint(equalTo: view.topAnchor), stack.leadingAnchor.constraint(equalTo: view.leadingAnchor), stack.trailingAnchor.constraint(equalTo: view.trailingAnchor), stack.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) } private func applyInitial() { canCreateTempChannelCB.state = initial.canCreateTempChannel ? .on : .off canKickCB.state = initial.canKick ? .on : .off canBanCB.state = initial.canBan ? .on : .off canMoveUsersCB.state = initial.canMoveUsers ? .on : .off canAdminAccountsCB.state = initial.canAdminAccounts ? .on : .off isAdminCB.state = initial.isAdmin ? .on : .off } @objc private func saveClicked() { let perms = Permissions( canCreateTempChannel: canCreateTempChannelCB.state == .on, canKick: canKickCB.state == .on, canBan: canBanCB.state == .on, canMoveUsers: canMoveUsersCB.state == .on, canAdminAccounts: canAdminAccountsCB.state == .on, isAdmin: isAdminCB.state == .on ) dismiss(nil) onComplete?(perms) } @objc private func cancelClicked() { dismiss(nil) onComplete?(nil) } }