diff --git a/Box42.xcodeproj/project.pbxproj b/Box42.xcodeproj/project.pbxproj index e36dc27..a5f301d 100644 --- a/Box42.xcodeproj/project.pbxproj +++ b/Box42.xcodeproj/project.pbxproj @@ -7,7 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - D65C5C7C2AA195AB00BD291A /* prefsHelper.app in Resources */ = {isa = PBXBuildFile; fileRef = D65C5C7B2AA195AB00BD291A /* prefsHelper.app */; }; DE018BB32A5099F900FF0AA3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE018BB22A5099F900FF0AA3 /* AppDelegate.swift */; }; DE018BB82A5099F900FF0AA3 /* Box42.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DE018BB62A5099F900FF0AA3 /* Box42.xcdatamodeld */; }; DE018BDD2A509AEB00FF0AA3 /* EventMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE018BDC2A509AEB00FF0AA3 /* EventMonitor.swift */; }; @@ -125,11 +124,15 @@ DEF0762A2AA3B955005700E5 /* PutUserMeQuickSlot.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF076292AA3B955005700E5 /* PutUserMeQuickSlot.swift */; }; DEF0762D2AA3C34C005700E5 /* GetUserMeQuickSlot.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF0762C2AA3C34C005700E5 /* GetUserMeQuickSlot.swift */; }; DEF076302AA3CF8A005700E5 /* QuickSlotItemLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF0762F2AA3CF8A005700E5 /* QuickSlotItemLabel.swift */; }; + DEF076362AA47FDB005700E5 /* QuickSlotManagerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF076352AA47FDB005700E5 /* QuickSlotManagerViewController.swift */; }; + DEF0763A2AA480C6005700E5 /* QuickSlotTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF076392AA480C6005700E5 /* QuickSlotTableView.swift */; }; + DEF0763D2AA48125005700E5 /* QuickSlotCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF0763C2AA48125005700E5 /* QuickSlotCell.swift */; }; + DEF076402AA4845E005700E5 /* QuickSlotCellManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF0763F2AA4845E005700E5 /* QuickSlotCellManager.swift */; }; + DEF076432AA48AF0005700E5 /* QuickSlotCellDeleteButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF076422AA48AF0005700E5 /* QuickSlotCellDeleteButton.swift */; }; DEF749322A85657600D987C8 /* NSScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF749312A85657600D987C8 /* NSScreen.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - D65C5C7B2AA195AB00BD291A /* prefsHelper.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; name = prefsHelper.app; path = ../../Downloads/prefsHelper.app; sourceTree = ""; }; DE018BAF2A5099F900FF0AA3 /* Box42.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Box42.app; sourceTree = BUILT_PRODUCTS_DIR; }; DE018BB22A5099F900FF0AA3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; DE018BB72A5099F900FF0AA3 /* Box42.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Box42.xcdatamodel; sourceTree = ""; }; @@ -249,6 +252,11 @@ DEF076292AA3B955005700E5 /* PutUserMeQuickSlot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PutUserMeQuickSlot.swift; sourceTree = ""; }; DEF0762C2AA3C34C005700E5 /* GetUserMeQuickSlot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetUserMeQuickSlot.swift; sourceTree = ""; }; DEF0762F2AA3CF8A005700E5 /* QuickSlotItemLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickSlotItemLabel.swift; sourceTree = ""; }; + DEF076352AA47FDB005700E5 /* QuickSlotManagerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickSlotManagerViewController.swift; sourceTree = ""; }; + DEF076392AA480C6005700E5 /* QuickSlotTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickSlotTableView.swift; sourceTree = ""; }; + DEF0763C2AA48125005700E5 /* QuickSlotCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickSlotCell.swift; sourceTree = ""; }; + DEF0763F2AA4845E005700E5 /* QuickSlotCellManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickSlotCellManager.swift; sourceTree = ""; }; + DEF076422AA48AF0005700E5 /* QuickSlotCellDeleteButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickSlotCellDeleteButton.swift; sourceTree = ""; }; DEF7492E2A85603700D987C8 /* nodeInstall.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = nodeInstall.sh; sourceTree = ""; }; DEF749312A85657600D987C8 /* NSScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSScreen.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -268,7 +276,6 @@ DE018BA62A5099F900FF0AA3 = { isa = PBXGroup; children = ( - D65C5C7B2AA195AB00BD291A /* prefsHelper.app */, DE018BB12A5099F900FF0AA3 /* Box42 */, DE018BB02A5099F900FF0AA3 /* Products */, DE17AF722A834A1600325BF4 /* Frameworks */, @@ -660,6 +667,7 @@ DE98E8412A98DDEB00F8744A /* View */ = { isa = PBXGroup; children = ( + DEF076382AA480B7005700E5 /* Table */, DE44081C2A928F760091937A /* Divider.swift */, DE97CA782A9A6F6A001073DE /* QuickSlotHeaderView.swift */, DE97CA7B2A9A7199001073DE /* QuickSlotGroupView.swift */, @@ -741,6 +749,7 @@ children = ( DE98E8422A98DDFD00F8744A /* QuickSlotViewController.swift */, DE6332F12A9BCA2C00DCFAF6 /* QuickSlotScriptsLogicController.swift */, + DEF076352AA47FDB005700E5 /* QuickSlotManagerViewController.swift */, ); path = Controller; sourceTree = ""; @@ -753,6 +762,17 @@ path = Model; sourceTree = ""; }; + DEF076382AA480B7005700E5 /* Table */ = { + isa = PBXGroup; + children = ( + DEF076392AA480C6005700E5 /* QuickSlotTableView.swift */, + DEF0763C2AA48125005700E5 /* QuickSlotCell.swift */, + DEF076422AA48AF0005700E5 /* QuickSlotCellDeleteButton.swift */, + DEF0763F2AA4845E005700E5 /* QuickSlotCellManager.swift */, + ); + path = Table; + sourceTree = ""; + }; DEF749302A85655E00D987C8 /* Extensions */ = { isa = PBXGroup; children = ( @@ -840,7 +860,6 @@ DE7F9D462A9B7A4700F8ACAE /* QuickSlotButtonViewItem.xib in Resources */, DEB862D92A852C4500278FCD /* brewInGoinfre.sh in Resources */, DE62BE5A2A9BA31700D97E06 /* QuickSlotButtonCollectionViewController.xib in Resources */, - D65C5C7C2AA195AB00BD291A /* prefsHelper.app in Resources */, DE018BE02A509B0600FF0AA3 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -862,6 +881,7 @@ DE874F542A591F1400FC3B77 /* PreferencesView.swift in Sources */, DE98E83B2A98DB6000F8744A /* RotateImage+NSImage.swift in Sources */, DE0A91982A8F977F00D1D6F1 /* ToolbarViewController.swift in Sources */, + DEF076432AA48AF0005700E5 /* QuickSlotCellDeleteButton.swift in Sources */, DE9DA8142A97F20E001C0D3B /* ButtonGroupViewController.swift in Sources */, DE4408082A9240300091937A /* BoxFunctionButtonView.swift in Sources */, DE3FF3742A978AB8009C88EF /* WindowMaximizeButton.swift in Sources */, @@ -883,6 +903,8 @@ DE77BBF02A9E38C6006CC98B /* GetUserProfile.swift in Sources */, DEF749322A85657600D987C8 /* NSScreen.swift in Sources */, DE018BF02A509B2F00FF0AA3 /* MenubarViewController.swift in Sources */, + DEF0763A2AA480C6005700E5 /* QuickSlotTableView.swift in Sources */, + DEF076362AA47FDB005700E5 /* QuickSlotManagerViewController.swift in Sources */, DE94571C2A9EFB7800B0B768 /* Associated+NSButton.swift in Sources */, DE6332E42A9BB8F800DCFAF6 /* QuickSlotButtonCollectionViewController.swift in Sources */, DE9457062A9E69C100B0B768 /* ScriptNameLabel.swift in Sources */, @@ -929,6 +951,7 @@ DE9457572AA0C5C600B0B768 /* IconSettingView.swift in Sources */, DE0A91672A8E6CA700D1D6F1 /* WebViewManager.swift in Sources */, DE77BBF32A9E38DC006CC98B /* UserManager.swift in Sources */, + DEF076402AA4845E005700E5 /* QuickSlotCellManager.swift in Sources */, DE94570C2A9E69EB00B0B768 /* ScriptExcuteButton.swift in Sources */, DE9457162A9E6D3000B0B768 /* ScriptQuickSlotButton.swift in Sources */, DE97CA7F2A9A73A9001073DE /* QuickSlotUI.swift in Sources */, @@ -936,6 +959,7 @@ DE018BED2A509B2600FF0AA3 /* URLModel.swift in Sources */, DE97CA692A9A6364001073DE /* PixelConversion+CGFloat.swift in Sources */, DE7886282A9D186700FE21DD /* ScriptsViewController.swift in Sources */, + DEF0763D2AA48125005700E5 /* QuickSlotCell.swift in Sources */, DE4408052A923EC00091937A /* QuitButtonView.swift in Sources */, DE0A918A2A8F88A900D1D6F1 /* GoForwardInToolbar.swift in Sources */, DE1F1A1E2A8B50C500A88DD8 /* BoxButtonViewGroup.swift in Sources */, diff --git a/Box42/Main/BoxBaseContainerViewController.swift b/Box42/Main/BoxBaseContainerViewController.swift index e217f74..b2cc181 100644 --- a/Box42/Main/BoxBaseContainerViewController.swift +++ b/Box42/Main/BoxBaseContainerViewController.swift @@ -25,7 +25,7 @@ class BoxBaseContainerViewController: NSViewController { weak var menubarVCDelegate: MenubarViewControllerDelegate? // extension - + var quickSlotManagerVC: QuickSlotManagerViewController = QuickSlotManagerViewController() var quickSlotButtonCollectionVC: QuickSlotButtonCollectionViewController = QuickSlotButtonCollectionViewController() @@ -47,6 +47,8 @@ class BoxBaseContainerViewController: NSViewController { self.view.layer?.backgroundColor = NSColor(hex: "#E7E7E7").cgColor NotificationCenter.default.addObserver(self, selector: #selector(handleButtonTapped), name: .collectionButtonTapped, object: nil) + + NotificationCenter.default.addObserver(self, selector: #selector(headerTappedQuickSlotManagerHandle), name: .collectionHeaderTapped, object: nil) } func BoxButtonViewGroupInit() -> BoxButtonViewGroup { @@ -210,3 +212,15 @@ extension BoxBaseContainerViewController { } } } + +extension BoxBaseContainerViewController { + @objc func headerTappedQuickSlotManagerHandle(notification: NSNotification) { + print("QuickSlotManager") + contentGroup.removeAllSubviews() + print(quickSlotManagerVC) + contentGroup.addSubview(quickSlotManagerVC.view) + quickSlotManagerVC.view.snp.makeConstraints { make in + make.top.bottom.left.right.equalToSuperview() + } + } +} diff --git a/Box42/QuickSlot/Controller/QuickSlotManagerViewController.swift b/Box42/QuickSlot/Controller/QuickSlotManagerViewController.swift new file mode 100644 index 0000000..18a9f47 --- /dev/null +++ b/Box42/QuickSlot/Controller/QuickSlotManagerViewController.swift @@ -0,0 +1,37 @@ +// +// QuickSlotManagerViewController.swift +// Box42 +// +// Created by Chanhee Kim on 9/3/23. +// + +import AppKit + +class QuickSlotManagerViewController: NSViewController { + var quickSlotManagerTableView: QuickSlotTableView? + var viewModel: QuickSlotViewModel? = QuickSlotViewModel.shared { + didSet { + quickSlotManagerTableView?.viewModel = viewModel + } + } + + override func loadView() { + self.view = NSView() + + quickSlotManagerTableView = QuickSlotTableView(frame: .zero) + quickSlotManagerTableView?.setup() + quickSlotManagerTableView?.viewModel = viewModel + + let scrollView = NSScrollView() + scrollView.documentView = quickSlotManagerTableView + self.view.addSubview(scrollView) + + scrollView.snp.makeConstraints({ make in + make.edges.equalToSuperview() + }) + + quickSlotManagerTableView?.snp.makeConstraints({ make in + make.edges.equalToSuperview() + }) + } +} diff --git a/Box42/QuickSlot/Controller/QuickSlotViewController.swift b/Box42/QuickSlot/Controller/QuickSlotViewController.swift index e60f49a..5a659d9 100644 --- a/Box42/QuickSlot/Controller/QuickSlotViewController.swift +++ b/Box42/QuickSlot/Controller/QuickSlotViewController.swift @@ -21,7 +21,7 @@ class QuickSlotViewController: NSViewController { } func headerAction() { - print("quick slot header") + NotificationCenter.default.post(name: .collectionHeaderTapped, object: nil) } @objc func handleButtonTapped(notification: NSNotification) { diff --git a/Box42/QuickSlot/Model/QuickSlotButtonModel.swift b/Box42/QuickSlot/Model/QuickSlotButtonModel.swift index 2665c32..0f3b50f 100644 --- a/Box42/QuickSlot/Model/QuickSlotButtonModel.swift +++ b/Box42/QuickSlot/Model/QuickSlotButtonModel.swift @@ -18,8 +18,8 @@ struct QuickSlotButtonModel: Codable { var path: String? var type: String? - init(id: UUID = UUID(), title: String = "Default", path: String? = "none", type: String = "sh") { - self.scriptUuid = id + init(scriptUuid: UUID? = UUID(), title: String = "Default", path: String? = "none", type: String = "sh") { + self.scriptUuid = scriptUuid ?? UUID() self.title = title self.path = path self.type = type diff --git a/Box42/QuickSlot/View/ButtonCollectionView/QuickSlotButtonCollectionViewController.swift b/Box42/QuickSlot/View/ButtonCollectionView/QuickSlotButtonCollectionViewController.swift index 5e1c9f1..9b5ebfc 100644 --- a/Box42/QuickSlot/View/ButtonCollectionView/QuickSlotButtonCollectionViewController.swift +++ b/Box42/QuickSlot/View/ButtonCollectionView/QuickSlotButtonCollectionViewController.swift @@ -88,8 +88,13 @@ extension QuickSlotButtonCollectionViewController: NSCollectionViewDelegate, NSC func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem { let item = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "QuickSlotButtonViewItem"), for: indexPath) - + print("current item index>", indexPath.item) if let customItem = item as? QuickSlotButtonViewItem { + + for subview in customItem.view.subviews { + subview.removeFromSuperview() + } + if customItem.view.subviews.isEmpty { let btn = QuickSlotItemButton(indexPath.item) btn.action = #selector(collectionButtonTapped) @@ -123,4 +128,5 @@ extension QuickSlotButtonCollectionViewController { // MARK: - Notification Name collectionButtonTapped extension Notification.Name { static let collectionButtonTapped = Notification.Name("collectionButtonTapped") + static let collectionHeaderTapped = Notification.Name("collectionHeaderTapped") } diff --git a/Box42/QuickSlot/View/ButtonCollectionView/Vertical Item/QuickSlotItemButton.swift b/Box42/QuickSlot/View/ButtonCollectionView/Vertical Item/QuickSlotItemButton.swift index 6d0f349..8fdaf8c 100644 --- a/Box42/QuickSlot/View/ButtonCollectionView/Vertical Item/QuickSlotItemButton.swift +++ b/Box42/QuickSlot/View/ButtonCollectionView/Vertical Item/QuickSlotItemButton.swift @@ -22,6 +22,10 @@ class QuickSlotItemButton: NSButton { self.image = NSImage(imageLiteralResourceName: "document-text") } else if buttonModel.type == "pref" { self.image = NSImage(imageLiteralResourceName: "setting") + } else if buttonModel.type == "default-sh" { + self.image = NSImage(imageLiteralResourceName: "document-text") + } else if buttonModel.type == "default-pref" { + self.image = NSImage(imageLiteralResourceName: "setting") } self.isBordered = false self.wantsLayer = true diff --git a/Box42/QuickSlot/View/QuickSlotGroupView.swift b/Box42/QuickSlot/View/QuickSlotGroupView.swift index d6238eb..e436c86 100644 --- a/Box42/QuickSlot/View/QuickSlotGroupView.swift +++ b/Box42/QuickSlot/View/QuickSlotGroupView.swift @@ -11,7 +11,7 @@ import SnapKit class QuickSlotGroupView: NSView { lazy var divider: NSBox = Divider(completion: { [weak self] in self?.dividerAction?() }) - lazy var headerView: QuickSlotHeaderView = QuickSlotHeaderView(image: NSImage(imageLiteralResourceName: "Star"), completion: { [weak self] in self?.headerAction?() }) + lazy var headerView: QuickSlotHeaderView = QuickSlotHeaderView(image: NSImage(imageLiteralResourceName: "star"), completion: { [weak self] in self?.headerAction?() }) lazy var buttonCollectionView: QuickSlotButtonCollectionViewController = QuickSlotButtonCollectionViewController() var dividerAction: (() -> Void)? diff --git a/Box42/QuickSlot/View/QuickSlotHeaderView.swift b/Box42/QuickSlot/View/QuickSlotHeaderView.swift index 3638225..341bc48 100644 --- a/Box42/QuickSlot/View/QuickSlotHeaderView.swift +++ b/Box42/QuickSlot/View/QuickSlotHeaderView.swift @@ -11,37 +11,51 @@ import SnapKit class QuickSlotHeaderView: NSView { private var callback: (() -> Void)? - private var QuickSlotHeaderButton: NSButton! - private var QuickSlotHeaderLabel: NSTextField! + private var quickSlotHeaderButton: NSButton! + private var quickSlotHeaderLabel: NSTextField! + private var quickSlotManageButton: NSButton! init(image: NSImage, completion: @escaping () -> Void) { super.init(frame: .zero) - QuickSlotHeaderButton = NSButton(image: image, target: self, action: #selector(btnAction)) - QuickSlotHeaderButton.isBordered = false - QuickSlotHeaderButton.wantsLayer = true - QuickSlotHeaderButton.layer?.backgroundColor = NSColor.clear.cgColor + quickSlotHeaderButton = NSButton(image: image, target: self, action: #selector(btnAction)) + quickSlotHeaderButton.isBordered = false + quickSlotHeaderButton.wantsLayer = true + quickSlotHeaderButton.layer?.backgroundColor = NSColor.clear.cgColor - self.addSubview(QuickSlotHeaderButton) + self.addSubview(quickSlotHeaderButton) - QuickSlotHeaderLabel = NSTextField(labelWithString: "Quick Slot") - QuickSlotHeaderLabel.font = NSFont(name: "Inter", size: QuickSlotUI.size.font) - QuickSlotHeaderLabel.textColor = NSColor(hex: "#696969") - QuickSlotHeaderLabel.backgroundColor = NSColor.clear - QuickSlotHeaderLabel.isBordered = false + quickSlotHeaderLabel = NSTextField(labelWithString: "Quick Slot") + quickSlotHeaderLabel.font = NSFont(name: "Inter", size: QuickSlotUI.size.font) + quickSlotHeaderLabel.textColor = NSColor(hex: "#696969") + quickSlotHeaderLabel.backgroundColor = NSColor.clear + quickSlotHeaderLabel.isBordered = false - self.addSubview(QuickSlotHeaderLabel) + self.addSubview(quickSlotHeaderLabel) - QuickSlotHeaderButton.snp.makeConstraints { make in + quickSlotManageButton = NSButton(image: NSImage(imageLiteralResourceName: "add"), target: self, action: #selector(btnAction)) + quickSlotManageButton.isBordered = false + quickSlotManageButton.wantsLayer = true + quickSlotManageButton.layer?.backgroundColor = NSColor.clear.cgColor + + self.addSubview(quickSlotManageButton) + + quickSlotHeaderButton.snp.makeConstraints { make in make.left.equalToSuperview() make.top.equalToSuperview().offset(13) } - QuickSlotHeaderLabel.snp.makeConstraints { make in - make.left.equalTo(QuickSlotHeaderButton.snp.right).offset(4) - make.bottom.equalTo(QuickSlotHeaderButton.snp.bottom) + quickSlotHeaderLabel.snp.makeConstraints { make in + make.left.equalTo(quickSlotHeaderButton.snp.right).offset(4) + make.bottom.equalTo(quickSlotHeaderButton.snp.bottom) + } + + quickSlotManageButton.snp.makeConstraints { make in + make.right.equalToSuperview() + make.bottom.equalTo(quickSlotHeaderLabel.snp.bottom) } + self.callback = completion } diff --git a/Box42/QuickSlot/View/Table/QuickSlotCell.swift b/Box42/QuickSlot/View/Table/QuickSlotCell.swift new file mode 100644 index 0000000..89e6deb --- /dev/null +++ b/Box42/QuickSlot/View/Table/QuickSlotCell.swift @@ -0,0 +1,101 @@ +// +// QuickSlotCell.swift +// Box42 +// +// Created by Chanhee Kim on 9/3/23. +// + +import AppKit +import SnapKit + +class QuickSlotCell: NSTableCellView { + var imageButton: NSButton = NSButton() + var titleLabel: NSTextField = NSTextField() + var pathLabel: NSTextField = NSTextField() + var typeLabel: NSTextField = NSTextField() + var deleteButton: QuickSlotCellDeleteButton = QuickSlotCellDeleteButton() + + var viewModel: QuickSlotViewModel? + var qsButton: QuickSlotButtonModel? + + override init(frame frameRect: NSRect) { + super.init(frame: frameRect) + setupUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupUI() { + addSubview(imageButton) + addSubview(titleLabel) + addSubview(pathLabel) + addSubview(typeLabel) + addSubview(deleteButton) + + imageButton.snp.makeConstraints { make in + make.left.equalToSuperview().offset(8) + make.top.equalToSuperview().offset(8) + make.bottom.equalToSuperview().offset(-8) + make.width.equalTo(imageButton.snp.height).multipliedBy(1) + } + + deleteButton.snp.makeConstraints { make in + make.right.equalToSuperview().offset(-8) + make.centerY.equalToSuperview() + make.height.equalToSuperview() + } + + titleLabel.snp.makeConstraints { make in + make.left.equalTo(imageButton.snp.right).offset(8) + make.right.equalTo(deleteButton.snp.left).offset(-8) + make.top.equalTo(imageButton) + } + + pathLabel.snp.makeConstraints { make in + make.left.equalTo(titleLabel) + make.right.equalTo(deleteButton.snp.left).offset(-8) + make.top.equalTo(titleLabel.snp.bottom).offset(4) + } + + typeLabel.snp.makeConstraints { make in + make.left.equalTo(pathLabel) + make.right.equalTo(deleteButton.snp.left).offset(-8) + make.top.equalTo(pathLabel.snp.bottom).offset(4) + } + } + + func configure(with qsItem: QuickSlotButtonModel, viewModel: QuickSlotViewModel?) { + self.qsButton = qsItem + self.viewModel = viewModel + titleLabel.stringValue = qsItem.title + pathLabel.stringValue = qsItem.path ?? "none" + + if qsItem.title == "CleanCache" { + imageButton.image = NSImage(imageLiteralResourceName: "trash") + } else if qsItem.type == "sh" { + imageButton.image = NSImage(imageLiteralResourceName: "document-text") + } else if qsItem.type == "pref" { + imageButton.image = NSImage(imageLiteralResourceName: "setting") + } else if qsItem.type == "default-sh" { + imageButton.image = NSImage(imageLiteralResourceName: "document-text") + } else if qsItem.type == "default-pref" { + imageButton.image = NSImage(imageLiteralResourceName: "setting") + } + imageButton.isBordered = false + + + deleteButton.target = self + deleteButton.action = #selector(deleteButtonClicked) + } + + @objc func deleteButtonClicked() { + // if let id = qsButton?.scriptUuid { + // viewModel?.removeButton(id) + // } + if let path = qsButton?.path { + viewModel?.removeButton(path) + } + } +} diff --git a/Box42/QuickSlot/View/Table/QuickSlotCellDeleteButton.swift b/Box42/QuickSlot/View/Table/QuickSlotCellDeleteButton.swift new file mode 100644 index 0000000..9db5098 --- /dev/null +++ b/Box42/QuickSlot/View/Table/QuickSlotCellDeleteButton.swift @@ -0,0 +1,76 @@ +// +// QuickSlotCellDeleteButton.swift +// Box42 +// +// Created by Chanhee Kim on 9/3/23. +// + +import AppKit + +class QuickSlotCellDeleteButton: NSButton { + + init() { + super.init(frame: NSRect(x: 0, y: 0, width: 53, height: 100)) + + self.title = "퀵슬롯에서\n제거" + self.isBordered = false + self.wantsLayer = true + self.layer?.cornerRadius = WindowButtonUI.size.cornerRadius + self.layer?.backgroundColor = WindowButtonUI.color.opacityWhite + } + + override func layout() { + super.layout() + + for trackingArea in self.trackingAreas { + self.removeTrackingArea(trackingArea) + } + + let trackingArea = NSTrackingArea(rect: self.bounds, options: [.mouseEnteredAndExited, .activeAlways], owner: self, userInfo: nil) + self.addTrackingArea(trackingArea) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func mouseEntered(with event: NSEvent) { + super.mouseEntered(with: event) + + let bgColorAnimation = CABasicAnimation(keyPath: "backgroundColor") + bgColorAnimation.fromValue = WindowButtonUI.color.opacityWhite + bgColorAnimation.toValue = WindowButtonUI.color.close + bgColorAnimation.duration = WindowButtonUI.animation.duration + + let cornerAnimation = CABasicAnimation(keyPath: "cornerRadius") + cornerAnimation.fromValue = WindowButtonUI.size.cornerRadius + cornerAnimation.toValue = WindowButtonUI.size.cornerRadius / 2 + cornerAnimation.duration = WindowButtonUI.animation.duration + + self.layer?.add(bgColorAnimation, forKey: "backgroundColorAnimation") + self.layer?.add(cornerAnimation, forKey: "cornerRadiusAnimation") + + self.layer?.backgroundColor = WindowButtonUI.color.close + self.layer?.cornerRadius = WindowButtonUI.size.cornerRadius / 2 + } + + override func mouseExited(with event: NSEvent) { + super.mouseExited(with: event) + + let bgColorAnimation = CABasicAnimation(keyPath: "backgroundColor") + bgColorAnimation.fromValue = WindowButtonUI.color.close + bgColorAnimation.toValue = WindowButtonUI.color.opacityWhite + bgColorAnimation.duration = WindowButtonUI.animation.duration + + let cornerAnimation = CABasicAnimation(keyPath: "cornerRadius") + cornerAnimation.fromValue = WindowButtonUI.size.cornerRadius / 2 + cornerAnimation.toValue = WindowButtonUI.size.cornerRadius + cornerAnimation.duration = WindowButtonUI.animation.duration + + self.layer?.add(bgColorAnimation, forKey: "backgroundColorAnimation") + self.layer?.add(cornerAnimation, forKey: "cornerRadiusAnimation") + + self.layer?.backgroundColor = WindowButtonUI.color.opacityWhite + self.layer?.cornerRadius = WindowButtonUI.size.cornerRadius + } +} diff --git a/Box42/QuickSlot/View/Table/QuickSlotCellManager.swift b/Box42/QuickSlot/View/Table/QuickSlotCellManager.swift new file mode 100644 index 0000000..29215c7 --- /dev/null +++ b/Box42/QuickSlot/View/Table/QuickSlotCellManager.swift @@ -0,0 +1,109 @@ +// +// QuickSlotCellManager.swift +// Box42 +// +// Created by Chanhee Kim on 9/3/23. +// + +import AppKit +import SnapKit + +// MARK: - 다음 버전에 추가 예정 +class QuickSlotCellManager: NSTableCellView { + var nameLabel: NSTextField = NSTextField() + var descriptionLabel: NSTextField = NSTextField() + var excuteButton: ScriptExcuteButton = ScriptExcuteButton() + var deleteButton: ScriptDeleteButton = ScriptDeleteButton() + var quickSlotButton: ScriptQuickSlotButton = ScriptQuickSlotButton() + + var viewModel: ScriptViewModel? + var script: Script? + + override init(frame frameRect: NSRect) { + super.init(frame: frameRect) + setupUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupUI() { + addSubview(nameLabel) + addSubview(descriptionLabel) + addSubview(quickSlotButton) + addSubview(excuteButton) + addSubview(deleteButton) + + nameLabel.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.left.equalToSuperview().offset(16) + make.width.lessThanOrEqualTo(200).priority(.high) // 최대 너비와 우선순위 설정 + } + + deleteButton.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.right.equalToSuperview().offset(-16) + make.width.equalTo(53) + make.height.equalTo(40) + } + + excuteButton.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.right.equalTo(deleteButton.snp.left).offset(-8) + make.width.equalTo(70) + make.height.equalTo(40) + } + + quickSlotButton.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.right.equalTo(excuteButton.snp.left).offset(-8) + make.width.equalTo(53) + make.height.equalTo(40) + } + + descriptionLabel.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.left.equalTo(nameLabel.snp.right).offset(8) + make.right.lessThanOrEqualTo(quickSlotButton.snp.left).offset(-8) + make.width.greaterThanOrEqualTo(100).priority(.low) // 최소 너비와 낮은 우선순위 설정 + } + } + + + + func configure(with script: Script, viewModel: ScriptViewModel?) { + self.script = script + self.viewModel = viewModel + nameLabel.stringValue = script.name + descriptionLabel.stringValue = script.description ?? "description" + + deleteButton.target = self + deleteButton.action = #selector(deleteButtonClicked) + + excuteButton.target = self + excuteButton.action = #selector(excuteButtonClicked) + + quickSlotButton.target = self + quickSlotButton.action = #selector(quickSlotButtonclicked) + + } + + @objc func deleteButtonClicked() { + if let id = script?.scriptUuid { + viewModel?.deleteScript(id: id) + } + } + + @objc func excuteButtonClicked() { + if let path = script?.path { + viewModel?.excuteScript(path: path) + } + } + + @objc func quickSlotButtonclicked() { + if let id = script?.scriptUuid { + viewModel?.quickSlotScript(id: id) + } + } +} diff --git a/Box42/QuickSlot/View/Table/QuickSlotTableView.swift b/Box42/QuickSlot/View/Table/QuickSlotTableView.swift new file mode 100644 index 0000000..7fbf7b5 --- /dev/null +++ b/Box42/QuickSlot/View/Table/QuickSlotTableView.swift @@ -0,0 +1,78 @@ +// +// QuickSlotTableView.swift +// Box42 +// +// Created by Chanhee Kim on 9/3/23. +// + +import AppKit +import SnapKit +import Combine + +class QuickSlotTableView: NSTableView { + var viewModel: QuickSlotViewModel? { + didSet { + print("ViewModel has been set.") + setupBindings() + } + } + + var cancellables: Set = [] + + private func setupBindings() { + print("Setting up QuickSlotTableView...") // 디버깅 로그 + viewModel?.$buttons.sink(receiveValue: { [weak self] newScripts in + print("Received new QuickSlotTableViewModel: \(newScripts)") // 디버깅 로그 + DispatchQueue.main.async { + self?.reloadData() + } + }).store(in: &cancellables) + } + + func setup() { + self.delegate = self + self.dataSource = self + + let column1 = NSTableColumn(identifier: NSUserInterfaceItemIdentifier("QuickSlots")) + column1.width = 100.0 + column1.title = "QuickSlot" + self.addTableColumn(column1) + } +} + +extension QuickSlotTableView: NSTableViewDelegate, NSTableViewDataSource { + func getCellForRow(at row: Int) -> NSView { + guard let viewModel = viewModel else { + return NSView() + } + + if row < viewModel.buttons.count { + return getQuickSlotCell(for: viewModel.buttons[row], viewModel: viewModel) + } else { + return getQuickSlotCellManager() + } + } + + private func getQuickSlotCell(for quickSlotItem: QuickSlotButtonModel, viewModel: QuickSlotViewModel) -> QuickSlotCell { + let cell = QuickSlotCell(frame: .zero) + cell.configure(with: quickSlotItem, viewModel: viewModel) + return cell + } + + private func getQuickSlotCellManager() -> QuickSlotCellManager { + let quickSlotCellManger = QuickSlotCellManager(frame: .zero) + return quickSlotCellManger + } + + func numberOfRows(in tableView: NSTableView) -> Int { + return (viewModel?.buttons.count ?? 0 ) // + 1 + } + + func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { + getCellForRow(at: row) + } + + func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat { + return 200 + } +} diff --git a/Box42/QuickSlot/ViewModel/QuickSlotViewModel.swift b/Box42/QuickSlot/ViewModel/QuickSlotViewModel.swift index ca43f68..351a562 100644 --- a/Box42/QuickSlot/ViewModel/QuickSlotViewModel.swift +++ b/Box42/QuickSlot/ViewModel/QuickSlotViewModel.swift @@ -13,14 +13,20 @@ class QuickSlotViewModel { @Published var buttons: [QuickSlotButtonModel] = [] private init() { - let button1 = QuickSlotButtonModel(id: UUID(uuidString: "37a56076-e72c-4efe-ba7f-de0effe7f4c3")!, + let button1 = QuickSlotButtonModel(scriptUuid: UUID(uuidString: "37a56076-e72c-4efe-ba7f-de0effe7f4c3")!, title: QuickSlotUI.title.clean, path: Bundle.main.path(forResource: "cleanCache", ofType: "sh"), type: "sh" ) - let button2 = QuickSlotButtonModel(title: QuickSlotUI.title.preferences, type: "pref") - let button3 = QuickSlotButtonModel(title: QuickSlotUI.title.scripts) - let button4 = QuickSlotButtonModel(title: QuickSlotUI.title.user, type: "pref") + let button2 = QuickSlotButtonModel(title: QuickSlotUI.title.preferences, + path: "preferences", + type: "default-pref") + let button3 = QuickSlotButtonModel(title: QuickSlotUI.title.scripts, + path: "scripts", + type: "default-sh") + let button4 = QuickSlotButtonModel(title: QuickSlotUI.title.user, + path: "user", + type: "default-pref") buttons = [button1, button2, button3, button4] } @@ -45,10 +51,39 @@ class QuickSlotViewModel { } func removeButton(_ id: UUID) { - buttons.removeAll { $0.scriptUuid == id } - updateMeQuickSlot() + if let index = buttons.firstIndex(where: { $0.scriptUuid == id }) { + let buttonToRemove = buttons[index] + if let type = buttonToRemove.type, !type.hasPrefix("default") { + buttons.remove(at: index) + updateMeQuickSlot() + } + } } + func removeButton(_ path: String) { + print("1. Attempting to remove button with path: \(path)") + print("2. Current buttons: \(buttons)") + if let index = buttons.firstIndex(where: { $0.path == path }) { + print("3. Found button at index: \(index)") + let buttonToRemove = buttons[index] + print("4. Button to remove: \(buttonToRemove)") + if let type = buttonToRemove.type { + print("5. Button type: \(type)") + if !type.hasPrefix("default") { + print("6. Removing button...") + buttons.remove(at: index) + updateMeQuickSlot() + } else { + print("Button type starts with 'default'. Skipping removal.") + } + } else { + print("Button type is nil. Skipping removal.") + } + } else { + print("Button not found.") + } + } + func updateButton(id: UUID, newTitle: String) { if let index = buttons.firstIndex(where: { $0.scriptUuid == id }) { buttons[index].title = newTitle @@ -67,3 +102,4 @@ class QuickSlotViewModel { } } } + diff --git a/Box42/Resources/Assets.xcassets/uibuttons/add.imageset/Contents.json b/Box42/Resources/Assets.xcassets/uibuttons/add.imageset/Contents.json new file mode 100644 index 0000000..52e243f --- /dev/null +++ b/Box42/Resources/Assets.xcassets/uibuttons/add.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "add.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Box42/Resources/Assets.xcassets/uibuttons/add.imageset/add.png b/Box42/Resources/Assets.xcassets/uibuttons/add.imageset/add.png new file mode 100644 index 0000000..12a1110 Binary files /dev/null and b/Box42/Resources/Assets.xcassets/uibuttons/add.imageset/add.png differ diff --git a/Box42/Resources/Assets.xcassets/uibuttons/add.png b/Box42/Resources/Assets.xcassets/uibuttons/add.png new file mode 100644 index 0000000..12a1110 Binary files /dev/null and b/Box42/Resources/Assets.xcassets/uibuttons/add.png differ diff --git a/Box42/Scripts/Model/Scripts.swift b/Box42/Scripts/Model/Scripts.swift index d22fc03..313511f 100644 --- a/Box42/Scripts/Model/Scripts.swift +++ b/Box42/Scripts/Model/Scripts.swift @@ -19,8 +19,8 @@ struct Script: Codable { var savedId: Int? var userUuid: String? - init(id: UUID?, name: String, description: String?, path: String, savedId: Int?, userUuid: String?) { - self.scriptUuid = id + init(scriptUuid: UUID?, name: String, description: String?, path: String, savedId: Int?, userUuid: String?) { + self.scriptUuid = scriptUuid self.name = name self.description = description self.path = path diff --git a/Box42/Scripts/View/Table/ScriptCell.swift b/Box42/Scripts/View/Table/ScriptCell.swift index c8be376..251e194 100644 --- a/Box42/Scripts/View/Table/ScriptCell.swift +++ b/Box42/Scripts/View/Table/ScriptCell.swift @@ -95,27 +95,28 @@ class ScriptCell: NSTableCellView { } @objc func excuteButtonClicked() { - if let id = script?.scriptUuid { - viewModel?.excuteScript(id: id) + if let path = script?.path { + viewModel?.excuteScript(path: path) } } @objc func quickSlotButtonclicked() { - guard let id = script?.scriptUuid else { + guard let path = script?.path else { return } - let alreadyExists = QuickSlotViewModel.shared.buttons.contains { $0.scriptUuid == id } + let alreadyExists = QuickSlotViewModel.shared.buttons.contains { $0.path == path } if alreadyExists { - QuickSlotViewModel.shared.removeButton(id) + QuickSlotViewModel.shared.removeButton(path) quickSlotButton.title = "퀵슬롯" } else { if QuickSlotViewModel.shared.buttons.count > 7 { return } else { quickSlotButton.title = "저장됨" - viewModel?.quickSlotScript(id: id) +// viewModel?.quickSlotScript(id: id) + viewModel?.quickSlotScript(path: path) } } } diff --git a/Box42/Scripts/View/Table/ScriptCellManager.swift b/Box42/Scripts/View/Table/ScriptCellManager.swift index a7567ae..1dfc952 100644 --- a/Box42/Scripts/View/Table/ScriptCellManager.swift +++ b/Box42/Scripts/View/Table/ScriptCellManager.swift @@ -96,8 +96,11 @@ class ScriptCellManager: NSTableCellView { } @objc func excuteButtonClicked() { - if let id = script?.scriptUuid { - viewModel?.excuteScript(id: id) + // if let id = script?.scriptUuid { + // viewModel?.excuteScript(id: id) + // } + if let path = script?.path { + viewModel?.excuteScript(path: path) } } diff --git a/Box42/Scripts/ViewModel/ScriptsViewModel.swift b/Box42/Scripts/ViewModel/ScriptsViewModel.swift index 9abc40e..a2f2a51 100644 --- a/Box42/Scripts/ViewModel/ScriptsViewModel.swift +++ b/Box42/Scripts/ViewModel/ScriptsViewModel.swift @@ -15,7 +15,7 @@ class ScriptViewModel: NSObject { private override init() { self.scripts = [ - Script(id: UUID(uuidString: "37a56076-e72c-4efe-ba7f-de0effe7f4c3"), + Script(scriptUuid: UUID(uuidString: "37a56076-e72c-4efe-ba7f-de0effe7f4c3"), name: "CleanCache", description: "Cleaning cache", path: Bundle.main.path(forResource: "cleanCache", ofType: "sh") ?? "", savedId: -1 , userUuid: nil), @@ -39,19 +39,24 @@ class ScriptViewModel: NSObject { } // Create - func addScript(id: UUID = UUID(), name: String, description: String, path: String, savedId: Int, userUuid: String) { - let newScript = Script(id: UUID(), name: name, description: description, path: path, savedId: savedId, userUuid: userUuid) + func addScript(scriptUuid: UUID?, name: String, description: String?, path: String, savedId: Int?, userUuid: String?) { + let newScript = Script(scriptUuid: scriptUuid, name: name, description: description, path: path, savedId: savedId, userUuid: userUuid) scripts.append(newScript) } + // // Read + // func excuteScript(id: UUID) { + // if let index = scripts.firstIndex(where: { $0.scriptUuid == id }) { + // // MARK: - 파일스크립트 매니저에서 권한을 얻은 실행으로 실행합니다. + // ScriptsFileManager.downloadFile(from: "https://42box.kr/" + scripts[index].path) + // } + // } + // Read - func excuteScript(id: UUID) { - if let index = scripts.firstIndex(where: { $0.scriptUuid == id }) { - // ExecuteScripts.executeShellScript(path: scripts[index].name) + func excuteScript(path: String) { + if scripts.firstIndex(where: { $0.path == path }) != nil { // MARK: - 파일스크립트 매니저에서 권한을 얻은 실행으로 실행합니다. - ScriptsFileManager.downloadFile(from: "https://42box.kr/" + scripts[index].path) - - // SecurityScopedResourceAccess.accessResourceExecuteShellScript(scriptPath: scripts[index].path) + ScriptsFileManager.downloadFile(from: "https://42box.kr/" + path) } } @@ -64,13 +69,31 @@ class ScriptViewModel: NSObject { } // Delete - func deleteScript(id: UUID) { + func deleteScript(id: UUID?) { if let script = scripts.first(where: { $0.scriptUuid == id }) { API.deleteUserMeScripts(WebViewManager.shared.getCookieWebKit, savedId: script.savedId!) { result in switch result { case .success(_): self.scripts.removeAll(where: { $0.scriptUuid == id }) - QuickSlotViewModel.shared.removeButton(id) + if let scriptUuid = id { + QuickSlotViewModel.shared.removeButton(scriptUuid) + } + + case .failure(let error): + print("Failed to delete script: \(error)") + } + } + } + } + + // Delete + func deleteScript(path: String) { + if let script = scripts.first(where: { $0.path == path }) { + API.deleteUserMeScripts(WebViewManager.shared.getCookieWebKit, savedId: script.savedId!) { result in + switch result { + case .success(_): + self.scripts.removeAll(where: { $0.path == path }) + QuickSlotViewModel.shared.removeButton(path) case .failure(let error): print("Failed to delete script: \(error)") @@ -92,7 +115,15 @@ class ScriptViewModel: NSObject { // 스크립트안에서 해당하는 스크립트를 찾아서 quickslotVM에 추가 func quickSlotScript(id: UUID) { if let index = scripts.firstIndex(where: { $0.scriptUuid == id }) { - let button = QuickSlotButtonModel(id: id, title: scripts[index].name, path: scripts[index].path) + let button = QuickSlotButtonModel(scriptUuid: id, title: scripts[index].name, path: scripts[index].path) + QuickSlotViewModel.shared.addButton(button) + } + } + + // 스크립트안에서 해당하는 스크립트를 찾아서 quickslotVM에 추가 + func quickSlotScript(path: String) { + if let index = scripts.firstIndex(where: { $0.path == path }) { + let button = QuickSlotButtonModel(scriptUuid: scripts[index].scriptUuid, title: scripts[index].name, path: scripts[index].path) QuickSlotViewModel.shared.addButton(button) } } diff --git a/Box42/Shared/User/UserProfile.swift b/Box42/Shared/User/UserProfile.swift index fdeafcf..b786d4d 100644 --- a/Box42/Shared/User/UserProfile.swift +++ b/Box42/Shared/User/UserProfile.swift @@ -46,7 +46,7 @@ extension UserProfile { statusMessage: "hello 42Box!", profileImageUrl: "https://42box.kr/user_profile_image/a52671f9-fca9-43ad-b0c0-1c5360831cf2.png", profileImagePath: "user_profile_image/a52671f9-fca9-43ad-b0c0-1c5360831cf2.png", - quickSlotList: [ QuickSlotButtonModel(id: UUID(uuidString: "37a56076-e72c-4efe-ba7f-de0effe7f4c3")!, title: "cleanCache", path: Bundle.main.path(forResource: "cleanCache", ofType: "sh")), + quickSlotList: [ QuickSlotButtonModel(scriptUuid: UUID(uuidString: "37a56076-e72c-4efe-ba7f-de0effe7f4c3")!, title: "cleanCache", path: Bundle.main.path(forResource: "cleanCache", ofType: "sh")), ] ) } diff --git a/Box42/View/BoxContentsViewGroup.swift b/Box42/View/BoxContentsViewGroup.swift index bb48f46..df71ba7 100644 --- a/Box42/View/BoxContentsViewGroup.swift +++ b/Box42/View/BoxContentsViewGroup.swift @@ -8,106 +8,75 @@ import WebKit import SnapKit -class BoxContentsViewGroup: NSView, WKUIDelegate { - // var webVC: WebViewController? +class BoxContentsViewGroup: NSView { + var webVC: WebViewController? var preferencesVC = PreferencesViewController() var scriptsVC = ScriptsViewController() - var webView: WKWebView! +// var webView: WKWebView! static let shared = BoxContentsViewGroup() init() { super.init(frame: .zero) - // webVC = WebViewController(nibName: nil, bundle: nil) + webVC = WebViewController(nibName: nil, bundle: nil) self.wantsLayer = true self.layer?.cornerRadius = 20 self.layer?.masksToBounds = true - // self.addSubview(webVC!.view) - // webVC?.view.snp.makeConstraints { make in - // make.edges.equalTo(self) - // } - - let webConfiguration = WKWebViewConfiguration() - webView = WKWebView(frame: .zero, configuration: webConfiguration) - webView.uiDelegate = self - WebViewManager.shared.hostingWebView = webView - self.addSubview(webView) - webView.snp.makeConstraints { make in + self.addSubview(webVC!.view) + webVC?.view.snp.makeConstraints { make in make.edges.equalTo(self) } - if let url = URL(string: "https://www.42box.kr") { - let request = URLRequest(url: url) - webView.load(request) - } - - NotificationCenter.default.addObserver(self, selector: - #selector(goBack), name: - Notification.Name("goBack"), object:nil) - - NotificationCenter.default.addObserver(self, selector: - #selector(goForward), name: - Notification.Name("goForward"), object:nil) - - NotificationCenter.default.addObserver(self, selector: - #selector(reload), name: - Notification.Name("reload"), object:nil) - } - - deinit { - // view controller가 해제될 때 observer도 제거합니다. - NotificationCenter.default.removeObserver(self) - } - - @objc func goBack() { - if webView.canGoBack { - webView.goBack() - } - } - - @objc func goForward() { - if webView.canGoForward { - webView.goForward() - } - } - - @objc func reload() { - webView.reload() - } - - func webView(_ webView: WKWebView, - createWebViewWith configuration: WKWebViewConfiguration, - for navigationAction: WKNavigationAction, - windowFeatures: WKWindowFeatures) -> WKWebView? { - - if navigationAction.targetFrame == nil { - if let url = navigationAction.request.url { - if navigationAction.navigationType == .linkActivated { - webView.load(URLRequest(url: url)) - return nil - } - } - } - return nil - } - - func webView(_ webView: WKWebView, runOpenPanelWith parameters: WKOpenPanelParameters, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping ([URL]?) -> Void) { - let openPanel = NSOpenPanel() - openPanel.canChooseFiles = true - openPanel.allowsMultipleSelection = parameters.allowsMultipleSelection - openPanel.level = .popUpMenu - - openPanel.begin { (result) in - if result == .OK { - completionHandler(openPanel.urls) - } else { - completionHandler(nil) - } - } +// let webConfiguration = WKWebViewConfiguration() +// webView = WKWebView(frame: .zero, configuration: webConfiguration) +// +// webView.uiDelegate = self +// WebViewManager.shared.hostingWebView = webView +// self.addSubview(webView) +// webView.snp.makeConstraints { make in +// make.edges.equalTo(self) +// } +// +// if let url = URL(string: "https://www.42box.kr") { +// let request = URLRequest(url: url) +// webView.load(request) +// } +// +// NotificationCenter.default.addObserver(self, selector: +// #selector(goBack), name: +// Notification.Name("goBack"), object:nil) +// +// NotificationCenter.default.addObserver(self, selector: +// #selector(goForward), name: +// Notification.Name("goForward"), object:nil) +// +// NotificationCenter.default.addObserver(self, selector: +// #selector(reload), name: +// Notification.Name("reload"), object:nil) } +// +// deinit { +// // view controller가 해제될 때 observer도 제거합니다. +// NotificationCenter.default.removeObserver(self) +// } +// +// @objc func goBack() { +// if webView.canGoBack { +// webView.goBack() +// } +// } +// +// @objc func goForward() { +// if webView.canGoForward { +// webView.goForward() +// } +// } +// +// @objc func reload() { +// webView.reload() +// } - required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } diff --git a/Box42/WebView/WebView.swift b/Box42/WebView/WebView.swift index ac76554..9117d5d 100644 --- a/Box42/WebView/WebView.swift +++ b/Box42/WebView/WebView.swift @@ -7,7 +7,7 @@ import WebKit -class WebView: WKWebView, WKScriptMessageHandler { +class WebView: WKWebView, WKScriptMessageHandler, WKUIDelegate, WKNavigationDelegate { var icon = MenubarViewController() init() { @@ -32,6 +32,9 @@ class WebView: WKWebView, WKScriptMessageHandler { self.configuration.preferences.setValue(true, forKey: "allowFileAccessFromFileURLs") self.becomeFirstResponder() + + self.navigationDelegate = self + self.uiDelegate = self } required init?(coder: NSCoder) { @@ -39,6 +42,41 @@ class WebView: WKWebView, WKScriptMessageHandler { } } +extension WebView { + // front openpanel + func webView(_ webView: WKWebView, runOpenPanelWith parameters: WKOpenPanelParameters, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping ([URL]?) -> Void) { + let openPanel = NSOpenPanel() + openPanel.canChooseFiles = true + openPanel.allowsMultipleSelection = parameters.allowsMultipleSelection + openPanel.level = .popUpMenu + + openPanel.begin { (result) in + if result == .OK { + completionHandler(openPanel.urls) + } else { + completionHandler(nil) + } + } + } + + // front new tap navigation + func webView(_ webView: WKWebView, + createWebViewWith configuration: WKWebViewConfiguration, + for navigationAction: WKNavigationAction, + windowFeatures: WKWindowFeatures) -> WKWebView? { + + if navigationAction.targetFrame == nil { + if let url = navigationAction.request.url { + if navigationAction.navigationType == .linkActivated { + webView.load(URLRequest(url: url)) + return nil + } + } + } + return nil + } +} + // MARK: - Front Client 통신 extension WebView { func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { @@ -73,7 +111,12 @@ extension WebView { let decoder = JSONDecoder() let downloadString = try decoder.decode(Script.self, from: scriptJson!) - ScriptViewModel.shared.addScript(id: UUID(), name: downloadString.name, description: downloadString.description ?? "description", path: downloadString.path, savedId: Int(downloadString.savedId ?? 0), userUuid: downloadString.userUuid!) + ScriptViewModel.shared.addScript(scriptUuid: downloadString.scriptUuid, + name: downloadString.name, + description: downloadString.description, + path: downloadString.path, + savedId: downloadString.savedId, + userUuid: downloadString.userUuid) print(downloadString) @@ -92,9 +135,9 @@ extension WebView { let executeScript = try decoder.decode(Script.self, from: scriptJson!) print(String(data: scriptJson!, encoding: .utf8) ?? "Invalid JSON data") - print(executeScript) - - ScriptsFileManager.downloadFile(from: "https://42box.kr/" + executeScript.path) + DispatchQueue.global().async { + ScriptsFileManager.downloadFile(from: "https://42box.kr/" + executeScript.path) + } } catch { print("JSON decoding failed: \(error)") } @@ -110,9 +153,9 @@ extension WebView { let deleteScript = try decoder.decode(Script.self, from: scriptJson!) print(String(data: scriptJson!, encoding: .utf8) ?? "Invalid JSON data") - print(deleteScript) - - ScriptViewModel.shared.deleteScript(id: deleteScript.scriptUuid!) + DispatchQueue.global().async { + ScriptViewModel.shared.deleteScript(id: deleteScript.scriptUuid) + } } catch { print("JSON decoding failed: \(error)") } diff --git a/Box42/WebView/WebViewController.swift b/Box42/WebView/WebViewController.swift index cb4b4c9..3acc72d 100644 --- a/Box42/WebView/WebViewController.swift +++ b/Box42/WebView/WebViewController.swift @@ -61,11 +61,4 @@ class WebViewController: NSViewController { override func viewDidLoad() { super.viewDidLoad() } - - func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { - if let url = navigationAction.request.url { - webView.load(URLRequest(url: url)) - } - return nil - } }