From b7f562633e2d3ac75fd6548bcc8fedf3f0b23fd0 Mon Sep 17 00:00:00 2001 From: KIM CHAN HEE <85754295+chanhihi@users.noreply.github.com> Date: Wed, 30 Aug 2023 15:29:54 +0900 Subject: [PATCH 01/14] =?UTF-8?q?feat:=20script=EB=A5=BC=20quickslot?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EB=93=B1=EB=A1=9D=20=ED=9B=84=20=EC=8B=A4?= =?UTF-8?q?=ED=96=89=EA=B9=8C=EC=A7=80=20=ED=95=98=EA=B2=8C=20=ED=95=A9?= =?UTF-8?q?=EB=8B=88=EB=8B=A4.=20(#101)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: cell manager 추가 * refactor: 코드를 가독성있게 구성합니다. * feat: quickSlotButton Model에 path 인스턴스를 넣어 퀵슬롯에서 실행되도록 제어합니다. --- Box42.xcodeproj/project.pbxproj | 8 ++ Box42/Extensions/Associated+NSButton.swift | 21 ++++ .../BoxFunctionViewController.swift | 7 ++ .../QuickSlotScriptsLogicController.swift | 17 +-- .../Model/QuickSlotButtonModel.swift | 4 +- ...ckSlotButtonCollectionViewController.swift | 1 + Box42/Scripts/Model/Scripts.swift | 4 +- .../View/Table/ScriptCellManager.swift | 109 ++++++++++++++++++ .../Scripts/View/Table/ScriptsTableView.swift | 39 +++++-- .../Scripts/ViewModel/ScriptsViewModel.swift | 14 ++- 10 files changed, 195 insertions(+), 29 deletions(-) create mode 100644 Box42/Extensions/Associated+NSButton.swift create mode 100644 Box42/Scripts/View/Table/ScriptCellManager.swift diff --git a/Box42.xcodeproj/project.pbxproj b/Box42.xcodeproj/project.pbxproj index c4c677f..6e15b5e 100644 --- a/Box42.xcodeproj/project.pbxproj +++ b/Box42.xcodeproj/project.pbxproj @@ -90,6 +90,8 @@ DE94570C2A9E69EB00B0B768 /* ScriptExcuteButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE94570B2A9E69EB00B0B768 /* ScriptExcuteButton.swift */; }; DE94570F2A9E69F200B0B768 /* ScriptDeleteButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE94570E2A9E69F200B0B768 /* ScriptDeleteButton.swift */; }; DE9457162A9E6D3000B0B768 /* ScriptQuickSlotButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9457112A9E6A0000B0B768 /* ScriptQuickSlotButton.swift */; }; + DE9457192A9EEEF000B0B768 /* ScriptCellManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9457182A9EEEF000B0B768 /* ScriptCellManager.swift */; }; + DE94571C2A9EFB7800B0B768 /* Associated+NSButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE94571B2A9EFB7800B0B768 /* Associated+NSButton.swift */; }; DE97CA692A9A6364001073DE /* PixelConversion+CGFloat.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE97CA682A9A6364001073DE /* PixelConversion+CGFloat.swift */; }; DE97CA792A9A6F6A001073DE /* QuickSlotHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE97CA782A9A6F6A001073DE /* QuickSlotHeaderView.swift */; }; DE97CA7C2A9A7199001073DE /* QuickSlotGroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE97CA7B2A9A7199001073DE /* QuickSlotGroupView.swift */; }; @@ -193,6 +195,8 @@ DE94570B2A9E69EB00B0B768 /* ScriptExcuteButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptExcuteButton.swift; sourceTree = ""; }; DE94570E2A9E69F200B0B768 /* ScriptDeleteButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptDeleteButton.swift; sourceTree = ""; }; DE9457112A9E6A0000B0B768 /* ScriptQuickSlotButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptQuickSlotButton.swift; sourceTree = ""; }; + DE9457182A9EEEF000B0B768 /* ScriptCellManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptCellManager.swift; sourceTree = ""; }; + DE94571B2A9EFB7800B0B768 /* Associated+NSButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Associated+NSButton.swift"; sourceTree = ""; }; DE97CA682A9A6364001073DE /* PixelConversion+CGFloat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PixelConversion+CGFloat.swift"; sourceTree = ""; }; DE97CA6E2A9A6EFC001073DE /* QuickSlotViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickSlotViewModel.swift; sourceTree = ""; }; DE97CA712A9A6F0D001073DE /* QuickSlotButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickSlotButtonModel.swift; sourceTree = ""; }; @@ -566,6 +570,7 @@ children = ( DE7886032A9C71CB00FE21DD /* ScriptsTableView.swift */, DE9456FF2A9E5B0900B0B768 /* ScriptCell.swift */, + DE9457182A9EEEF000B0B768 /* ScriptCellManager.swift */, ); path = Table; sourceTree = ""; @@ -687,6 +692,7 @@ DE24E63A2A8FE93900E29F5D /* NSImage.swift */, DE98E83A2A98DB6000F8744A /* RotateImage+NSImage.swift */, DE97CA682A9A6364001073DE /* PixelConversion+CGFloat.swift */, + DE94571B2A9EFB7800B0B768 /* Associated+NSButton.swift */, ); path = Extensions; sourceTree = ""; @@ -785,6 +791,7 @@ DE4408082A9240300091937A /* BoxFunctionButtonView.swift in Sources */, DE3FF3742A978AB8009C88EF /* WindowMaximizeButton.swift in Sources */, DE3FF3A32A97D2A6009C88EF /* DisplayURLTextfield.swift in Sources */, + DE9457192A9EEEF000B0B768 /* ScriptCellManager.swift in Sources */, DE9457002A9E5B0900B0B768 /* ScriptCell.swift in Sources */, DE7886042A9C71CB00FE21DD /* ScriptsTableView.swift in Sources */, DE97CA872A9A7407001073DE /* QuickSlotButtonModel.swift in Sources */, @@ -798,6 +805,7 @@ DE77BBF02A9E38C6006CC98B /* GetUserProfile.swift in Sources */, DEF749322A85657600D987C8 /* NSScreen.swift in Sources */, DE018BF02A509B2F00FF0AA3 /* MenubarViewController.swift in Sources */, + DE94571C2A9EFB7800B0B768 /* Associated+NSButton.swift in Sources */, DE6332E42A9BB8F800DCFAF6 /* QuickSlotButtonCollectionViewController.swift in Sources */, DE9457062A9E69C100B0B768 /* ScriptNameLabel.swift in Sources */, DE77BA512A82580400713683 /* MenubarViewModel.swift in Sources */, diff --git a/Box42/Extensions/Associated+NSButton.swift b/Box42/Extensions/Associated+NSButton.swift new file mode 100644 index 0000000..f6d610f --- /dev/null +++ b/Box42/Extensions/Associated+NSButton.swift @@ -0,0 +1,21 @@ +// +// Associated+NSButton.swift +// Box42 +// +// Created by Chanhee Kim on 8/30/23. +// + +import AppKit + +private var AssociatedObjectKey: UInt8 = 0 + +extension NSButton { + var associatedString: String? { + get { + return objc_getAssociatedObject(self, &AssociatedObjectKey) as? String + } + set(newValue) { + objc_setAssociatedObject(self, &AssociatedObjectKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } +} diff --git a/Box42/FunctionButton/BoxFunctionViewController.swift b/Box42/FunctionButton/BoxFunctionViewController.swift index 42e3396..ea2f9e0 100644 --- a/Box42/FunctionButton/BoxFunctionViewController.swift +++ b/Box42/FunctionButton/BoxFunctionViewController.swift @@ -28,6 +28,13 @@ class BoxFunctionViewController: NSViewController { } func pin() { + StateManager.shared.togglePin() + + if StateManager.shared.pin { + // image on + } else { + // image off + } print("pin") } diff --git a/Box42/QuickSlot/Controller/QuickSlotScriptsLogicController.swift b/Box42/QuickSlot/Controller/QuickSlotScriptsLogicController.swift index 41bc732..517a789 100644 --- a/Box42/QuickSlot/Controller/QuickSlotScriptsLogicController.swift +++ b/Box42/QuickSlot/Controller/QuickSlotScriptsLogicController.swift @@ -17,30 +17,23 @@ class ScriptsLogicController { @objc func handleButtonTapped(notification: NSNotification) { if let button = notification.object as? NSButton { - let buttonTitle = button.title - print("Button with title \(buttonTitle) was tapped") - - DispatchQueue.global(qos: .background).async { [weak self] in - if buttonTitle == QuickSlotUI.title.clean { - self?.executeCleanScript() - } - } + ExcuteScripts.executeShellScript(path: button.associatedString ?? "") } } - + private func executeCleanScript() { if let scriptPath = Bundle.main.path(forResource: "cleanCache", ofType: "sh") { let task = Process() task.launchPath = "/bin/sh" task.arguments = [scriptPath] - + let outputPipe = Pipe() task.standardOutput = outputPipe task.standardError = outputPipe - + task.launch() task.waitUntilExit() - + let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile() let output = String(data: outputData, encoding: .utf8) ?? "" diff --git a/Box42/QuickSlot/Model/QuickSlotButtonModel.swift b/Box42/QuickSlot/Model/QuickSlotButtonModel.swift index 2929b82..b965db8 100644 --- a/Box42/QuickSlot/Model/QuickSlotButtonModel.swift +++ b/Box42/QuickSlot/Model/QuickSlotButtonModel.swift @@ -11,9 +11,11 @@ import Foundation struct QuickSlotButtonModel { let id: UUID var title: String + var path: String? - init(id: UUID = UUID(), title: String = "Default") { + init(id: UUID = UUID(), title: String = "Default", path: String? = nil) { self.id = id self.title = title + self.path = path } } diff --git a/Box42/QuickSlot/View/ButtonCollectionView/QuickSlotButtonCollectionViewController.swift b/Box42/QuickSlot/View/ButtonCollectionView/QuickSlotButtonCollectionViewController.swift index 52b2697..c5d60bc 100644 --- a/Box42/QuickSlot/View/ButtonCollectionView/QuickSlotButtonCollectionViewController.swift +++ b/Box42/QuickSlot/View/ButtonCollectionView/QuickSlotButtonCollectionViewController.swift @@ -97,6 +97,7 @@ extension QuickSlotButtonCollectionViewController: NSCollectionViewDelegate, NSC btn.layer?.backgroundColor = NSColor.red.cgColor customItem.view.addSubview(btn) btn.frame = CGRect(x: 0, y: 0, width: QuickSlotUI.size.button, height: QuickSlotUI.size.button) + btn.associatedString = buttonModel.path } return item } diff --git a/Box42/Scripts/Model/Scripts.swift b/Box42/Scripts/Model/Scripts.swift index 7671c3d..2b74c13 100644 --- a/Box42/Scripts/Model/Scripts.swift +++ b/Box42/Scripts/Model/Scripts.swift @@ -15,10 +15,12 @@ struct Script: Codable { var id: UUID var name: String var description: String + var path: String - init(name: String, description: String) { + init(name: String, description: String, path: String) { self.id = UUID() self.name = name self.description = description + self.path = path } } diff --git a/Box42/Scripts/View/Table/ScriptCellManager.swift b/Box42/Scripts/View/Table/ScriptCellManager.swift new file mode 100644 index 0000000..b471493 --- /dev/null +++ b/Box42/Scripts/View/Table/ScriptCellManager.swift @@ -0,0 +1,109 @@ +// +// ScriptCellManager.swift +// Box42 +// +// Created by Chanhee Kim on 8/30/23. +// + +import AppKit +import SnapKit + +// MARK: - 다음 버전에 추가 예정 +class ScriptCellManager: 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 + + 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?.id { + viewModel?.deleteScript(id: id) + } + } + + @objc func excuteButtonClicked() { + if let id = script?.id { + viewModel?.excuteScript(id: id) + } + } + + @objc func quickSlotButtonclicked() { + if let id = script?.id { + viewModel?.quickSlotScript(id: id) + } + } +} diff --git a/Box42/Scripts/View/Table/ScriptsTableView.swift b/Box42/Scripts/View/Table/ScriptsTableView.swift index 44c155c..2d77ef0 100644 --- a/Box42/Scripts/View/Table/ScriptsTableView.swift +++ b/Box42/Scripts/View/Table/ScriptsTableView.swift @@ -30,28 +30,47 @@ class ScriptsTableView: NSTableView { self.delegate = self self.dataSource = self - let column1 = NSTableColumn(identifier: NSUserInterfaceItemIdentifier("Column1")) + let column1 = NSTableColumn(identifier: NSUserInterfaceItemIdentifier("Scripts")) column1.width = 100.0 - column1.title = "Column 1" + column1.title = "Scripts" self.addTableColumn(column1) } } extension ScriptsTableView: NSTableViewDelegate, NSTableViewDataSource { - + func getCellForRow(at row: Int) -> NSView { + guard let viewModel = viewModel else { + return NSView() + } + + if row < viewModel.scripts.count { + return getScriptCell(for: viewModel.scripts[row], viewModel: viewModel) + } else { + // MARK: - 다음 버전에 추가 예정 + return getScriptCellManager() + } + } + + private func getScriptCell(for script: Script, viewModel: ScriptViewModel) -> ScriptCell { + let cell = ScriptCell(frame: .zero) + cell.configure(with: script, viewModel: viewModel) + return cell + } + + private func getScriptCellManager() -> ScriptCellManager { + let scriptCellManger = ScriptCellManager(frame: .zero) + return scriptCellManger + } + func numberOfRows(in tableView: NSTableView) -> Int { - return viewModel?.scripts.count ?? 0 + return viewModel?.scripts.count ?? 0 // + 1 } func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { - let cell = ScriptCell(frame: .zero) // 또는 원하는 frame 값을 설정 - if let script = viewModel?.scripts[row] { - cell.configure(with: script, viewModel: viewModel) - } - return cell // 이 줄을 추가 + getCellForRow(at: row) } func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat { - return 44.0 // 셀 높이를 44로 설정 + return 44.0 } } diff --git a/Box42/Scripts/ViewModel/ScriptsViewModel.swift b/Box42/Scripts/ViewModel/ScriptsViewModel.swift index 75955fd..2d2db23 100644 --- a/Box42/Scripts/ViewModel/ScriptsViewModel.swift +++ b/Box42/Scripts/ViewModel/ScriptsViewModel.swift @@ -13,14 +13,18 @@ class ScriptViewModel: NSObject { override init() { self.scripts = [ - Script(name: "cleanCache", description: "Cleaning cache"), - Script(name: "brewInGoinfre", description: "Brew download in goinfre") + Script(name: "cleanCache", + description: "Cleaning cache", + path: Bundle.main.path(forResource: "cleanCache", ofType: "sh") ?? ""), + Script(name: "brewInGoinfre", + description: "Brew download in goinfre", + path: Bundle.main.path(forResource: "brewInGoinfre", ofType: "sh") ?? "") ] } // Create - func addScript(name: String, description: String) { - let newScript = Script(name: name, description: description) + func addScript(name: String, description: String, path: String) { + let newScript = Script(name: name, description: description, path: path) scripts.append(newScript) } @@ -47,7 +51,7 @@ class ScriptViewModel: NSObject { func quickSlotScript(id: UUID) { if let index = scripts.firstIndex(where: { $0.id == id }) { - let button = QuickSlotButtonModel(id: id, title: scripts[index].name) + let button = QuickSlotButtonModel(id: id, title: scripts[index].name, path: scripts[index].path) QuickSlotViewModel.shared.addButton(button) } } From 31cf240f193b7685a339326cd84251c65051da20 Mon Sep 17 00:00:00 2001 From: KIM CHAN HEE <85754295+chanhihi@users.noreply.github.com> Date: Wed, 30 Aug 2023 20:07:59 +0900 Subject: [PATCH 02/14] feat: pin (#105) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: 잘못된 resource명을 변경합니다. * feat: 핀 변경시 image 변경 --- .../FunctionButton/BoxFunctionViewController.swift | 13 ++++++++++--- Box42/FunctionButton/View/PinButtonView.swift | 4 ++++ .../uibuttons/Bookmark.imageset/Contents.json | 2 +- .../uibuttons/Star.imageset/Contents.json | 2 +- .../Star.imageset/{Star 3.png => star.png} | Bin 5 files changed, 16 insertions(+), 5 deletions(-) rename Box42/Resources/Assets.xcassets/uibuttons/Star.imageset/{Star 3.png => star.png} (100%) diff --git a/Box42/FunctionButton/BoxFunctionViewController.swift b/Box42/FunctionButton/BoxFunctionViewController.swift index ea2f9e0..0c1a9b3 100644 --- a/Box42/FunctionButton/BoxFunctionViewController.swift +++ b/Box42/FunctionButton/BoxFunctionViewController.swift @@ -8,9 +8,13 @@ import Cocoa class BoxFunctionViewController: NSViewController { + + var pinButtonView: PinButtonView? + override func loadView() { let functionViewGroup = BoxFunctionViewGroup() + pinButtonView = functionViewGroup.pinButton functionViewGroup.preferenceAction = preference functionViewGroup.pinAction = pin functionViewGroup.quitAction = quit @@ -30,11 +34,14 @@ class BoxFunctionViewController: NSViewController { func pin() { StateManager.shared.togglePin() + let newImage: NSImage if StateManager.shared.pin { - // image on + newImage = NSImage(imageLiteralResourceName: "pin-box-ver") } else { - // image off + newImage = NSImage(imageLiteralResourceName: "pin-box") } + + pinButtonView?.changePinImage(to: newImage) // 이미지 변경 print("pin") } @@ -44,7 +51,7 @@ class BoxFunctionViewController: NSViewController { } weak var delegate: BoxFunctionViewControllerDelegate? - + func box() { print("box") delegate?.didTapBoxButton() diff --git a/Box42/FunctionButton/View/PinButtonView.swift b/Box42/FunctionButton/View/PinButtonView.swift index 684e3be..9c9db8b 100644 --- a/Box42/FunctionButton/View/PinButtonView.swift +++ b/Box42/FunctionButton/View/PinButtonView.swift @@ -49,6 +49,10 @@ class PinButtonView: NSView { fatalError("init(coder:) has not been implemented") } + func changePinImage(to image: NSImage) { + pinBoxButton.image = image + } + @objc func pin() { callback?() } diff --git a/Box42/Resources/Assets.xcassets/uibuttons/Bookmark.imageset/Contents.json b/Box42/Resources/Assets.xcassets/uibuttons/Bookmark.imageset/Contents.json index f843e5b..c1d7e62 100644 --- a/Box42/Resources/Assets.xcassets/uibuttons/Bookmark.imageset/Contents.json +++ b/Box42/Resources/Assets.xcassets/uibuttons/Bookmark.imageset/Contents.json @@ -5,7 +5,7 @@ "scale" : "1x" }, { - "filename" : "Bookmark icon.png", + "filename" : "bookmark icon.png", "idiom" : "universal", "scale" : "2x" }, diff --git a/Box42/Resources/Assets.xcassets/uibuttons/Star.imageset/Contents.json b/Box42/Resources/Assets.xcassets/uibuttons/Star.imageset/Contents.json index bad711e..2e47fcd 100644 --- a/Box42/Resources/Assets.xcassets/uibuttons/Star.imageset/Contents.json +++ b/Box42/Resources/Assets.xcassets/uibuttons/Star.imageset/Contents.json @@ -5,7 +5,7 @@ "scale" : "1x" }, { - "filename" : "Star 3.png", + "filename" : "star.png", "idiom" : "universal", "scale" : "2x" }, diff --git a/Box42/Resources/Assets.xcassets/uibuttons/Star.imageset/Star 3.png b/Box42/Resources/Assets.xcassets/uibuttons/Star.imageset/star.png similarity index 100% rename from Box42/Resources/Assets.xcassets/uibuttons/Star.imageset/Star 3.png rename to Box42/Resources/Assets.xcassets/uibuttons/Star.imageset/star.png From 2e998d5bcd1fae67c7a416650855c5363cae8c9f Mon Sep 17 00:00:00 2001 From: KIM CHAN HEE <85754295+chanhihi@users.noreply.github.com> Date: Wed, 30 Aug 2023 21:04:48 +0900 Subject: [PATCH 03/14] fix: swift build error fix (#107) --- Box42.xcodeproj/project.pbxproj | 3 +- .../Preferences/Accessibility.swift | 0 .../PreferencesViewController.swift | 0 .../{QuickSlot => }/Preferences/Hotkey.swift | 0 .../Preferences/PreferencesView.swift | 0 .../PreferencesViewController.swift | 147 ------------------ .../Preferences/View/PreferencesCell.swift | 0 Package.resolved | 16 ++ 8 files changed, 17 insertions(+), 149 deletions(-) rename Box42/{QuickSlot => }/Preferences/Accessibility.swift (100%) rename Box42/{QuickSlot => }/Preferences/Controller/PreferencesViewController.swift (100%) rename Box42/{QuickSlot => }/Preferences/Hotkey.swift (100%) rename Box42/{QuickSlot => }/Preferences/PreferencesView.swift (100%) delete mode 100644 Box42/Preferences/PreferencesViewController.swift rename Box42/{QuickSlot => }/Preferences/View/PreferencesCell.swift (100%) create mode 100644 Package.resolved diff --git a/Box42.xcodeproj/project.pbxproj b/Box42.xcodeproj/project.pbxproj index 6e15b5e..3f287e1 100644 --- a/Box42.xcodeproj/project.pbxproj +++ b/Box42.xcodeproj/project.pbxproj @@ -532,8 +532,7 @@ DE2AD3282A824EEB00002D51 /* Accessibility.swift */, DE874F4D2A591DEA00FC3B77 /* Hotkey.swift */, ); - name = Preferences; - path = QuickSlot/Preferences; + path = Preferences; sourceTree = ""; }; DE9456F62A9E44F100B0B768 /* Icon */ = { diff --git a/Box42/QuickSlot/Preferences/Accessibility.swift b/Box42/Preferences/Accessibility.swift similarity index 100% rename from Box42/QuickSlot/Preferences/Accessibility.swift rename to Box42/Preferences/Accessibility.swift diff --git a/Box42/QuickSlot/Preferences/Controller/PreferencesViewController.swift b/Box42/Preferences/Controller/PreferencesViewController.swift similarity index 100% rename from Box42/QuickSlot/Preferences/Controller/PreferencesViewController.swift rename to Box42/Preferences/Controller/PreferencesViewController.swift diff --git a/Box42/QuickSlot/Preferences/Hotkey.swift b/Box42/Preferences/Hotkey.swift similarity index 100% rename from Box42/QuickSlot/Preferences/Hotkey.swift rename to Box42/Preferences/Hotkey.swift diff --git a/Box42/QuickSlot/Preferences/PreferencesView.swift b/Box42/Preferences/PreferencesView.swift similarity index 100% rename from Box42/QuickSlot/Preferences/PreferencesView.swift rename to Box42/Preferences/PreferencesView.swift diff --git a/Box42/Preferences/PreferencesViewController.swift b/Box42/Preferences/PreferencesViewController.swift deleted file mode 100644 index e132672..0000000 --- a/Box42/Preferences/PreferencesViewController.swift +++ /dev/null @@ -1,147 +0,0 @@ -// -// PreferencesViewController.swift -// Box42 -// -// Created by Chanhee Kim on 7/24/23. -// - -import Cocoa -import Foundation - -class PreferencesViewController: NSViewController { - let menubarVC = MenubarViewController() - private var stackView: NSStackView! - private var rightView: NSView! - private var outputView: NSTextView! - - override func loadView() { - self.view = NSView() - self.stackView = NSStackView() - self.stackView.orientation = .vertical - self.stackView.distribution = .fillEqually - self.stackView.spacing = 20 - self.view.addSubview(stackView) - stackView.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - stackView.topAnchor.constraint(equalTo: self.view.topAnchor), - stackView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), - stackView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), - stackView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor) - ]) - - let leftView = NSView() - self.rightView = NSView() - self.stackView.addArrangedSubview(leftView) - self.stackView.addArrangedSubview(rightView) - - outputView = NSTextView() - outputView.translatesAutoresizingMaskIntoConstraints = false - rightView.addSubview(outputView) - - NSLayoutConstraint.activate([ - outputView.topAnchor.constraint(equalTo: rightView.topAnchor), - outputView.leadingAnchor.constraint(equalTo: rightView.leadingAnchor), - outputView.trailingAnchor.constraint(equalTo: rightView.trailingAnchor), - outputView.bottomAnchor.constraint(equalTo: rightView.bottomAnchor) - ]) - - - var stackBox: [NSView] = [] - - - let scripts = Scripts().info - scripts.forEach { (script) in - stackBox.append(NSButton(title: "\(script.name) Script: \(script.description)", target: self, action: #selector(scriptButtonPressed))) - - } - -// let scriptButton = NSButton(title: "Script", target: self, action: #selector(scriptButtonPressed)) - let appleScriptButton = NSButton(title: "Apple Script", target: self, action: #selector(scriptButtonPressed)) - let etcButton = NSButton(title: "Etc.", target: self, action: #selector(etcButtonPressed)) - -// stackBox.append(scriptButton) - stackBox.append(appleScriptButton) - stackBox.append(etcButton) - let buttonStackView = NSStackView(views: stackBox) - buttonStackView.orientation = .vertical - buttonStackView.distribution = .fillEqually - buttonStackView.spacing = 20 - leftView.addSubview(buttonStackView) - buttonStackView.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - buttonStackView.topAnchor.constraint(equalTo: leftView.topAnchor), - buttonStackView.leadingAnchor.constraint(equalTo: leftView.leadingAnchor), - buttonStackView.trailingAnchor.constraint(equalTo: leftView.trailingAnchor), - buttonStackView.bottomAnchor.constraint(equalTo: leftView.bottomAnchor) - ]) - } - - @objc func changeIconButtonPressed(_ sender: NSButton) { - // Change the content of the right view for icon changing - let icon = sender.title.split(separator: " ").map{String($0)} - print(icon[1]) - menubarVC.menubarStopRunning() - menubarVC.buttonImageChange(icon[1]) - menubarVC.menubarStartRunning() - } - - @objc func scriptButtonPressed(_ sender: NSButton) { - let script = sender.title.split(separator: " ").map{String($0)} - if script[1] == "Script:" { - if let scriptPath = Bundle.main.path(forResource: script[0], ofType: "sh") { - let task = Process() - task.launchPath = "/bin/sh" - task.arguments = [scriptPath] - - let outputPipe = Pipe() - task.standardOutput = outputPipe - task.standardError = outputPipe - - - task.standardError = outputPipe - -// outputPipe.fileHandleForReading.readabilityHandler = { [weak self] fileHandle in -// if #available(OSX 10.15.4, *) { -// if let data = try? fileHandle.readToEnd(), let output = String(data: data, encoding: .utf8) { -// DispatchQueue.main.async { -// if let outputView = self?.outputView { -// outputView.string += "\(output)" -// } else { -// print("outputView is nil") -// } -// } -// } -// } else { -// // Fallback on earlier versions -// } -// } - - - task.launch() - task.waitUntilExit() - -// let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile() -// let output = String(data: outputData, encoding: .utf8) ?? "" -// print("Output: \(output)") - } else { - print("Script not found") - } - } else if sender.title == "Apple Script" { - let appleScriptCode = "display dialog \"Hello, World!\"" - - if let appleScript = NSAppleScript(source: appleScriptCode) { - var errorDict: NSDictionary? = nil - appleScript.executeAndReturnError(&errorDict) - - if let error = errorDict { - print("Error: \(error)") - } - } - } - } - - @objc func etcButtonPressed() { - // Change the content of the right view for etc. - } -} - diff --git a/Box42/QuickSlot/Preferences/View/PreferencesCell.swift b/Box42/Preferences/View/PreferencesCell.swift similarity index 100% rename from Box42/QuickSlot/Preferences/View/PreferencesCell.swift rename to Box42/Preferences/View/PreferencesCell.swift diff --git a/Package.resolved b/Package.resolved new file mode 100644 index 0000000..81101ad --- /dev/null +++ b/Package.resolved @@ -0,0 +1,16 @@ +{ + "object": { + "pins": [ + { + "package": "SnapKit", + "repositoryURL": "https://github.com/SnapKit/SnapKit", + "state": { + "branch": null, + "revision": "f222cbdf325885926566172f6f5f06af95473158", + "version": "5.6.0" + } + } + ] + }, + "version": 1 +} From fdc16e1547db4c23701374a63e78f1700a7b5338 Mon Sep 17 00:00:00 2001 From: chanhihi Date: Thu, 31 Aug 2023 04:23:32 +0900 Subject: [PATCH 04/14] =?UTF-8?q?feat:=20API=EB=A5=BC=20=EB=AA=A8=EB=93=88?= =?UTF-8?q?=ED=99=94=20=ED=95=A9=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Box42.xcodeproj/project.pbxproj | 28 ++++++- ...cuteScripts.swift => ExecuteScripts.swift} | 4 +- Box42/Shared/API/API.swift | 63 ++++++++++++++++ Box42/Shared/API/GetUserMeScripts.swift | 34 +++++++++ Box42/Shared/API/GetUserProfile.swift | 74 ++++++++++++------- 5 files changed, 169 insertions(+), 34 deletions(-) rename Box42/Scripts/Controller/{ExcuteScripts.swift => ExecuteScripts.swift} (84%) create mode 100644 Box42/Shared/API/API.swift create mode 100644 Box42/Shared/API/GetUserMeScripts.swift diff --git a/Box42.xcodeproj/project.pbxproj b/Box42.xcodeproj/project.pbxproj index 3f287e1..cf1c784 100644 --- a/Box42.xcodeproj/project.pbxproj +++ b/Box42.xcodeproj/project.pbxproj @@ -68,7 +68,7 @@ DE77BA562A82637900713683 /* StateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE77BA552A82637900713683 /* StateManager.swift */; }; DE77BBA22A9DDC40006CC98B /* ScriptsFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE77BBA12A9DDC40006CC98B /* ScriptsFileManager.swift */; }; DE77BBA62A9DDF2B006CC98B /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0A91772A8F014F00D1D6F1 /* WebView.swift */; }; - DE77BBCD2A9E0568006CC98B /* ExcuteScripts.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE77BBCC2A9E0568006CC98B /* ExcuteScripts.swift */; }; + DE77BBCD2A9E0568006CC98B /* ExecuteScripts.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE77BBCC2A9E0568006CC98B /* ExecuteScripts.swift */; }; DE77BBD22A9E0AE8006CC98B /* WebViewUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE77BBD12A9E0AE8006CC98B /* WebViewUI.swift */; }; DE77BBE22A9E0F70006CC98B /* Scripts.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE77BBE12A9E0F70006CC98B /* Scripts.swift */; }; DE77BBF02A9E38C6006CC98B /* GetUserProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE77BBA92A9DE680006CC98B /* GetUserProfile.swift */; }; @@ -92,6 +92,11 @@ DE9457162A9E6D3000B0B768 /* ScriptQuickSlotButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9457112A9E6A0000B0B768 /* ScriptQuickSlotButton.swift */; }; DE9457192A9EEEF000B0B768 /* ScriptCellManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9457182A9EEEF000B0B768 /* ScriptCellManager.swift */; }; DE94571C2A9EFB7800B0B768 /* Associated+NSButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE94571B2A9EFB7800B0B768 /* Associated+NSButton.swift */; }; + DE9457282A9F6E4400B0B768 /* GetUserMeScripts.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9457272A9F6E4400B0B768 /* GetUserMeScripts.swift */; }; + DE94572C2A9F75D500B0B768 /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE94572B2A9F75D500B0B768 /* API.swift */; }; + DE9457312A9FB01400B0B768 /* PreferencesTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9457302A9FB01400B0B768 /* PreferencesTableView.swift */; }; + DE9457342A9FB1D300B0B768 /* RequestAccessView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9457332A9FB1D300B0B768 /* RequestAccessView.swift */; }; + DE9457372A9FC0A800B0B768 /* SecurityScopedResourceAccess.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9457362A9FC0A800B0B768 /* SecurityScopedResourceAccess.swift */; }; DE97CA692A9A6364001073DE /* PixelConversion+CGFloat.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE97CA682A9A6364001073DE /* PixelConversion+CGFloat.swift */; }; DE97CA792A9A6F6A001073DE /* QuickSlotHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE97CA782A9A6F6A001073DE /* QuickSlotHeaderView.swift */; }; DE97CA7C2A9A7199001073DE /* QuickSlotGroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE97CA7B2A9A7199001073DE /* QuickSlotGroupView.swift */; }; @@ -173,7 +178,7 @@ DE77BA552A82637900713683 /* StateManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateManager.swift; sourceTree = ""; }; DE77BBA12A9DDC40006CC98B /* ScriptsFileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptsFileManager.swift; sourceTree = ""; }; DE77BBA92A9DE680006CC98B /* GetUserProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetUserProfile.swift; sourceTree = ""; }; - DE77BBCC2A9E0568006CC98B /* ExcuteScripts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExcuteScripts.swift; sourceTree = ""; }; + DE77BBCC2A9E0568006CC98B /* ExecuteScripts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExecuteScripts.swift; sourceTree = ""; }; DE77BBD12A9E0AE8006CC98B /* WebViewUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewUI.swift; sourceTree = ""; }; DE77BBE12A9E0F70006CC98B /* Scripts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Scripts.swift; sourceTree = ""; }; DE77BBE92A9E2DDF006CC98B /* UserManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserManager.swift; sourceTree = ""; }; @@ -197,6 +202,11 @@ DE9457112A9E6A0000B0B768 /* ScriptQuickSlotButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptQuickSlotButton.swift; sourceTree = ""; }; DE9457182A9EEEF000B0B768 /* ScriptCellManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptCellManager.swift; sourceTree = ""; }; DE94571B2A9EFB7800B0B768 /* Associated+NSButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Associated+NSButton.swift"; sourceTree = ""; }; + DE9457272A9F6E4400B0B768 /* GetUserMeScripts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetUserMeScripts.swift; sourceTree = ""; }; + DE94572B2A9F75D500B0B768 /* API.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = ""; }; + DE9457302A9FB01400B0B768 /* PreferencesTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesTableView.swift; sourceTree = ""; }; + DE9457332A9FB1D300B0B768 /* RequestAccessView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestAccessView.swift; sourceTree = ""; }; + DE9457362A9FC0A800B0B768 /* SecurityScopedResourceAccess.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityScopedResourceAccess.swift; sourceTree = ""; }; DE97CA682A9A6364001073DE /* PixelConversion+CGFloat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PixelConversion+CGFloat.swift"; sourceTree = ""; }; DE97CA6E2A9A6EFC001073DE /* QuickSlotViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickSlotViewModel.swift; sourceTree = ""; }; DE97CA712A9A6F0D001073DE /* QuickSlotButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickSlotButtonModel.swift; sourceTree = ""; }; @@ -424,6 +434,7 @@ DE1F1A282A8B50E200A88DD8 /* BoxSizeManager.swift */, DE77BA552A82637900713683 /* StateManager.swift */, DE0A91622A8E6A5400D1D6F1 /* Constants.swift */, + DE9457362A9FC0A800B0B768 /* SecurityScopedResourceAccess.swift */, ); path = Shared; sourceTree = ""; @@ -432,6 +443,8 @@ isa = PBXGroup; children = ( DE77BBA92A9DE680006CC98B /* GetUserProfile.swift */, + DE9457272A9F6E4400B0B768 /* GetUserMeScripts.swift */, + DE94572B2A9F75D500B0B768 /* API.swift */, ); path = API; sourceTree = ""; @@ -500,7 +513,7 @@ children = ( DE0A917A2A8F0CA800D1D6F1 /* AppleScripts+ShowMessage.swift */, DE77BBA12A9DDC40006CC98B /* ScriptsFileManager.swift */, - DE77BBCC2A9E0568006CC98B /* ExcuteScripts.swift */, + DE77BBCC2A9E0568006CC98B /* ExecuteScripts.swift */, DE7886272A9D186700FE21DD /* ScriptsViewController.swift */, ); path = Controller; @@ -510,6 +523,8 @@ isa = PBXGroup; children = ( DE78862C2A9D1ADE00FE21DD /* PreferencesCell.swift */, + DE9457302A9FB01400B0B768 /* PreferencesTableView.swift */, + DE9457332A9FB1D300B0B768 /* RequestAccessView.swift */, ); path = View; sourceTree = ""; @@ -793,6 +808,7 @@ DE9457192A9EEEF000B0B768 /* ScriptCellManager.swift in Sources */, DE9457002A9E5B0900B0B768 /* ScriptCell.swift in Sources */, DE7886042A9C71CB00FE21DD /* ScriptsTableView.swift in Sources */, + DE9457312A9FB01400B0B768 /* PreferencesTableView.swift in Sources */, DE97CA872A9A7407001073DE /* QuickSlotButtonModel.swift in Sources */, DE77BA562A82637900713683 /* StateManager.swift in Sources */, DE1F1A1C2A8B50C500A88DD8 /* BoxBaseContainerViewController.swift in Sources */, @@ -800,6 +816,7 @@ DE018BE72A509B1E00FF0AA3 /* WebViewController.swift in Sources */, DE98E8552A98EA7900F8744A /* WindowButtonUI.swift in Sources */, DE4407FA2A923E860091937A /* BoxFunctionViewController.swift in Sources */, + DE94572C2A9F75D500B0B768 /* API.swift in Sources */, DE4407FE2A923EA90091937A /* PreferenceButtonView.swift in Sources */, DE77BBF02A9E38C6006CC98B /* GetUserProfile.swift in Sources */, DEF749322A85657600D987C8 /* NSScreen.swift in Sources */, @@ -818,22 +835,25 @@ DE77BBA62A9DDF2B006CC98B /* WebView.swift in Sources */, DE0A91832A8F889000D1D6F1 /* GoHomePageViaToolbar().swift in Sources */, DE6332F22A9BCA2C00DCFAF6 /* QuickSlotScriptsLogicController.swift in Sources */, + DE9457342A9FB1D300B0B768 /* RequestAccessView.swift in Sources */, DE018BB32A5099F900FF0AA3 /* AppDelegate.swift in Sources */, DE78860C2A9C770300FE21DD /* ScriptsViewModel.swift in Sources */, DE0A91632A8E6A5400D1D6F1 /* Constants.swift in Sources */, DE7886172A9CCB3B00FE21DD /* UserProfile.swift in Sources */, DE0A91902A8F88CA00D1D6F1 /* DisplayURLInToolbar.swift in Sources */, - DE77BBCD2A9E0568006CC98B /* ExcuteScripts.swift in Sources */, + DE77BBCD2A9E0568006CC98B /* ExecuteScripts.swift in Sources */, DE9456F82A9E44FD00B0B768 /* IconController.swift in Sources */, DE018BF32A509B3300FF0AA3 /* MenubarModel.swift in Sources */, DE7A257A2A6D8CA20043225A /* PreferencesViewController.swift in Sources */, DE24E63B2A8FE93900E29F5D /* NSImage.swift in Sources */, DE94570F2A9E69F200B0B768 /* ScriptDeleteButton.swift in Sources */, DE97CA792A9A6F6A001073DE /* QuickSlotHeaderView.swift in Sources */, + DE9457372A9FC0A800B0B768 /* SecurityScopedResourceAccess.swift in Sources */, DE0A916D2A8E7DD700D1D6F1 /* HoverButton.swift in Sources */, DE97CA862A9A7404001073DE /* QuickSlotViewModel.swift in Sources */, DE3FF3762A978AB8009C88EF /* WindowCloseButton.swift in Sources */, DE9457092A9E69D100B0B768 /* ScriptDescriptionsLabel.swift in Sources */, + DE9457282A9F6E4400B0B768 /* GetUserMeScripts.swift in Sources */, DE77BBD22A9E0AE8006CC98B /* WebViewUI.swift in Sources */, DE3FF3772A978AB8009C88EF /* WindowMinimizeButton.swift in Sources */, DE4408022A923EB60091937A /* PinButtonView.swift in Sources */, diff --git a/Box42/Scripts/Controller/ExcuteScripts.swift b/Box42/Scripts/Controller/ExecuteScripts.swift similarity index 84% rename from Box42/Scripts/Controller/ExcuteScripts.swift rename to Box42/Scripts/Controller/ExecuteScripts.swift index cf36f28..1692d77 100644 --- a/Box42/Scripts/Controller/ExcuteScripts.swift +++ b/Box42/Scripts/Controller/ExecuteScripts.swift @@ -1,5 +1,5 @@ // -// ExcuteScripts.swift +// ExecuteScripts.swift // Box42 // // Created by Chanhee Kim on 8/29/23. @@ -7,7 +7,7 @@ import Foundation -class ExcuteScripts { +class ExecuteScripts { static func executeShellScript(path: String) { let task = Process() task.launchPath = "/bin/sh" diff --git a/Box42/Shared/API/API.swift b/Box42/Shared/API/API.swift new file mode 100644 index 0000000..f9cb069 --- /dev/null +++ b/Box42/Shared/API/API.swift @@ -0,0 +1,63 @@ +// +// Shared.swift +// Box42 +// +// Created by Chanhee Kim on 8/30/23. +// + +import WebKit + +class API { + // GET + static func fetchDataFromAPI(withURL urlString: String, forType type: T.Type, completion: @escaping (Result) -> Void) { + + let url = URL(string: urlString)! + var request = URLRequest(url: url) + request.httpShouldHandleCookies = true + + let task = URLSession.shared.dataTask(with: request) { (data, response, error) in + if let error = error { + completion(.failure(error)) + return + } + + guard let data = data else { + completion(.failure(NSError(domain: "NoData", code: -1, userInfo: nil))) + return + } + + do { + let decodedData = try JSONDecoder().decode(type, from: data) + completion(.success(decodedData)) + } catch let jsonError { + completion(.failure(jsonError)) + } + } + task.resume() + } + + // DELETE + static func deleteDataFromAPI(withURL urlString: String, completion: @escaping (Result) -> Void) { + + let url = URL(string: urlString)! + var request = URLRequest(url: url) + request.httpMethod = "DELETE" + request.httpShouldHandleCookies = true + + let task = URLSession.shared.dataTask(with: request) { (data, response, error) in + if let error = error { + completion(.failure(error)) + return + } + + if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode != 200 { + completion(.failure(NSError(domain: "InvalidStatusCode", code: httpResponse.statusCode, userInfo: nil))) + return + } + + completion(.success(data)) + } + task.resume() + } + +} diff --git a/Box42/Shared/API/GetUserMeScripts.swift b/Box42/Shared/API/GetUserMeScripts.swift new file mode 100644 index 0000000..7fa7d15 --- /dev/null +++ b/Box42/Shared/API/GetUserMeScripts.swift @@ -0,0 +1,34 @@ +// +// GetScripts.swift +// Box42 +// +// Created by Chanhee Kim on 8/30/23. +// + +import WebKit + +extension API { + // MARK: - Scripts GET: https://api.42box.site/user-service/users/me/scripts + // result : scripts.shared 저장 + + static func getUserMeScripts(_ webView: WKWebView) { + webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in + let cookieStorage = HTTPCookieStorage.shared + for cookie in cookies { + cookieStorage.setCookie(cookie) + } + + fetchDataFromAPI(withURL: "https://api.42box.site/user-service/users/me/scripts", forType: [Script].self) { (result: Result<[Script], Error>) in + switch result { + case .success(let scripts): + print(">> MacOS Get :", scripts) + DispatchQueue.main.async { + ScriptViewModel.shared.replaceScripts(with: scripts) + } + case .failure(let error): + print("Error: \(error)") + } + } + } + } +} diff --git a/Box42/Shared/API/GetUserProfile.swift b/Box42/Shared/API/GetUserProfile.swift index 8fa41d1..1815669 100644 --- a/Box42/Shared/API/GetUserProfile.swift +++ b/Box42/Shared/API/GetUserProfile.swift @@ -7,45 +7,63 @@ import WebKit -class API { +extension API { // MARK: - 유저 정보 (Back) GET: https://api.42box.site/user-service/users/me - // return : 실패 nil 반환 - // : 성공 UserProfile() + // result : 성공 UserProfile.shared 저장 + static func getUserProfile(_ webView: WKWebView) { - var userProfile: UserProfile? - webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in let cookieStorage = HTTPCookieStorage.shared - for cookie in cookies { -// print("\(cookie.name) = \(cookie.value)") cookieStorage.setCookie(cookie) } - var request = URLRequest(url: URL(string: "https://api.42box.site/user-service/users/me")!) - request.httpShouldHandleCookies = true - let task = URLSession.shared.dataTask(with: request) { (data, response, error) in - if let error = error { - print("Error: \(error)") - return - } - - guard let data = data else { - print("No data received.") - return - } - - do { - userProfile = try JSONDecoder().decode(UserProfile.self, from: data) - - print(">> MacOS Get", userProfile) + fetchDataFromAPI(withURL: "https://api.42box.site/user-service/users/me", forType: UserProfile.self) { (result: Result) in + switch result { + case .success(let userProfile): + print(">> MacOS Get :", userProfile) UserManager.shared.updateUserProfile(newProfile: userProfile) - - } catch let jsonError { - print("JSON Parsing Error: \(jsonError)") + case .failure(let error): + print("Error: \(error)") } } - task.resume() } } } + +//static func getUserProfile(_ webView: WKWebView) { +// webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in +// let cookieStorage = HTTPCookieStorage.shared +// +// for cookie in cookies { +//// print("\(cookie.name) = \(cookie.value)") +// cookieStorage.setCookie(cookie) +// } +// +// var request = URLRequest(url: URL(string: "https://api.42box.site/user-service/users/me")!) +// request.httpShouldHandleCookies = true +// let task = URLSession.shared.dataTask(with: request) { (data, response, error) in +// if let error = error { +// print("Error: \(error)") +// return +// } +// +// guard let data = data else { +// print("No data received.") +// return +// } +// +// do { +// let userProfile = try JSONDecoder().decode(UserProfile.self, from: data) +// +// print(">> MacOS Get :", userProfile ) +// UserManager.shared.updateUserProfile(newProfile: userProfile) +// +// } catch let jsonError { +// print("JSON Parsing Error: \(jsonError)") +// } +// } +// task.resume() +// } +//} +// From eec990389ac7d0df2d13554af0cd43747d18b085 Mon Sep 17 00:00:00 2001 From: chanhihi Date: Thu, 31 Aug 2023 04:24:54 +0900 Subject: [PATCH 05/14] =?UTF-8?q?feat:=20=EC=8A=A4=ED=81=AC=EB=A6=BD?= =?UTF-8?q?=ED=8A=B8=20=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4?= =?UTF-8?q?=EB=A5=BC=20=EB=A7=9E=EC=B6=A5=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controller/ScriptsViewController.swift | 2 -- Box42/Scripts/Model/Scripts.swift | 4 ++- .../View/Button/ScriptQuickSlotButton.swift | 2 +- Box42/Scripts/View/Table/ScriptCell.swift | 20 ++++++++++-- .../Scripts/ViewModel/ScriptsViewModel.swift | 32 ++++++++++++++++--- 5 files changed, 49 insertions(+), 11 deletions(-) diff --git a/Box42/Scripts/Controller/ScriptsViewController.swift b/Box42/Scripts/Controller/ScriptsViewController.swift index ed12375..e86f46d 100644 --- a/Box42/Scripts/Controller/ScriptsViewController.swift +++ b/Box42/Scripts/Controller/ScriptsViewController.swift @@ -18,8 +18,6 @@ class ScriptsViewController: NSViewController { override func loadView() { self.view = NSView() - self.view.wantsLayer = true - self.view.layer?.backgroundColor = NSColor.blue.cgColor scriptsTableView = ScriptsTableView(frame: .zero) scriptsTableView?.setup() diff --git a/Box42/Scripts/Model/Scripts.swift b/Box42/Scripts/Model/Scripts.swift index 2b74c13..a83a5c4 100644 --- a/Box42/Scripts/Model/Scripts.swift +++ b/Box42/Scripts/Model/Scripts.swift @@ -16,11 +16,13 @@ struct Script: Codable { var name: String var description: String var path: String + var savedId: Int - init(name: String, description: String, path: String) { + init(name: String, description: String, path: String, savedId: Int) { self.id = UUID() self.name = name self.description = description self.path = path + self.savedId = savedId } } diff --git a/Box42/Scripts/View/Button/ScriptQuickSlotButton.swift b/Box42/Scripts/View/Button/ScriptQuickSlotButton.swift index a8d2420..e2351d7 100644 --- a/Box42/Scripts/View/Button/ScriptQuickSlotButton.swift +++ b/Box42/Scripts/View/Button/ScriptQuickSlotButton.swift @@ -73,7 +73,7 @@ class ScriptQuickSlotButton: NSButton { guard self.window != nil else { return } - + if self.title == "퀵슬롯" { return } // 현재 버튼의 위치를 윈도우 기준으로 변환 let initialLocation = self.frame.origin diff --git a/Box42/Scripts/View/Table/ScriptCell.swift b/Box42/Scripts/View/Table/ScriptCell.swift index bf75e4d..57d421b 100644 --- a/Box42/Scripts/View/Table/ScriptCell.swift +++ b/Box42/Scripts/View/Table/ScriptCell.swift @@ -100,9 +100,25 @@ class ScriptCell: NSTableCellView { } } + // script 내부 클릭시 1차 실행 + // 있는거면 지우고 없는거면 추가 @objc func quickSlotButtonclicked() { - if let id = script?.id { - viewModel?.quickSlotScript(id: id) + guard let id = script?.id else { + return + } + + let alreadyExists = QuickSlotViewModel.shared.buttons.contains { $0.id == id } + + if alreadyExists { + QuickSlotViewModel.shared.removeButton(id) + quickSlotButton.title = "퀵슬롯" + } else { + if QuickSlotViewModel.shared.buttons.count > 7 { + return + } else { + quickSlotButton.title = "저장됨" + viewModel?.quickSlotScript(id: id) + } } } } diff --git a/Box42/Scripts/ViewModel/ScriptsViewModel.swift b/Box42/Scripts/ViewModel/ScriptsViewModel.swift index 2d2db23..d81c86e 100644 --- a/Box42/Scripts/ViewModel/ScriptsViewModel.swift +++ b/Box42/Scripts/ViewModel/ScriptsViewModel.swift @@ -9,29 +9,45 @@ import AppKit import Combine class ScriptViewModel: NSObject { + static let shared = ScriptViewModel() + @Published var scripts: [Script] = [] override init() { self.scripts = [ Script(name: "cleanCache", description: "Cleaning cache", - path: Bundle.main.path(forResource: "cleanCache", ofType: "sh") ?? ""), + path: Bundle.main.path(forResource: "cleanCache", ofType: "sh") ?? "", savedId: -1 ), Script(name: "brewInGoinfre", description: "Brew download in goinfre", - path: Bundle.main.path(forResource: "brewInGoinfre", ofType: "sh") ?? "") + path: Bundle.main.path(forResource: "brewInGoinfre", ofType: "sh") ?? "", savedId: -1), + Script(name: "exportMacOSInfo", + description: "export setting MacOS Info", + path: Bundle.main.path(forResource: "exportMacOSInfo", ofType: "sh") ?? "", savedId: -1 ), + Script(name: "importMacOSInfo", + description: "import MacOS Info", + path: Bundle.main.path(forResource: "importMacOSInfo", ofType: "sh") ?? "", savedId: -1), + Script(name: "key Mapping", + description: "key Mapping", + path: Bundle.main.path(forResource: "keyMapping", ofType: "sh") ?? "", savedId: -1 ), + Script(name: "nodeInstall", + description: "node Install", + path: Bundle.main.path(forResource: "nodeInstall", ofType: "sh") ?? "", savedId: -1) ] } // Create func addScript(name: String, description: String, path: String) { - let newScript = Script(name: name, description: description, path: path) + let newScript = Script(name: name, description: description, path: path, savedId: -1) scripts.append(newScript) } // Read func excuteScript(id: UUID) { if let index = scripts.firstIndex(where: { $0.id == id }) { - ExcuteScripts.executeShellScript(path: scripts[index].name) +// ExecuteScripts.executeShellScript(path: scripts[index].name) + // MARK: - 파일스크립트 매니저에서 권한을 얻은 실행으로 실행합니다. + SecurityScopedResourceAccess.accessResourceExecuteShellScript(scriptPath: scripts[index].path) } } @@ -45,15 +61,21 @@ class ScriptViewModel: NSObject { // Delete func deleteScript(id: UUID) { + // delete 요청 보내야함 보내고 성공하면 지우기 scripts.removeAll(where: { $0.id == id }) QuickSlotViewModel.shared.removeButton(id) } + // 새로운 스크립트 배열로 교체하는 메서드 + func replaceScripts(with newScripts: [Script]) { + self.scripts = newScripts + } + + // 스크립트안에서 해당하는 스크립트를 찾아서 quickslotVM에 추가 func quickSlotScript(id: UUID) { if let index = scripts.firstIndex(where: { $0.id == id }) { let button = QuickSlotButtonModel(id: id, title: scripts[index].name, path: scripts[index].path) QuickSlotViewModel.shared.addButton(button) } } - } From de9df940b067b1f76558d3adb3ab5c9602f92ccd Mon Sep 17 00:00:00 2001 From: chanhihi Date: Thu, 31 Aug 2023 04:25:38 +0900 Subject: [PATCH 06/14] =?UTF-8?q?feat(API):=20=ED=94=84=EB=A1=A0=ED=8A=B8?= =?UTF-8?q?=EC=99=80=20=ED=86=B5=EC=8B=A0=EC=9D=84=20=EC=9C=84=ED=95=B4=20?= =?UTF-8?q?=EB=A9=94=EC=84=B8=EC=A7=80=EB=A5=BC=20=EB=93=B1=EB=A1=9D?= =?UTF-8?q?=ED=95=A9=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Box42/WebView/WebView.swift | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Box42/WebView/WebView.swift b/Box42/WebView/WebView.swift index 8e3e12e..80b8b3b 100644 --- a/Box42/WebView/WebView.swift +++ b/Box42/WebView/WebView.swift @@ -24,6 +24,7 @@ class WebView: WKWebView, WKScriptMessageHandler { contentController.add(self, name: WebViewUI.transfer.download) contentController.add(self, name: WebViewUI.transfer.icon) contentController.add(self, name: WebViewUI.transfer.userProfile) + contentController.add(self, name: WebViewUI.transfer.script) self.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true self.configuration.preferences.javaScriptEnabled = true @@ -57,10 +58,24 @@ extension WebView { do { let decoder = JSONDecoder() let userProfile = try decoder.decode(UserProfile.self, from: userProfileJson!) - print(userProfile.icon) UserManager.shared.updateUserProfile(newProfile: userProfile) + } catch { + print("JSON decoding failed: \(error)") + } + } + + if message.name == WebViewUI.transfer.script, let scriptString = message.body as? String { + let scriptJson = scriptString.data(using: .utf8) + + do { + let decoder = JSONDecoder() + let downScript = try decoder.decode(Script.self, from: scriptJson!) + print(downScript) + + + } catch { print("JSON decoding failed: \(error)") } From 6f1ded67df91cec36c62214ef8c95cef074056ec Mon Sep 17 00:00:00 2001 From: chanhihi Date: Thu, 31 Aug 2023 04:26:07 +0900 Subject: [PATCH 07/14] =?UTF-8?q?feat:=20=EC=95=B1=EC=8B=A4=ED=96=89?= =?UTF-8?q?=EC=8B=9C=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=EC=9D=B4=20=EB=90=98?= =?UTF-8?q?=EC=96=B4=EC=9E=88=EB=8B=A4=EB=A9=B4=20GET=EC=9A=94=EC=B2=AD?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=A0=80=EC=9E=A5=EB=90=9C=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=A6=BD=ED=8A=B8=20=EB=AA=A9=EB=A1=9D=EC=9D=84=20?= =?UTF-8?q?=EA=B0=80=EC=A0=B8=EC=98=B5=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Box42/Resources/AppDelegate.swift | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Box42/Resources/AppDelegate.swift b/Box42/Resources/AppDelegate.swift index 5555c9b..d674746 100644 --- a/Box42/Resources/AppDelegate.swift +++ b/Box42/Resources/AppDelegate.swift @@ -23,14 +23,16 @@ class AppDelegate: NSObject, NSApplicationDelegate { // alertAccessibility() // hotkey() - // storage.storageTimerEvent() +// storage.storageTimerEvent() _ = UserManager.shared _ = ScriptsLogicController.shared // MARK: - 유저데이터 동기화 -// WebViewManager.shared.getCookie() -// API.getUserProfile(WebViewManager.shared.getCookieWebKit) + WebViewManager.shared.getCookie() + API.getUserProfile(WebViewManager.shared.getCookieWebKit) _ = QuickSlotViewModel.shared + API.getUserMeScripts(WebViewManager.shared.getCookieWebKit) + _ = ScriptViewModel.shared } func applicationWillTerminate(_ aNotification: Notification) { From d0aa4f2cb6a3b0930684e5755735bf5c4143edde Mon Sep 17 00:00:00 2001 From: chanhihi Date: Thu, 31 Aug 2023 04:26:37 +0900 Subject: [PATCH 08/14] =?UTF-8?q?feat(API):=20=ED=94=84=EB=A1=A0=ED=8A=B8?= =?UTF-8?q?=EC=99=80=20=ED=86=B5=EC=8B=A0=EC=9D=84=20=EC=9C=84=ED=95=B4=20?= =?UTF-8?q?=EB=A9=94=EC=84=B8=EC=A7=80=EB=A5=BC=20=EB=93=B1=EB=A1=9D?= =?UTF-8?q?=ED=95=A9=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Box42/WebView/Model/WebViewUI.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Box42/WebView/Model/WebViewUI.swift b/Box42/WebView/Model/WebViewUI.swift index 50679a9..b3d5582 100644 --- a/Box42/WebView/Model/WebViewUI.swift +++ b/Box42/WebView/Model/WebViewUI.swift @@ -12,5 +12,6 @@ enum WebViewUI { static let download = "download" static let icon = "icon" static let userProfile = "userProfile" + static let script = "script" } } From dd09b09bbf6cb76309d414910ee6682d49564a32 Mon Sep 17 00:00:00 2001 From: chanhihi Date: Thu, 31 Aug 2023 04:30:39 +0900 Subject: [PATCH 09/14] =?UTF-8?q?feat(info):=20=EC=9B=90=ED=99=9C=ED=95=9C?= =?UTF-8?q?=20=EC=95=B1=20=EA=B5=AC=EB=8F=99=EC=9D=84=20=EC=9C=84=ED=95=B4?= =?UTF-8?q?=20=EC=9C=A0=EC=A0=80=20=EB=94=94=EB=A0=89=ED=86=A0=EB=A6=AC?= =?UTF-8?q?=EC=9D=98=20=EA=B6=8C=ED=95=9C=EC=9D=84=20=EC=9A=94=EC=B2=AD?= =?UTF-8?q?=ED=95=A9=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Box42/Resources/Info.plist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Box42/Resources/Info.plist b/Box42/Resources/Info.plist index 1520f65..59cd59d 100644 --- a/Box42/Resources/Info.plist +++ b/Box42/Resources/Info.plist @@ -2,6 +2,8 @@ + NSDocumentsFolderUsageDescription + 원활한 앱 구동을 위해 유저 디렉토리의 권한을 요청합니다. NSAppTransportSecurity NSAllowsArbitraryLoads From 1cbdebf81c3de4872bd7f2b653de7102a6dbb954 Mon Sep 17 00:00:00 2001 From: chanhihi Date: Thu, 31 Aug 2023 04:31:04 +0900 Subject: [PATCH 10/14] =?UTF-8?q?refact:=20NSViewController=EC=9D=84=20?= =?UTF-8?q?=EA=B7=9C=EA=B2=A9=EC=97=90=20=EB=A7=9E=EA=B2=8C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=ED=95=A9=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PreferencesViewController.swift | 34 +++---------------- 1 file changed, 4 insertions(+), 30 deletions(-) diff --git a/Box42/Preferences/Controller/PreferencesViewController.swift b/Box42/Preferences/Controller/PreferencesViewController.swift index 1fede64..7dc8692 100644 --- a/Box42/Preferences/Controller/PreferencesViewController.swift +++ b/Box42/Preferences/Controller/PreferencesViewController.swift @@ -9,30 +9,21 @@ import Cocoa import SnapKit class PreferencesViewController: NSViewController { - var prefTableView : NSTableView? + var prefTableView : PreferencesTableView? override func loadView() { self.view = NSView() self.view.wantsLayer = true self.view.layer?.backgroundColor = NSColor.blue.cgColor - prefTableView = NSTableView(frame: .zero) - // Column 추가 - let column1 = NSTableColumn(identifier: NSUserInterfaceItemIdentifier("Column1")) - column1.width = 100.0 - column1.title = "Column 1" - prefTableView?.addTableColumn(column1) + prefTableView = PreferencesTableView(frame: .zero) + prefTableView?.setup() +// prefTableView?.viewModel = viewModel - // delegate와 dataSource 설정 - prefTableView?.delegate = self - prefTableView?.dataSource = self - - // TableView를 스크롤 뷰에 추가 (일반적으로 NSTableView는 NSScrollView 안에 위치합니다) let scrollView = NSScrollView() scrollView.documentView = prefTableView self.view.addSubview(scrollView) - scrollView.snp.makeConstraints({ make in make.edges.equalToSuperview() }) @@ -42,20 +33,3 @@ class PreferencesViewController: NSViewController { }) } } - -extension PreferencesViewController: NSTableViewDelegate, NSTableViewDataSource { - func numberOfRows(in tableView: NSTableView) -> Int { - return 10 // 총 로우 수 - } - - func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { - let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier("MyCell"), owner: self) as? NSTableCellView ?? NSTableCellView() - cell.textField?.stringValue = "Row \(row), Column \(tableColumn?.identifier ?? NSUserInterfaceItemIdentifier(""))" - return cell - } - - func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat { - return 44.0 // 셀 높이를 44로 설정 - } -} - From 58b4854a805791beeb2bbd344f891f8c0156a108 Mon Sep 17 00:00:00 2001 From: chanhihi Date: Thu, 31 Aug 2023 04:31:25 +0900 Subject: [PATCH 11/14] =?UTF-8?q?feat:=20=ED=85=8C=EC=9D=B4=EB=B8=94?= =?UTF-8?q?=EB=B7=B0=EB=A5=BC=20=EC=B6=94=EA=B0=80=ED=95=A9=EB=8B=88?= =?UTF-8?q?=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/PreferencesTableView.swift | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 Box42/Preferences/View/PreferencesTableView.swift diff --git a/Box42/Preferences/View/PreferencesTableView.swift b/Box42/Preferences/View/PreferencesTableView.swift new file mode 100644 index 0000000..5186bf1 --- /dev/null +++ b/Box42/Preferences/View/PreferencesTableView.swift @@ -0,0 +1,78 @@ +// +// PreferencesTableView.swift +// Box42 +// +// Created by Chanhee Kim on 8/31/23. +// + +import AppKit +import SnapKit +import Combine + +enum PreferencesCellList: Int, CaseIterable { + case requestAccessView = 1 + case cpu = 2 + case my = 3 + + var height: CGFloat { + switch self { + case .requestAccessView: + return 60.0 + case .cpu: + return 40.0 + case .my: + return 50.0 + } + } +} + +class PreferencesTableView: NSTableView { + let requestAccessView = RequestAccessView() + + func setup() { + self.delegate = self + self.dataSource = self + + let column1 = NSTableColumn(identifier: NSUserInterfaceItemIdentifier("Preferences")) + column1.width = 100.0 + column1.title = "Preferences" + self.addTableColumn(column1) + } + +} + +extension PreferencesTableView: NSTableViewDelegate, NSTableViewDataSource { + func getCellForRow(at row: Int) -> NSView { + let allCases = PreferencesCellList.allCases + if row >= 0 && row < allCases.count { + switch allCases[row] { + case .requestAccessView: + return requestAccessView + case .cpu: + // Return the view for the CPU cell + return NSView() // Placeholder + case .my: + // Return the view for the "my" cell + return NSView() // Placeholder + } + } + return NSView() // Default view if out of bounds or undefined + } + + func numberOfRows(in tableView: NSTableView) -> Int { + return PreferencesCellList.allCases.count + } + + func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { + return getCellForRow(at: row) + } + + func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat { + let allCases = PreferencesCellList.allCases + if row >= 0 && row < allCases.count { + return allCases[row].height + } + + return 44.0 // Default height + } +} From f10d1c24a564e94980a8f32f441efbe58d9e5057 Mon Sep 17 00:00:00 2001 From: chanhihi Date: Thu, 31 Aug 2023 04:36:21 +0900 Subject: [PATCH 12/14] =?UTF-8?q?feat:=20=EA=B6=8C=ED=95=9C=EC=9D=84=20?= =?UTF-8?q?=EB=B0=9B=EB=8A=94=20=ED=85=8C=EC=9D=B4=EB=B8=94=20=EC=85=80?= =?UTF-8?q?=EC=9D=84=20=EC=B6=94=EA=B0=80=ED=95=A9=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/PreferencesTableView.swift | 2 +- .../Preferences/View/RequestAccessView.swift | 136 ++++++++++++++++++ 2 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 Box42/Preferences/View/RequestAccessView.swift diff --git a/Box42/Preferences/View/PreferencesTableView.swift b/Box42/Preferences/View/PreferencesTableView.swift index 5186bf1..e4b862a 100644 --- a/Box42/Preferences/View/PreferencesTableView.swift +++ b/Box42/Preferences/View/PreferencesTableView.swift @@ -17,7 +17,7 @@ enum PreferencesCellList: Int, CaseIterable { var height: CGFloat { switch self { case .requestAccessView: - return 60.0 + return 100.0 case .cpu: return 40.0 case .my: diff --git a/Box42/Preferences/View/RequestAccessView.swift b/Box42/Preferences/View/RequestAccessView.swift new file mode 100644 index 0000000..0062579 --- /dev/null +++ b/Box42/Preferences/View/RequestAccessView.swift @@ -0,0 +1,136 @@ +// +// RequestAccessView.swift +// Box42 +// +// Created by Chanhee Kim on 8/31/23. +// + +import AppKit +import SnapKit + +class RequestAccessView: NSView { + var requestAccessTextField: NSTextField = NSTextField() + var grantAccessButton: NSButton = NSButton() + var revokeAccessButton: NSButton = NSButton() + var directoryNameTextField: NSTextField = NSTextField() + + override init(frame frameRect: NSRect) { + super.init(frame: .zero) + self.wantsLayer = true + self.layer?.backgroundColor = NSColor(hex: "#7FFFFFFF").cgColor + self.layer?.cornerRadius = 13 + + // Add subviews + self.addSubview(requestAccessTextField) + self.addSubview(grantAccessButton) + self.addSubview(revokeAccessButton) + self.addSubview(directoryNameTextField) + + // Initialize UI elements + textfieldInit() + buttonInit() + directoryNameTextFieldInit() + + // Set constraints + textfieldConstraints() + buttonConstraints() + directoryNameTextFieldConstraints() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func textfieldInit() { + requestAccessTextField.stringValue = "Script 및 기능들을 실행하기 위해서 루트 디렉토리의 권한이 필요합니다." + requestAccessTextField.font = NSFont.systemFont(ofSize: 15) + requestAccessTextField.isEditable = false + requestAccessTextField.isBordered = false + requestAccessTextField.backgroundColor = NSColor.clear + requestAccessTextField.lineBreakMode = .byWordWrapping + requestAccessTextField.maximumNumberOfLines = 3 + } + + func buttonInit() { + grantAccessButton.title = "권한 부여" + grantAccessButton.target = self + grantAccessButton.action = #selector(requestFolderAccess(_:)) + + revokeAccessButton.title = "권한 취소" + revokeAccessButton.target = self + revokeAccessButton.action = #selector(revokeFolderAccess(_:)) + } + + func directoryNameTextFieldInit() { + directoryNameTextField.stringValue = "선택된 디렉터리: 없음" + directoryNameTextField.font = NSFont.systemFont(ofSize: 15) + directoryNameTextField.isEditable = false + directoryNameTextField.isBordered = false + directoryNameTextField.backgroundColor = NSColor.clear + directoryNameTextField.lineBreakMode = .byWordWrapping + } + + func directoryNameTextFieldConstraints() { + directoryNameTextField.snp.makeConstraints { make in + make.top.equalTo(revokeAccessButton.snp.bottom).offset(10) + make.leading.equalToSuperview().offset(17) + make.trailing.equalToSuperview().offset(-17) + } + } + + func textfieldConstraints() { + requestAccessTextField.snp.makeConstraints { make in + make.top.equalToSuperview().offset(10) + make.leading.equalToSuperview().offset(17) + make.trailing.equalToSuperview().offset(-17) + } + } + + func buttonConstraints() { + grantAccessButton.snp.makeConstraints { make in + make.top.equalTo(requestAccessTextField.snp.bottom).offset(10) + make.leading.equalToSuperview().offset(17) + } + + revokeAccessButton.snp.makeConstraints { make in + make.top.equalTo(requestAccessTextField.snp.bottom).offset(10) + make.leading.equalTo(grantAccessButton.snp.trailing).offset(10) + } + } + + @objc func requestFolderAccess(_ sender: NSButton) { + let openPanel = NSOpenPanel() + openPanel.title = "Choose a folder" + openPanel.showsResizeIndicator = true + openPanel.showsHiddenFiles = false + openPanel.canChooseDirectories = true + openPanel.canCreateDirectories = true + openPanel.allowsMultipleSelection = false + openPanel.canChooseFiles = false + + if openPanel.runModal() == NSApplication.ModalResponse.OK { + let result = openPanel.url + + if let result = result { + print("Selected folder is \(result.path)") + + directoryNameTextField.stringValue = "선택된 디렉터리: \(result.path)" + + do { + let bookmarkData = try result.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil) + UserDefaults.standard.set(bookmarkData, forKey: "bookmarkData") + } catch { + print("Error creating bookmark: \(error)") + } + } + } else { + // User clicked on "Cancel" + return + } + } + + @objc func revokeFolderAccess(_ sender: NSButton) { + // TODO: Add code to revoke folder access + } + +} From ad34298c408cfa3b27aaead3d6f55451e5c847b2 Mon Sep 17 00:00:00 2001 From: chanhihi Date: Thu, 31 Aug 2023 04:37:16 +0900 Subject: [PATCH 13/14] =?UTF-8?q?feat:=20=EC=96=BB=EC=9D=80=20=EA=B6=8C?= =?UTF-8?q?=ED=95=9C=EC=9C=BC=EB=A1=9C=20=EC=8B=A4=ED=96=89=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EB=A1=9C=EC=A7=81=EC=9D=84=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=ED=95=A9=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../QuickSlotScriptsLogicController.swift | 2 +- .../ViewModel/QuickSlotViewModel.swift | 5 +- .../Controller/ScriptsFileManager.swift | 5 +- .../Shared/SecurityScopedResourceAccess.swift | 59 +++++++++++++++++++ 4 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 Box42/Shared/SecurityScopedResourceAccess.swift diff --git a/Box42/QuickSlot/Controller/QuickSlotScriptsLogicController.swift b/Box42/QuickSlot/Controller/QuickSlotScriptsLogicController.swift index 517a789..6c2ada1 100644 --- a/Box42/QuickSlot/Controller/QuickSlotScriptsLogicController.swift +++ b/Box42/QuickSlot/Controller/QuickSlotScriptsLogicController.swift @@ -17,7 +17,7 @@ class ScriptsLogicController { @objc func handleButtonTapped(notification: NSNotification) { if let button = notification.object as? NSButton { - ExcuteScripts.executeShellScript(path: button.associatedString ?? "") + SecurityScopedResourceAccess.accessResourceExecuteShellScript(scriptPath: button.associatedString ?? "") } } diff --git a/Box42/QuickSlot/ViewModel/QuickSlotViewModel.swift b/Box42/QuickSlot/ViewModel/QuickSlotViewModel.swift index 0d16006..d636599 100644 --- a/Box42/QuickSlot/ViewModel/QuickSlotViewModel.swift +++ b/Box42/QuickSlot/ViewModel/QuickSlotViewModel.swift @@ -13,7 +13,8 @@ class QuickSlotViewModel { @Published var buttons: [QuickSlotButtonModel] = [] private init() { - let button1 = QuickSlotButtonModel(title: QuickSlotUI.title.clean) + let button1 = QuickSlotButtonModel(title: QuickSlotUI.title.clean, + path: Bundle.main.path(forResource: "cleanCache", ofType: "sh")) let button2 = QuickSlotButtonModel(title: QuickSlotUI.title.preferences) let button3 = QuickSlotButtonModel(title: QuickSlotUI.title.scripts) let button4 = QuickSlotButtonModel(title: QuickSlotUI.title.user) @@ -21,8 +22,8 @@ class QuickSlotViewModel { buttons = [button1, button2, button3, button4] } + // 퀵슬롯 안에 해당 버튼이 없으면 추가 func addButton(_ button: QuickSlotButtonModel) { - if buttons.count > 7 { return } if !buttons.contains(where: { $0.id == button.id }) { buttons.append(button) } diff --git a/Box42/Scripts/Controller/ScriptsFileManager.swift b/Box42/Scripts/Controller/ScriptsFileManager.swift index 5b4c69f..7cae68f 100644 --- a/Box42/Scripts/Controller/ScriptsFileManager.swift +++ b/Box42/Scripts/Controller/ScriptsFileManager.swift @@ -16,7 +16,7 @@ class ScriptsFileManager { if let savedURL = savedURL, fileManager.fileExists(atPath: savedURL.path) { print("File already exists, executing...") - ExcuteScripts.executeShellScript(path: savedURL.path) + SecurityScopedResourceAccess.accessResourceExecuteShellScript(scriptPath: savedURL.path) return } @@ -37,8 +37,7 @@ class ScriptsFileManager { try fileManager.moveItem(at: location, to: savedURL) print("Saved URL: ", savedURL) - - ExcuteScripts.executeShellScript(path: savedURL.path) + SecurityScopedResourceAccess.accessResourceExecuteShellScript(scriptPath: savedURL.path) } catch { print("File error: \(error)") diff --git a/Box42/Shared/SecurityScopedResourceAccess.swift b/Box42/Shared/SecurityScopedResourceAccess.swift new file mode 100644 index 0000000..a919d15 --- /dev/null +++ b/Box42/Shared/SecurityScopedResourceAccess.swift @@ -0,0 +1,59 @@ +// +// SecurityScopedResourceAccess.swift +// Box42 +// +// Created by Chanhee Kim on 8/31/23. +// + +import Foundation + +class SecurityScopedResourceAccess { + private static let queue = DispatchQueue(label: "com.yourApp.securityAccessQueue", attributes: .concurrent) + private static var isAccessing = false + static var bookmarkData: Data? { + get { + return UserDefaults.standard.data(forKey: "bookmarkData") + } + set { + UserDefaults.standard.set(newValue, forKey: "bookmarkData") + } + } + + static func accessResourceExecuteShellScript(scriptPath: String) { + queue.async(flags: .barrier) { + var url: URL? = nil // 이 부분을 추가하여 url 변수의 스코프를 확장합니다. + do { + var staleBookmarkData = false + guard let bookmarkData = self.bookmarkData else { + print("Bookmark data not available.") + return + } + + print("Stored bookmark data: \(String(describing: UserDefaults.standard.data(forKey: "bookmarkData")))") + + + url = try URL(resolvingBookmarkData: bookmarkData, options: .withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &staleBookmarkData) + + if staleBookmarkData { + // Refresh the bookmark data and save it. + } + + isAccessing = url?.startAccessingSecurityScopedResource() ?? false + + // Perform work here + if isAccessing { + ExecuteScripts.executeShellScript(path: scriptPath) + } + + } catch { + print("An error occurred: \(error)") + } + + // Cleanup + if isAccessing { + // Make sure to match this with a call to startAccessingSecurityScopedResource() + url?.stopAccessingSecurityScopedResource() + } + } + } +} From a2095a9230679ba692f828ebf5d2355cf5c895d3 Mon Sep 17 00:00:00 2001 From: KIM CHAN HEE <85754295+chanhihi@users.noreply.github.com> Date: Thu, 31 Aug 2023 04:58:18 +0900 Subject: [PATCH 14/14] =?UTF-8?q?feat:=20stroage=20=EA=B4=80=EB=A0=A8=20UI?= =?UTF-8?q?=20view=EB=A5=BC=20=EC=B6=94=EA=B0=80=ED=95=A9=EB=8B=88?= =?UTF-8?q?=EB=8B=A4.=20(#113)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: storage view를 추가합니다. * chore: 파일구조를 변경합니다. --- Box42.xcodeproj/project.pbxproj | 26 +++- ...yDown+BoxBaseContainerViewController.swift | 4 + .../{ => Funtion}/RequestAccessView.swift | 0 .../View/Funtion/StorageView.swift | 112 ++++++++++++++++++ .../View/{ => Table}/PreferencesCell.swift | 0 .../{ => Table}/PreferencesTableView.swift | 16 ++- 6 files changed, 151 insertions(+), 7 deletions(-) rename Box42/Preferences/View/{ => Funtion}/RequestAccessView.swift (100%) create mode 100644 Box42/Preferences/View/Funtion/StorageView.swift rename Box42/Preferences/View/{ => Table}/PreferencesCell.swift (100%) rename Box42/Preferences/View/{ => Table}/PreferencesTableView.swift (86%) diff --git a/Box42.xcodeproj/project.pbxproj b/Box42.xcodeproj/project.pbxproj index cf1c784..f2eb8dd 100644 --- a/Box42.xcodeproj/project.pbxproj +++ b/Box42.xcodeproj/project.pbxproj @@ -97,6 +97,7 @@ DE9457312A9FB01400B0B768 /* PreferencesTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9457302A9FB01400B0B768 /* PreferencesTableView.swift */; }; DE9457342A9FB1D300B0B768 /* RequestAccessView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9457332A9FB1D300B0B768 /* RequestAccessView.swift */; }; DE9457372A9FC0A800B0B768 /* SecurityScopedResourceAccess.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9457362A9FC0A800B0B768 /* SecurityScopedResourceAccess.swift */; }; + DE94573D2A9FD33400B0B768 /* StorageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE94573C2A9FD33400B0B768 /* StorageView.swift */; }; DE97CA692A9A6364001073DE /* PixelConversion+CGFloat.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE97CA682A9A6364001073DE /* PixelConversion+CGFloat.swift */; }; DE97CA792A9A6F6A001073DE /* QuickSlotHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE97CA782A9A6F6A001073DE /* QuickSlotHeaderView.swift */; }; DE97CA7C2A9A7199001073DE /* QuickSlotGroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE97CA7B2A9A7199001073DE /* QuickSlotGroupView.swift */; }; @@ -207,6 +208,7 @@ DE9457302A9FB01400B0B768 /* PreferencesTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesTableView.swift; sourceTree = ""; }; DE9457332A9FB1D300B0B768 /* RequestAccessView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestAccessView.swift; sourceTree = ""; }; DE9457362A9FC0A800B0B768 /* SecurityScopedResourceAccess.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityScopedResourceAccess.swift; sourceTree = ""; }; + DE94573C2A9FD33400B0B768 /* StorageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageView.swift; sourceTree = ""; }; DE97CA682A9A6364001073DE /* PixelConversion+CGFloat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PixelConversion+CGFloat.swift"; sourceTree = ""; }; DE97CA6E2A9A6EFC001073DE /* QuickSlotViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickSlotViewModel.swift; sourceTree = ""; }; DE97CA712A9A6F0D001073DE /* QuickSlotButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickSlotButtonModel.swift; sourceTree = ""; }; @@ -522,9 +524,8 @@ DE78862B2A9D1A9E00FE21DD /* View */ = { isa = PBXGroup; children = ( - DE78862C2A9D1ADE00FE21DD /* PreferencesCell.swift */, - DE9457302A9FB01400B0B768 /* PreferencesTableView.swift */, - DE9457332A9FB1D300B0B768 /* RequestAccessView.swift */, + DE9457412A9FD69800B0B768 /* Table */, + DE94573F2A9FD68C00B0B768 /* Funtion */, ); path = View; sourceTree = ""; @@ -589,6 +590,24 @@ path = Table; sourceTree = ""; }; + DE94573F2A9FD68C00B0B768 /* Funtion */ = { + isa = PBXGroup; + children = ( + DE9457332A9FB1D300B0B768 /* RequestAccessView.swift */, + DE94573C2A9FD33400B0B768 /* StorageView.swift */, + ); + path = Funtion; + sourceTree = ""; + }; + DE9457412A9FD69800B0B768 /* Table */ = { + isa = PBXGroup; + children = ( + DE78862C2A9D1ADE00FE21DD /* PreferencesCell.swift */, + DE9457302A9FB01400B0B768 /* PreferencesTableView.swift */, + ); + path = Table; + sourceTree = ""; + }; DE98E8382A98D48700F8744A /* QuickSlot */ = { isa = PBXGroup; children = ( @@ -853,6 +872,7 @@ DE97CA862A9A7404001073DE /* QuickSlotViewModel.swift in Sources */, DE3FF3762A978AB8009C88EF /* WindowCloseButton.swift in Sources */, DE9457092A9E69D100B0B768 /* ScriptDescriptionsLabel.swift in Sources */, + DE94573D2A9FD33400B0B768 /* StorageView.swift in Sources */, DE9457282A9F6E4400B0B768 /* GetUserMeScripts.swift in Sources */, DE77BBD22A9E0AE8006CC98B /* WebViewUI.swift in Sources */, DE3FF3772A978AB8009C88EF /* WindowMinimizeButton.swift in Sources */, diff --git a/Box42/Main/keyDown+BoxBaseContainerViewController.swift b/Box42/Main/keyDown+BoxBaseContainerViewController.swift index f16fcfc..f73306a 100644 --- a/Box42/Main/keyDown+BoxBaseContainerViewController.swift +++ b/Box42/Main/keyDown+BoxBaseContainerViewController.swift @@ -22,6 +22,10 @@ extension BoxBaseContainerViewController { StorageConfig.shared.setPeriod(.period1s) } + if event.modifierFlags.contains(.command) && event.keyCode == 15 { + print("Cmd + R pressed, reloading...") + WebViewManager.shared.hostingWebView?.reload() + } if event.keyCode == 53 { // Escape 키의 keyCode는 53입니다. print("escape") diff --git a/Box42/Preferences/View/RequestAccessView.swift b/Box42/Preferences/View/Funtion/RequestAccessView.swift similarity index 100% rename from Box42/Preferences/View/RequestAccessView.swift rename to Box42/Preferences/View/Funtion/RequestAccessView.swift diff --git a/Box42/Preferences/View/Funtion/StorageView.swift b/Box42/Preferences/View/Funtion/StorageView.swift new file mode 100644 index 0000000..77650b6 --- /dev/null +++ b/Box42/Preferences/View/Funtion/StorageView.swift @@ -0,0 +1,112 @@ +// +// StorageView.swift +// Box42 +// +// Created by Chanhee Kim on 8/31/23. +// +import AppKit +import SnapKit + +class StorageView: NSView { + + var currentStorageTextField: NSTextField = NSTextField() + var remainingStorageTextField: NSTextField = NSTextField() + var totalStorageTextField: NSTextField = NSTextField() + var thresholdTextField: NSTextField = NSTextField() + var intervalTextField: NSTextField = NSTextField() + var executeScriptButton: NSButton = NSButton() + + override init(frame frameRect: NSRect) { + super.init(frame: frameRect) + + // Add subviews + addSubview(currentStorageTextField) + addSubview(remainingStorageTextField) + addSubview(totalStorageTextField) + addSubview(thresholdTextField) + addSubview(intervalTextField) + addSubview(executeScriptButton) + + // Initialize UI elements + initTextFields() + initButton() + + // Set constraints + setConstraints() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func initTextFields() { + // Initialize textfields + currentStorageTextField.stringValue = "Current Storage: ?? GB" + remainingStorageTextField.stringValue = "Remaining Storage: ?? GB" + totalStorageTextField.stringValue = "Total Storage: ?? GB" + thresholdTextField.placeholderString = "Enter threshold (%)" + intervalTextField.placeholderString = "Enter interval (seconds)" + + [currentStorageTextField, remainingStorageTextField, totalStorageTextField, thresholdTextField, intervalTextField].forEach { textField in + textField.isEditable = false + textField.isBordered = false + textField.backgroundColor = NSColor.clear + } + + intervalTextField.isEditable = true + thresholdTextField.isEditable = true + } + + func initButton() { + executeScriptButton.title = "Run Script" + executeScriptButton.target = self + executeScriptButton.action = #selector(runScript(_:)) + } + + func setConstraints() { + // Use SnapKit to set constraints + currentStorageTextField.snp.makeConstraints { make in + make.top.leading.equalToSuperview().offset(20) + } + + remainingStorageTextField.snp.makeConstraints { make in + make.top.equalTo(currentStorageTextField.snp.bottom).offset(10) + make.leading.equalToSuperview().offset(20) + } + + totalStorageTextField.snp.makeConstraints { make in + make.top.equalTo(remainingStorageTextField.snp.bottom).offset(10) + make.leading.equalToSuperview().offset(20) + } + + thresholdTextField.snp.makeConstraints { make in + make.top.equalTo(totalStorageTextField.snp.bottom).offset(10) + make.leading.equalToSuperview().offset(20) + make.height.equalTo(30) + make.width.equalTo(100) + } + + intervalTextField.snp.makeConstraints { make in + make.top.equalTo(thresholdTextField.snp.bottom).offset(10) + make.leading.equalToSuperview().offset(20) + make.height.equalTo(30) + make.width.equalTo(100) + } + + executeScriptButton.snp.makeConstraints { make in + make.top.equalTo(intervalTextField.snp.bottom).offset(20) + make.leading.equalToSuperview().offset(20) + } + } + + @objc func runScript(_ sender: NSButton) { + // Logic to run script + } + + // Update storage information + func updateStorageInfo(current: String, remaining: String, total: String) { + currentStorageTextField.stringValue = "Current Storage: \(current) GB" + remainingStorageTextField.stringValue = "Remaining Storage: \(remaining) GB" + totalStorageTextField.stringValue = "Total Storage: \(total) GB" + } +} diff --git a/Box42/Preferences/View/PreferencesCell.swift b/Box42/Preferences/View/Table/PreferencesCell.swift similarity index 100% rename from Box42/Preferences/View/PreferencesCell.swift rename to Box42/Preferences/View/Table/PreferencesCell.swift diff --git a/Box42/Preferences/View/PreferencesTableView.swift b/Box42/Preferences/View/Table/PreferencesTableView.swift similarity index 86% rename from Box42/Preferences/View/PreferencesTableView.swift rename to Box42/Preferences/View/Table/PreferencesTableView.swift index e4b862a..2c0ec06 100644 --- a/Box42/Preferences/View/PreferencesTableView.swift +++ b/Box42/Preferences/View/Table/PreferencesTableView.swift @@ -9,15 +9,18 @@ import AppKit import SnapKit import Combine -enum PreferencesCellList: Int, CaseIterable { - case requestAccessView = 1 - case cpu = 2 - case my = 3 +enum PreferencesCellList: CaseIterable { + case requestAccessView + case storage + case cpu + case my var height: CGFloat { switch self { case .requestAccessView: return 100.0 + case .storage: + return 300.0 case .cpu: return 40.0 case .my: @@ -28,6 +31,7 @@ enum PreferencesCellList: Int, CaseIterable { class PreferencesTableView: NSTableView { let requestAccessView = RequestAccessView() + let storageView = StorageView() func setup() { self.delegate = self @@ -37,6 +41,8 @@ class PreferencesTableView: NSTableView { column1.width = 100.0 column1.title = "Preferences" self.addTableColumn(column1) + + self.selectionHighlightStyle = .none } } @@ -48,6 +54,8 @@ extension PreferencesTableView: NSTableViewDelegate, NSTableViewDataSource { switch allCases[row] { case .requestAccessView: return requestAccessView + case .storage: + return StorageView() case .cpu: // Return the view for the CPU cell return NSView() // Placeholder