diff --git a/Box42/Box/BoxButtonHandler.swift b/Box42/Box/BoxButtonHandler.swift new file mode 100644 index 0000000..f79d076 --- /dev/null +++ b/Box42/Box/BoxButtonHandler.swift @@ -0,0 +1,16 @@ +// +// BoxButtonHandler.swift +// Box42 +// +// Created by Chanhee Kim on 8/11/23. +// + +import Cocoa + +class BoxButtonHandler { + var clickAction: ((NSButton) -> Void)? + + @objc func buttonClicked(_ sender: NSButton) { + clickAction?(sender) + } +} diff --git a/Box42/Box/BoxController.swift b/Box42/Box/BoxController.swift deleted file mode 100644 index 5d9cfc9..0000000 --- a/Box42/Box/BoxController.swift +++ /dev/null @@ -1,275 +0,0 @@ -// -// BoxViewController.swift -// Box42 -// -// Created by Chan on 2023/03/16. -// - -import Cocoa -import AppKit -import WebKit - -class BoxController: NSViewController, WKScriptMessageHandler, WKUIDelegate, WKNavigationDelegate { - var ad = NSApplication.shared.delegate as? AppDelegate - let url = URLModel() - var wvc = WebViewController() - let preferencesVC = PreferencesViewController() - - var topAnchorDistance: CGFloat = 0 - - @IBOutlet var divider: NSBox! - @IBOutlet weak var boxView: NSView! - @IBOutlet weak var buttonViewGroup: NSView! - @IBOutlet weak var hostingViewGroup: NSView! - @IBOutlet var pinSwitch: NSSwitch! - - private var webView: WKWebView! - private var buttonBoxGroup: NSView! - - override func keyDown(with event: NSEvent) { - print(event.keyCode) - if event.keyCode == 53 { // Escape 키의 keyCode는 53입니다. - print("escape") - } else { - super.keyDown(with: event) // 기타 키를 처리하기 위해 상위 클래스에게 전달 - } - - if (event.modifierFlags.contains(.command) && event.charactersIgnoringModifiers == "c") || - (event.modifierFlags.contains(.command) && event.charactersIgnoringModifiers == "ㅊ") { - // 복사 동작 처리 - webView.evaluateJavaScript("document.execCommand('copy')") { (_, error) in - if let error = error { - print("Copy error: \(error)") - } else { - print("Copy success") - } - } - } else if (event.modifierFlags.contains(.command) && event.charactersIgnoringModifiers == "v") || - (event.modifierFlags.contains(.command) && event.charactersIgnoringModifiers == "ㅍ") { - // 붙여넣기 동작 처리 - let pasteboard = NSPasteboard.general - if let pasteString = pasteboard.string(forType: .string) { - let escapedPasteString = pasteString.escapedForJavaScript - webView.evaluateJavaScript("document.execCommand('insertText', false, '\(escapedPasteString)')") { (_, error) in - if let error = error { - print("Paste error: \(error)") - } else { - print("Paste success") - } - } - } - } else { - super.keyDown(with: event) // 기본 키 이벤트 처리 - } - } - - override func viewDidLoad() { - view.window?.makeFirstResponder(self) - super.viewDidLoad() - buttonBoxGroupInit() - boxViewSizeInit() - webViewInit() - wvc.loadWebViewInit() - configureButton() - } - - func createButton(_ title :String) { - let button = NSButton() - - button.title = title - button.setButtonType(.momentaryLight) - - button.translatesAutoresizingMaskIntoConstraints = false - button.action = #selector(self.clickBtn(sender:)) - - button.isBordered = true - button.bezelStyle = .roundRect - button.showsBorderOnlyWhileMouseInside = true - - buttonBoxGroup.addSubview(button) - - button.leadingAnchor.constraint(equalTo: buttonBoxGroup.leadingAnchor, constant: 20).isActive = true - button.topAnchor.constraint(equalTo: buttonBoxGroup.topAnchor, constant: topAnchorDistance).isActive = true - topAnchorDistance += 30 - button.trailingAnchor.constraint(equalTo: buttonBoxGroup.trailingAnchor, constant: -20).isActive = true - } - - func createHomeButton() { - let button = NSButton(title: "home", image: NSImage(imageLiteralResourceName: "42box_logo"), target: (Any).self, action: #selector(self.clickBtn(sender:))) - button.translatesAutoresizingMaskIntoConstraints = false - button.isBordered = false - button.imagePosition = .imageOnly - - buttonBoxGroup.addSubview(button) - - button.leadingAnchor.constraint(equalTo: buttonBoxGroup.leadingAnchor, constant: 20).isActive = true - button.topAnchor.constraint(equalTo: buttonBoxGroup.topAnchor, constant: topAnchorDistance).isActive = true - topAnchorDistance += 80 - button.trailingAnchor.constraint(equalTo: buttonBoxGroup.trailingAnchor, constant: -20).isActive = true - } - - func createQuitButton() { - let button = NSButton() - button.title = "Quit Box" - button.setButtonType(.momentaryLight) - - button.translatesAutoresizingMaskIntoConstraints = false - button.action = #selector(NSApplication.terminate(_:)) - button.isBordered = true - button.bezelStyle = .roundRect - button.showsBorderOnlyWhileMouseInside = true - - buttonBoxGroup.addSubview(button) - - button.leadingAnchor.constraint(equalTo: buttonBoxGroup.leadingAnchor, constant: 20).isActive = true - button.bottomAnchor.constraint(equalTo: buttonBoxGroup.bottomAnchor, constant: -10).isActive = true - button.trailingAnchor.constraint(equalTo: buttonBoxGroup.trailingAnchor, constant: -20).isActive = true - } - - func divide() { - divider.translatesAutoresizingMaskIntoConstraints = false - divider.bottomAnchor.constraint(equalTo: buttonBoxGroup.bottomAnchor, constant: -40).isActive = true - } - - func createPinButton() { - let button = NSButton() - button.title = "Pin Box" - button.setButtonType(.toggle) - button.contentTintColor = .orange - button.translatesAutoresizingMaskIntoConstraints = false - button.action = #selector(self.pin) - button.isBordered = true - button.bezelStyle = .roundRect - button.showsBorderOnlyWhileMouseInside = true - - buttonBoxGroup.addSubview(button) - - button.leadingAnchor.constraint(equalTo: buttonBoxGroup.leadingAnchor, constant: 20).isActive = true - button.bottomAnchor.constraint(equalTo: buttonBoxGroup.bottomAnchor, constant: -50).isActive = true - button.trailingAnchor.constraint(equalTo: buttonBoxGroup.trailingAnchor, constant: -20).isActive = true - } - - func preferencesButton() { - let button = NSButton() - button.title = "Preferences" - button.setButtonType(.momentaryLight) - - button.translatesAutoresizingMaskIntoConstraints = false - button.action = #selector(self.clickBtn(sender:)) - button.isBordered = true - button.bezelStyle = .roundRect - button.showsBorderOnlyWhileMouseInside = true - - buttonBoxGroup.addSubview(button) - - button.leadingAnchor.constraint(equalTo: buttonBoxGroup.leadingAnchor, constant: 20).isActive = true - button.bottomAnchor.constraint(equalTo: buttonBoxGroup.bottomAnchor, constant: -90).isActive = true - button.trailingAnchor.constraint(equalTo: buttonBoxGroup.trailingAnchor, constant: -20).isActive = true - } - - func configureButton() { - createHomeButton() - for i in 1.. 2 { - let rqURL = URLRequest(url: URLModel().URLdict[sender.title]!) - WebViewList.shared.list[sender.title]!.load(rqURL) - print("Triple Click") - } else if clickCount < 2 { - hostingViewGroup.subviews.removeAll() - hostingViewGroup.addSubview(WebViewList.shared.list[sender.title]!) - WebViewList.shared.list[sender.title]!.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true - WebViewList.shared.list[sender.title]!.configuration.preferences.javaScriptEnabled = true - WebViewList.shared.list[sender.title]?.viewDidMoveToSuperview() - setAutoLayout(from: WebViewList.shared.list[sender.title]!, to: hostingViewGroup) - } - } - - @objc - func pin(_ sender: NSSwitch) { - StateManager.shared.isPin.toggle() - print(sender.state) - } - - func boxViewSizeInit() { - boxView.frame.size.width = BoxViewSize().size.width - boxView.frame.size.height = BoxViewSize().size.height - - hostingViewGroup.frame.size.width = BoxViewSize().size.width - BoxViewSize().buttonGroupSize.width - hostingViewGroup.frame.size.height = BoxViewSize().size.height - - buttonViewGroup.frame.size.width = BoxViewSize().buttonGroupSize.width - buttonViewGroup.frame.size.height = BoxViewSize().buttonGroupSize.height - } - - func buttonBoxGroupInit() { - buttonBoxGroup = NSView(frame: NSRect(x: 0, y: 0, width: BoxViewSize().buttonGroupSize.width, height: BoxViewSize().buttonGroupSize.height)) - buttonBoxGroup.frame.size.width = BoxViewSize().buttonGroupSize.width - buttonBoxGroup.frame.size.height = BoxViewSize().buttonGroupSize.height - buttonViewGroup.addSubview(buttonBoxGroup) - - setAutoLayout(from: buttonBoxGroup, to: buttonViewGroup) - } - - func webViewInit() { - webView = wvc.addWebView() - hostingViewGroup.addSubview(webView) - setAutoLayout(from: webView, to: hostingViewGroup) - let request = URLRequest(url: url.URLdict["home"]!) - DispatchQueue.main.async { - self.webView.load(request) - } - } - - public func setAutoLayout(from: NSView, to: NSView) { - from.translatesAutoresizingMaskIntoConstraints = false - to.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.init(item: from, attribute: .leading, relatedBy: .equal, toItem: to, attribute: .leading, multiplier: 1.0, constant: 0).isActive = true - NSLayoutConstraint.init(item: from, attribute: .trailing, relatedBy: .equal, toItem: to, attribute: .trailing, multiplier: 1.0, constant: 0).isActive = true - NSLayoutConstraint.init(item: from, attribute: .top, relatedBy: .equal, toItem: to, attribute: .top, multiplier: 1.0, constant: 0).isActive = true - NSLayoutConstraint.init(item: from, attribute: .bottom, relatedBy: .equal, toItem: to, attribute: .bottom, multiplier: 1.0, constant: 0).isActive = true - view.layout() - } - - func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { - print(message.name) - } -} - -extension BoxController { - static func freshController() -> BoxController { - let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: nil) - let identifier = NSStoryboard.SceneIdentifier("BoxController") - - guard let viewcontroller = storyboard.instantiateController(withIdentifier: identifier) as? BoxController else { - fatalError("Story Board Not Found") - } - return viewcontroller - } -} diff --git a/Box42/Box/BoxModel.swift b/Box42/Box/BoxModel.swift index b188c95..686ced2 100644 --- a/Box42/Box/BoxModel.swift +++ b/Box42/Box/BoxModel.swift @@ -2,26 +2,21 @@ // BoxViewModel.swift // Box42 // -// Created by Chan on 2023/03/16. +// Created by Chan on 2023/08/11. // -import WebKit +import Cocoa -public extension NSScreen { - static let screenSize = NSScreen.main?.visibleFrame.size - static let screenWidth = screenSize!.width - static let screenHeight = screenSize!.height - static let halfOfScreen = (x: screenWidth / 2, y: screenHeight / 2) - static let customScreenSize = (x: CGFloat(900), y: screenHeight - 132) -} - -public struct BoxViewSize { - var halfSize: (width: CGFloat, height: CGFloat) = (NSScreen.halfOfScreen.x, NSScreen.halfOfScreen.y) - var size: (width: CGFloat, height: CGFloat) = (NSScreen.customScreenSize.x, NSScreen.customScreenSize.y) - var buttonGroupSize: (width: CGFloat, height: CGFloat) = (CGFloat(132), NSScreen.customScreenSize.y) - var viewStack = [NSView()] -} - -public class BoxStatus { - var isPin: Bool = false +struct BoxViewSize { + var halfSize: (width: CGFloat, height: CGFloat)! + var size: (width: CGFloat, height: CGFloat)! + var buttonGroupSize: (width: CGFloat, height: CGFloat)! + var viewStack: [NSView?] + + init() { + halfSize = (NSScreen.halfOfScreen.x, NSScreen.halfOfScreen.y) + size = (NSScreen.customScreenSize.x, NSScreen.customScreenSize.y) + buttonGroupSize = (CGFloat(132), NSScreen.customScreenSize.y) + viewStack = [NSView()] + } } diff --git a/Box42/Box/BoxView.swift b/Box42/Box/BoxView.swift deleted file mode 100644 index 9e5ba10..0000000 --- a/Box42/Box/BoxView.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// BoxView.swift -// Box42 -// -// Created by Chan on 2023/03/17. -// - -import Cocoa - -class BoxView: NSView { - -} - -struct BoxViewSize { - var halfSize: (width: CGFloat, height: CGFloat) = (NSScreen.halfOfScreen.x, NSScreen.halfOfScreen.y) - var size: (width: CGFloat, height: CGFloat) = (NSScreen.customScreenSize.x, NSScreen.customScreenSize.y) - var buttonGroupSize: (width: CGFloat, height: CGFloat) = (CGFloat(132), NSScreen.customScreenSize.y) - var viewStack = [NSView()] -} - -extension NSScreen { - static let screenSize = NSScreen.main?.visibleFrame.size - static let screenWidth = screenSize!.width - static let screenHeight = screenSize!.height - static let halfOfScreen = (x: screenWidth / 2, y: screenHeight / 2) - static let customScreenSize = (x: CGFloat(900), y: screenHeight - 132) -} diff --git a/Box42/Box/BoxViewController.swift b/Box42/Box/BoxViewController.swift new file mode 100644 index 0000000..784840c --- /dev/null +++ b/Box42/Box/BoxViewController.swift @@ -0,0 +1,159 @@ +// +// BoxViewController.swift +// Box42 +// +// Created by Chan on 2023/03/16. +// + +import Cocoa +import AppKit +import WebKit + +class BoxViewController: NSViewController, WKScriptMessageHandler, WKUIDelegate, WKNavigationDelegate { + var boxView: BoxButtonView! + var boxVM: BoxViewModel! + var wvc = WebViewController() + let preferencesVC = PreferencesViewController() + + private var webView: WKWebView! + + override func loadView() { + boxView = BoxButtonView() + boxVM = BoxViewModel() + } + + override func viewDidLoad() { + super.viewDidLoad() + view.window?.styleMask.insert(.resizable) + view.window?.makeFirstResponder(self) + + webViewInit() + wvc.loadWebViewInit() + configureButton() + } + + @objc + func doubleClickBtn(sender: NSButton) { + WebViewList.shared.list[sender.title]!.reload() + } + + @objc + func clickBtn(sender: NSButton) { + guard let clickCount = NSApp.currentEvent?.clickCount else { return } + if sender.title == "Preferences" { + boxView.hostingViewGroup.subviews.removeAll() + boxView.hostingViewGroup.addSubview(preferencesVC.view) + preferencesVC.viewDidAppear() + setAutoLayout(from: preferencesVC.view, to: boxView.hostingViewGroup) + return + } + if clickCount == 2 { + WebViewList.shared.list[sender.title]!.reload() + print("Dobule Click") + } else if clickCount > 2 { + let rqURL = URLRequest(url: boxVM.URLdict[sender.title]!) + WebViewList.shared.list[sender.title]!.load(rqURL) + print("Triple Click") + } else if clickCount < 2 { + boxView.hostingViewGroup.subviews.removeAll() + boxView.hostingViewGroup.addSubview(WebViewList.shared.list[sender.title]!) + WebViewList.shared.list[sender.title]!.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true + WebViewList.shared.list[sender.title]!.configuration.preferences.javaScriptEnabled = true + WebViewList.shared.list[sender.title]?.viewDidMoveToSuperview() + setAutoLayout(from: WebViewList.shared.list[sender.title]!, to: boxView.hostingViewGroup) + } + } + + @objc + func pin(_ sender: NSSwitch) { + StateManager.shared.setToggleIsPin() + print(sender.state) + } + + func webViewInit() { + boxVM.setUpURLdict() + webView = wvc.addWebView() + boxView.hostingViewGroup.addSubview(webView) + setAutoLayout(from: webView, to: boxView.hostingViewGroup) + let request = URLRequest(url: boxVM.URLdict["home"]!) + DispatchQueue.main.async { + self.webView.load(request) + } + } + + public func setAutoLayout(from: NSView, to: NSView) { + from.translatesAutoresizingMaskIntoConstraints = false + to.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.init(item: from, attribute: .leading, relatedBy: .equal, toItem: to, attribute: .leading, multiplier: 1.0, constant: 0).isActive = true + NSLayoutConstraint.init(item: from, attribute: .trailing, relatedBy: .equal, toItem: to, attribute: .trailing, multiplier: 1.0, constant: 0).isActive = true + NSLayoutConstraint.init(item: from, attribute: .top, relatedBy: .equal, toItem: to, attribute: .top, multiplier: 1.0, constant: 0).isActive = true + NSLayoutConstraint.init(item: from, attribute: .bottom, relatedBy: .equal, toItem: to, attribute: .bottom, multiplier: 1.0, constant: 0).isActive = true + view.layout() + } + + func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { + print(message.name) + } + + func configureButton() { + boxView.createHomeButton(clickAction: clickBtn) + for (name, _) in boxVM.webViewURL.URLstring { + boxView.createButton(name, clickAction: clickBtn) + } + boxView.divide() + boxView.preferencesButton(clickAction: clickBtn) + boxView.createQuitButton() + boxView.createPinButton(clickAction: clickBtn) + } +} + +extension BoxViewController { + static func freshController() -> BoxViewController { + let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: nil) + let identifier = NSStoryboard.SceneIdentifier("Main") + + guard let viewcontroller = storyboard.instantiateController(withIdentifier: identifier) as? BoxViewController else { + fatalError("Story Board Not Found") + } + return viewcontroller + } +} + +extension BoxViewController { + override func keyDown(with event: NSEvent) { + print(event.keyCode) + if event.keyCode == 53 { // Escape 키의 keyCode는 53입니다. + print("escape") + } else { + super.keyDown(with: event) // 기타 키를 처리하기 위해 상위 클래스에게 전달 + } + + if (event.modifierFlags.contains(.command) && event.charactersIgnoringModifiers == "c") || + (event.modifierFlags.contains(.command) && event.charactersIgnoringModifiers == "ㅊ") { + // 복사 동작 처리 + webView.evaluateJavaScript("document.execCommand('copy')") { (_, error) in + if let error = error { + print("Copy error: \(error)") + } else { + print("Copy success") + } + } + } else if (event.modifierFlags.contains(.command) && event.charactersIgnoringModifiers == "v") || + (event.modifierFlags.contains(.command) && event.charactersIgnoringModifiers == "ㅍ") { + // 붙여넣기 동작 처리 + let pasteboard = NSPasteboard.general + if let pasteString = pasteboard.string(forType: .string) { + let escapedPasteString = pasteString.escapedForJavaScript + webView.evaluateJavaScript("document.execCommand('insertText', false, '\(escapedPasteString)')") { (_, error) in + if let error = error { + print("Paste error: \(error)") + } else { + print("Paste success") + } + } + } + } else { + super.keyDown(with: event) // 기본 키 이벤트 처리 + } + } +} diff --git a/Box42/Box/BoxViewModel.swift b/Box42/Box/BoxViewModel.swift new file mode 100644 index 0000000..3fbd9ff --- /dev/null +++ b/Box42/Box/BoxViewModel.swift @@ -0,0 +1,29 @@ +// +// URLViewModel.swift +// Box42 +// +// Created by Chanhee Kim on 8/9/23. +// + +import Foundation +import Combine + +// CRUD 4가지 형태의 데이터 가공 create, read, update, delete +class BoxViewModel: ObservableObject { + var webViewURL: URLModels + @Published var URLdict: [String: URL] + + init() { + self.webViewURL = URLModels(info: [URLModel(name: "home", url: "https://42box.github.io/front-end/")]) + self.URLdict = [String: URL]() + } + + func setUpURLdict() { +// for urlModel in webViewURL.info { +// URLdict[urlModel.name] = URL(string: urlModel.url) +// } + for urlModel in webViewURL.URLstring { + URLdict[urlModel.0] = URL(string: urlModel.1) + } + } +} diff --git a/Box42/Box/View/BoxButtonView.swift b/Box42/Box/View/BoxButtonView.swift new file mode 100644 index 0000000..37a9a6f --- /dev/null +++ b/Box42/Box/View/BoxButtonView.swift @@ -0,0 +1,123 @@ +// +// BoxButtonView.swift +// Box42 +// +// Created by Chanhee Kim on 8/11/23. +// + +import Cocoa + +class BoxButtonView: BoxView { + var topAnchorDistance: CGFloat = 0 + + func createButton(_ title: String, clickAction: @escaping (NSButton) -> Void) { + let button = NSButton() + + button.title = title + button.setButtonType(.momentaryLight) + + button.translatesAutoresizingMaskIntoConstraints = false + + let handler = BoxButtonHandler() + handler.clickAction = clickAction + + button.target = handler + button.action = #selector(handler.buttonClicked(_:)) + + button.isBordered = true + button.bezelStyle = .roundRect + button.showsBorderOnlyWhileMouseInside = true + + super.buttonBoxGroup.addSubview(button) + + button.leadingAnchor.constraint(equalTo: super.buttonBoxGroup.leadingAnchor, constant: 20).isActive = true + button.topAnchor.constraint(equalTo: super.buttonBoxGroup.topAnchor, constant: topAnchorDistance).isActive = true + topAnchorDistance += 30 + button.trailingAnchor.constraint(equalTo: super.buttonBoxGroup.trailingAnchor, constant: -20).isActive = true + } + + func createHomeButton(clickAction: @escaping (NSButton) -> Void) { + let handler = BoxButtonHandler() + handler.clickAction = clickAction + + let button = NSButton(title: "home", image: NSImage(imageLiteralResourceName: "42box_logo"), target: handler, action: #selector(handler.buttonClicked(_:))) + + button.translatesAutoresizingMaskIntoConstraints = false + button.isBordered = false + button.imagePosition = .imageOnly + + super.buttonBoxGroup.addSubview(button) + + button.leadingAnchor.constraint(equalTo: super.buttonBoxGroup.leadingAnchor, constant: 20).isActive = true + button.topAnchor.constraint(equalTo: super.buttonBoxGroup.topAnchor, constant: topAnchorDistance).isActive = true + topAnchorDistance += 80 + button.trailingAnchor.constraint(equalTo: super.buttonBoxGroup.trailingAnchor, constant: -20).isActive = true + } + + func createQuitButton() { + let button = NSButton() + button.title = "Quit Box" + button.setButtonType(.momentaryLight) + + button.translatesAutoresizingMaskIntoConstraints = false + button.action = #selector(NSApplication.terminate(_:)) + button.isBordered = true + button.bezelStyle = .roundRect + button.showsBorderOnlyWhileMouseInside = true + + super.buttonBoxGroup.addSubview(button) + + button.leadingAnchor.constraint(equalTo: super.buttonBoxGroup.leadingAnchor, constant: 20).isActive = true + button.bottomAnchor.constraint(equalTo: super.buttonBoxGroup.bottomAnchor, constant: -10).isActive = true + button.trailingAnchor.constraint(equalTo: super.buttonBoxGroup.trailingAnchor, constant: -20).isActive = true + } + + func createPinButton(clickAction: @escaping (NSButton) -> Void) { + let button = NSButton() + button.title = "Pin Box" + button.setButtonType(.toggle) + button.contentTintColor = .orange + button.translatesAutoresizingMaskIntoConstraints = false + + let handler = BoxButtonHandler() + handler.clickAction = clickAction + + button.target = handler + button.action = #selector(handler.buttonClicked(_:)) + + button.isBordered = true + button.bezelStyle = .roundRect + button.showsBorderOnlyWhileMouseInside = true + + super.buttonBoxGroup.addSubview(button) + + button.leadingAnchor.constraint(equalTo: super.buttonBoxGroup.leadingAnchor, constant: 20).isActive = true + button.bottomAnchor.constraint(equalTo: super.buttonBoxGroup.bottomAnchor, constant: -50).isActive = true + button.trailingAnchor.constraint(equalTo: super.buttonBoxGroup.trailingAnchor, constant: -20).isActive = true + } + + func preferencesButton(clickAction: @escaping (NSButton) -> Void) { + let button = NSButton() + button.title = "Preferences" + button.setButtonType(.momentaryLight) + + button.translatesAutoresizingMaskIntoConstraints = false + + let handler = BoxButtonHandler() + handler.clickAction = clickAction + + button.target = handler + button.action = #selector(handler.buttonClicked(_:)) + + button.isBordered = true + button.bezelStyle = .roundRect + button.showsBorderOnlyWhileMouseInside = true + + super.buttonBoxGroup.addSubview(button) + + button.leadingAnchor.constraint(equalTo: super.buttonBoxGroup.leadingAnchor, constant: 20).isActive = true + button.bottomAnchor.constraint(equalTo: super.buttonBoxGroup.bottomAnchor, constant: -90).isActive = true + button.trailingAnchor.constraint(equalTo: super.buttonBoxGroup.trailingAnchor, constant: -20).isActive = true + } + +} diff --git a/Box42/Box/View/BoxView.swift b/Box42/Box/View/BoxView.swift new file mode 100644 index 0000000..c20ca54 --- /dev/null +++ b/Box42/Box/View/BoxView.swift @@ -0,0 +1,101 @@ +// +// BoxView.swift +// Box42 +// +// Created by Chan on 2023/03/17. +// + +import Cocoa + +class BoxView: NSView { + var buttonBoxGroup : NSView! + var buttonViewGroup : NSView! + var hostingViewGroup : NSView! + var divider : NSBox! + var pinSwitch : NSSwitch! + var boxModel = BoxViewSize() + + override init(frame frameRect: NSRect) { + super.init(frame: frameRect) + commonInit() + viewInit() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + commonInit() + viewInit() + } + + private func commonInit() { + buttonBoxGroup = NSView() + buttonViewGroup = NSView() + hostingViewGroup = NSView() + divider = NSBox() + pinSwitch = NSSwitch() + + // Pan Gesture Recognizer를 추가합니다. + let panRecognizer = NSPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:))) + addGestureRecognizer(panRecognizer) + } + + func viewInit() { + self.boxViewSizeInit() + self.buttonBoxGroupInit() + self.divide() + } + + func boxViewSizeInit() { + self.frame.size.width = boxModel.size.width + self.frame.size.height = boxModel.size.height + + hostingViewGroup.frame.size.width = boxModel.size.width - boxModel.buttonGroupSize.width + hostingViewGroup.frame.size.height = boxModel.size.height + + buttonViewGroup.frame.size.width = boxModel.buttonGroupSize.width + buttonViewGroup.frame.size.height = boxModel.buttonGroupSize.height + } + + func divide() { + divider.translatesAutoresizingMaskIntoConstraints = false + divider.bottomAnchor.constraint(equalTo: buttonBoxGroup.bottomAnchor, constant: -40).isActive = true + } + + func buttonBoxGroupInit() { + self.buttonBoxGroup = NSView(frame: NSRect(x: 0, y: 0, width: boxModel.buttonGroupSize.width, height: boxModel.buttonGroupSize.height)) + self.buttonBoxGroup.frame.size.width = boxModel.buttonGroupSize.width + self.buttonBoxGroup.frame.size.height = boxModel.buttonGroupSize.height + self.buttonViewGroup.addSubview(self.buttonBoxGroup) + + setAutoLayout(from: self.buttonBoxGroup, to: self.buttonViewGroup) + } + + func setAutoLayout(from: NSView, to: NSView) { + from.translatesAutoresizingMaskIntoConstraints = false + to.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.init(item: from, attribute: .leading, relatedBy: .equal, toItem: to, attribute: .leading, multiplier: 1.0, constant: 0).isActive = true + NSLayoutConstraint.init(item: from, attribute: .trailing, relatedBy: .equal, toItem: to, attribute: .trailing, multiplier: 1.0, constant: 0).isActive = true + NSLayoutConstraint.init(item: from, attribute: .top, relatedBy: .equal, toItem: to, attribute: .top, multiplier: 1.0, constant: 0).isActive = true + NSLayoutConstraint.init(item: from, attribute: .bottom, relatedBy: .equal, toItem: to, attribute: .bottom, multiplier: 1.0, constant: 0).isActive = true + self.layout() + } +} + +extension BoxView { + @objc private func handlePanGesture(_ recognizer: NSPanGestureRecognizer) { + guard let view = recognizer.view else { return } + + // 사용자가 드래그한 변화량을 가져옵니다. + let translation = recognizer.translation(in: view) + + // 드래그로 인한 크기 변화를 계산합니다. + let newWidth = view.frame.width + translation.x + let newHeight = view.frame.height + translation.y + + // 크기를 적용합니다. + view.setFrameSize(NSSize(width: newWidth, height: newHeight)) + + // 변화량을 리셋합니다. + recognizer.setTranslation(.zero, in: view) + } +} diff --git a/Box42/CPU/CPU.swift b/Box42/CPU/CPU.swift index 33c11a9..1d31df6 100644 --- a/Box42/CPU/CPU.swift +++ b/Box42/CPU/CPU.swift @@ -10,7 +10,6 @@ import Foundation public class CPU { var cpuTimer: Timer? = nil - var isShow: Bool = false var usage: (value: Double, description: String) = (0.0, "") private let loadInfoCount: mach_msg_type_number_t! @@ -49,22 +48,17 @@ public class CPU { self.usage = (value, description) } - public func isShowUsage() -> Bool { - if isShow == false { return false } - return true - } - - public func processCPU(_ statusBar: StatusBar) -> Bool { + func processCPU(_ statusBar: StatusBar) -> Bool { cpuTimer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true, block: { _ in self.usageCPU() statusBar.interval = 0.02 * (100 - max(0.0, min(99.0, self.usage.value))) / 6 - statusBar.statusItem.button?.title = self.isShowUsage() ? self.usage.description : "" + statusBar.statusItem.button?.title = StateManager.shared.getIsShowCPUUsage() ? self.usage.description : "" }) self.cpuTimer?.fire() return true } - public func StopCPU() -> Bool { + func StopCPU() -> Bool { self.cpuTimer?.invalidate() return false } diff --git a/Box42/Extensions/NSScreen.swift b/Box42/Extensions/NSScreen.swift new file mode 100644 index 0000000..778e4fd --- /dev/null +++ b/Box42/Extensions/NSScreen.swift @@ -0,0 +1,16 @@ +// +// NSScreen.swift +// Box42 +// +// Created by Chanhee Kim on 8/11/23. +// + +import Cocoa + +extension NSScreen { + static let screenSize = NSScreen.main?.visibleFrame.size + static let screenWidth = screenSize!.width + static let screenHeight = screenSize!.height + static let halfOfScreen = (x: screenWidth / 2, y: screenHeight / 2) + static let customScreenSize = (x: CGFloat(900), y: screenHeight - 132) +} diff --git a/Box42/Resources/StringExtension.swift b/Box42/Extensions/StringExtension.swift similarity index 100% rename from Box42/Resources/StringExtension.swift rename to Box42/Extensions/StringExtension.swift diff --git a/Box42/Menubar/MenubarModel.swift b/Box42/Menubar/MenubarModel.swift index 4e920ba..24a9a73 100644 --- a/Box42/Menubar/MenubarModel.swift +++ b/Box42/Menubar/MenubarModel.swift @@ -8,6 +8,8 @@ import AppKit class StatusBar { + static let shared = StatusBar() + var statusItem: NSStatusItem var frames: [NSImage] var cnt: Int diff --git a/Box42/Menubar/MenubarViewController.swift b/Box42/Menubar/MenubarViewController.swift index 032e463..b381e1c 100644 --- a/Box42/Menubar/MenubarViewController.swift +++ b/Box42/Menubar/MenubarViewController.swift @@ -11,19 +11,13 @@ import AppKit class MenubarViewController: NSWorkspace { var popover = NSPopover() - lazy var eventMonitor: EventMonitor = self.setupEventMonitor() - var statusBarVM: StatusBarViewModel? // 옵셔널로 선언 + var statusBarVM = StatusBarViewModel() let menuBarView = MenuBarView() - lazy var keyboardEventMonitor = EventMonitor(mask: [.keyDown]) { [weak self] event in - print("keydown") - } - // 초기화 함수나 다른 적절한 시점에 호출 - func initializeStatusBarVM() { - statusBarVM = StatusBarViewModel(eventMonitor: eventMonitor) - } - + lazy var eventMonitor: EventMonitor = self.setupEventMonitor() + var boxWindowController: BoxWindowController? + + func menubarViewControllerInit() { - self.initializeStatusBarVM() self.buttonInit() } @@ -31,38 +25,43 @@ class MenubarViewController: NSWorkspace { self.menubarStartRunning() self.buttonActionInit() self.popoverHandler() + self.startEventMonitoring() + } + + func startEventMonitoring() { + eventMonitor.start() + } + + func stopEventMonitoring() { + eventMonitor.stop() } func menubarStartRunning() { - statusBarVM?.startRunning() + statusBarVM.startRunning() } func menubarStopRunning() { - statusBarVM?.stopRunning() + statusBarVM.stopRunning() } func buttonInit() { - buttonImageChange("box") - statusBarVM?.statusButtonAppear() + buttonImageChange("Cat") + statusBarVM.statusButtonAppear() } func buttonImageChange(_ img: String) { - statusBarVM?.changeStatusBarIcon(img) + statusBarVM.changeStatusBarIcon(img) } func buttonActionInit() { - statusBarVM?.statusBar.statusItem.button?.action = #selector(togglePopover(_:)) - statusBarVM?.statusBar.statusItem.button?.target = self - } - - func popoverHandler() { - popover.contentViewController = BoxController.freshController() + statusBarVM.statusBar.statusItem.button?.action = #selector(togglePopover(_:)) + statusBarVM.statusBar.statusItem.button?.target = self } func setupEventMonitor() -> EventMonitor { return EventMonitor(mask: [.leftMouseDown, .rightMouseDown, .otherMouseDown]) { [weak self] event in if let strongSelf = self, strongSelf.popover.isShown { - if StateManager.shared.isPin == false && event?.buttonNumber != 2 { + if StateManager.shared.getIsPin() == false && event?.buttonNumber != 2 { strongSelf.closePopover(sender: event) } } else if let strongSelf = self, !strongSelf.popover.isShown { @@ -81,15 +80,47 @@ class MenubarViewController: NSWorkspace { } } + func popoverHandler() { + popover.contentViewController = BoxViewController.freshController() + } + func showPopover(sender: Any?) { - if let button = statusBarVM?.statusBar.statusItem.button { + if let event = sender as? NSEvent { + if event.type == .otherMouseDown { + self.showWindow(sender: sender) + } + } else if let button = statusBarVM.statusBar.statusItem.button { popover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY) } - eventMonitor.start() } + + func showWindow(sender: Any?) { + boxWindowController?.close() + + boxWindowController = BoxWindowController(windowNibName: NSNib.Name("BoxWindowController")) + + // status bar 버튼의 위치를 얻어옵니다. + if let button = statusBarVM.statusBar.statusItem.button, + let screenFrame = NSScreen.main?.frame, + let window = boxWindowController?.window { + + let buttonFrame = button.window?.convertToScreen(button.frame) ?? NSZeroRect + + // 버튼 위치 아래에 윈도우를 표시하려면 + let desiredPosition = NSPoint(x: buttonFrame.origin.x, y: buttonFrame.origin.y - window.frame.height) + + // 혹은, 버튼 위치의 중앙에 윈도우를 표시하려면 +// let desiredPosition = NSPoint(x: buttonFrame.midX - window.frame.width / 2, y: buttonFrame.origin.y - window.frame.height) + + // 윈도우의 위치를 설정 + window.setFrameOrigin(desiredPosition) + } + boxWindowController?.contentViewController = BoxViewController.freshController() + boxWindowController?.showWindow(sender) + } + func closePopover(sender: Any?) { popover.performClose(sender) -// eventMonitor.stop() } } diff --git a/Box42/Menubar/MenubarViewModel.swift b/Box42/Menubar/MenubarViewModel.swift index 6f0b12c..d131b10 100644 --- a/Box42/Menubar/MenubarViewModel.swift +++ b/Box42/Menubar/MenubarViewModel.swift @@ -9,13 +9,12 @@ import AppKit class StatusBarViewModel { let cpu: CPU - let eventMonitor: EventMonitor let statusBar: StatusBar + private var currentAnimationWorkItem: DispatchWorkItem? - init (eventMonitor: EventMonitor) { - self.statusBar = StatusBar() + init () { + self.statusBar = StatusBar.shared self.cpu = CPU() - self.eventMonitor = eventMonitor } func statusButtonAppear() { @@ -24,12 +23,14 @@ class StatusBarViewModel { func changeStatusBarIcon(_ imgName: String) { statusBar.frames.removeAll() + switch imgName { - case "cat": for i in (0...4) {statusBar.frames.append(NSImage(imageLiteralResourceName: "cat_page\(i)"))} + case "Cat": for i in (0...4) {statusBar.frames.append(NSImage(imageLiteralResourceName: "cat_page\(i)"))} case "gon": for i in (1...5) {statusBar.frames.append(NSImage(imageLiteralResourceName: "gon_\(i)"))} case "gun": for i in (1...5) {statusBar.frames.append(NSImage(imageLiteralResourceName: "gun_\(i)"))} - case "lee": for i in (1...5) {statusBar.frames.append(NSImage(imageLiteralResourceName: "gam_\(i)"))} - case "box": for i in (1...4) {statusBar.frames.append(NSImage(imageLiteralResourceName: "42box_\(i)"))} + case "gam": for i in (1...5) {statusBar.frames.append(NSImage(imageLiteralResourceName: "gam_\(i)"))} + case "lee": for i in (1...5) {statusBar.frames.append(NSImage(imageLiteralResourceName: "lee_\(i)"))} + case "Box": for i in (1...4) {statusBar.frames.append(NSImage(imageLiteralResourceName: "42box_\(i)"))} case "box_oc": for i in (1...2) {statusBar.frames.append(NSImage(imageLiteralResourceName: "42box_oc\(i)"))} default : for i in (1...11) {statusBar.frames.append(NSImage(imageLiteralResourceName: "42flip_0\(i)"))} } @@ -37,19 +38,39 @@ class StatusBarViewModel { func startRunning() { statusBar.isRunning = cpu.processCPU(statusBar) - self.animate() +// self.animate() + scheduleAnimation() } func animate() { statusBar.statusItem.button?.image = statusBar.frames[statusBar.cnt] statusBar.cnt = (statusBar.cnt + 1) % statusBar.frames.count if !statusBar.isRunning { return } + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + statusBar.interval) { self.animate() } } + func scheduleAnimation() { + currentAnimationWorkItem?.cancel() + + let workItem = DispatchWorkItem { [weak self] in + self?.statusBar.statusItem.button?.image = self?.statusBar.frames[self?.statusBar.cnt ?? 0] + self?.statusBar.cnt = ((self?.statusBar.cnt)! + 1) % (self?.statusBar.frames.count ?? 1) + + if self?.statusBar.isRunning ?? false { + self?.scheduleAnimation() + } + } + + currentAnimationWorkItem = workItem + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + statusBar.interval, execute: workItem) + } + func stopRunning() { statusBar.isRunning = cpu.StopCPU() + currentAnimationWorkItem?.cancel() + statusBar.cnt = 0 } } diff --git a/Box42/Preferences/Icon.swift b/Box42/Preferences/Icon.swift index faca984..d256436 100644 --- a/Box42/Preferences/Icon.swift +++ b/Box42/Preferences/Icon.swift @@ -5,4 +5,15 @@ // Created by Chanhee Kim on 7/8/23. // -import Foundation +struct iconModel { + var icon: [String] = [ + "Cat", + "gam", + "gon", + "gun", + "lee", + "Box", + "box_oc", + "42" + ] +} diff --git a/Box42/Resources/AppDelegate.swift b/Box42/Resources/AppDelegate.swift index 688a686..358a56c 100644 --- a/Box42/Resources/AppDelegate.swift +++ b/Box42/Resources/AppDelegate.swift @@ -7,183 +7,10 @@ import Cocoa -@main -class AppDelegate: NSObject, NSApplicationDelegate { - let popover = NSPopover() - var eventMonitor: EventMonitor? - var menubarController = MenuBarController() - var boxController = BoxController() - var boxStatus = BoxStatus() - - func applicationWillFinishLaunching(_ notification: Notification) { - menubarController.buttonInit() - } - - func applicationDidFinishLaunching(_ aNotification: Notification) { - menubarController.startRunning() - buttonActionInit() - popoverHandler() - eventMonitorHandler() - } - - func popoverHandler() { - popover.contentViewController = BoxController.freshController() - } - - func buttonActionInit() { - menubarController.statusBar.statusItem.button?.action = #selector(togglePopover(_:)) - } - - func eventMonitorHandler() { - eventMonitor = EventMonitor(mask: [.leftMouseDown, .rightMouseDown]) { [weak self] event in - if let strongSelf = self, strongSelf.popover.isShown { - if self?.boxStatus.isPin == false { - strongSelf.closePopover(sender: event) - } - } - } - } - - @objc func togglePopover(_ sender: Any?) { - if popover.isShown { - closePopover(sender: sender) - } else { - showPopover(sender: sender) - } - } - - func showPopover(sender: Any?) { - if let button = menubarController.statusBar.statusItem.button { - popover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY) - } - eventMonitor?.start() - } - - func closePopover(sender: Any?) { - popover.performClose(sender) - eventMonitor?.stop() - } - - func applicationWillTerminate(_ aNotification: Notification) { - // Insert code here to tear down your application - } - - func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { - return true - } - - // MARK: - Core Data stack - - lazy var persistentContainer: NSPersistentContainer = { - /* - The persistent container for the application. This implementation - creates and returns a container, having loaded the store for the - application to it. This property is optional since there are legitimate - error conditions that could cause the creation of the store to fail. - */ - let container = NSPersistentContainer(name: "Box42") - container.loadPersistentStores(completionHandler: { (storeDescription, error) in - if let error = error { - // Replace this implementation with code to handle the error appropriately. - // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. - - /* - Typical reasons for an error here include: - * The parent directory does not exist, cannot be created, or disallows writing. - * The persistent store is not accessible, due to permissions or data protection when the device is locked. - * The device is out of space. - * The store could not be migrated to the current model version. - Check the error message to determine what the actual problem was. - */ - fatalError("Unresolved error \(error)") - } - }) - return container - }() - - // MARK: - Core Data Saving and Undo support - - @IBAction func saveAction(_ sender: AnyObject?) { - // Performs the save action for the application, which is to send the save: message to the application's managed object context. Any encountered errors are presented to the user. - let context = persistentContainer.viewContext - - if !context.commitEditing() { - NSLog("\(NSStringFromClass(type(of: self))) unable to commit editing before saving") - } - if context.hasChanges { - do { - try context.save() - } catch { - // Customize this code block to include application-specific recovery steps. - let nserror = error as NSError - NSApplication.shared.presentError(nserror) - } - } - } - - func windowWillReturnUndoManager(window: NSWindow) -> UndoManager? { - // Returns the NSUndoManager for the application. In this case, the manager returned is that of the managed object context for the application. - return persistentContainer.viewContext.undoManager - } - - func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply { - // Save changes in the application's managed object context before the application terminates. - let context = persistentContainer.viewContext - - if !context.commitEditing() { - NSLog("\(NSStringFromClass(type(of: self))) unable to commit editing to terminate") - return .terminateCancel - } - - if !context.hasChanges { - return .terminateNow - } - - do { - try context.save() - } catch { - let nserror = error as NSError - - // Customize this code block to include application-specific recovery steps. - let result = sender.presentError(nserror) - if (result) { - return .terminateCancel - } - - let question = NSLocalizedString("Could not save changes while quitting. Quit anyway?", comment: "Quit without saves error question message") - let info = NSLocalizedString("Quitting now will lose any changes you have made since the last successful save", comment: "Quit without saves error question info"); - let quitButton = NSLocalizedString("Quit anyway", comment: "Quit anyway button title") - let cancelButton = NSLocalizedString("Cancel", comment: "Cancel button title") - let alert = NSAlert() - alert.messageText = question - alert.informativeText = info - alert.addButton(withTitle: quitButton) - alert.addButton(withTitle: cancelButton) - - let answer = alert.runModal() - if answer == .alertSecondButtonReturn { - return .terminateCancel - } - } - // If we got here, it is time to quit. - return .terminateNow - } - -} - -// -// AppDelegate.swift -// Box42 -// -// Created by Chan on 2023/03/15. -// - -import Cocoa - @main class AppDelegate: NSObject, NSApplicationDelegate { var menubarController = MenubarViewController() - + func applicationWillFinishLaunching(_ notification: Notification) { menubarController.menubarViewControllerInit() } diff --git a/Box42/Resources/Box42.entitlements b/Box42/Resources/Box42.entitlements index 40b639e..aa078cb 100644 --- a/Box42/Resources/Box42.entitlements +++ b/Box42/Resources/Box42.entitlements @@ -4,6 +4,8 @@ com.apple.security.app-sandbox + com.apple.security.automation.apple-events + com.apple.security.files.user-selected.read-only com.apple.security.network.client diff --git a/Box42/Resources/EventMonitor.swift b/Box42/Resources/EventMonitor.swift index e56d895..ca7722b 100644 --- a/Box42/Resources/EventMonitor.swift +++ b/Box42/Resources/EventMonitor.swift @@ -7,40 +7,6 @@ import Cocoa -public class EventMonitor { - private var monitor: Any? - private let mask: NSEvent.EventTypeMask - private let handler: (NSEvent?) -> Void - - public init(monitor: Any? = nil, mask: NSEvent.EventTypeMask, handler: @escaping (NSEvent?) -> Void) { - self.mask = mask - self.handler = handler - } - - deinit { - stop() - } - - public func start() { - monitor = NSEvent.addGlobalMonitorForEvents(matching: mask, handler: handler) - } - - public func stop() { - if monitor != nil { - NSEvent.removeMonitor(monitor!) - monitor = nil - } - } -} -// -// EventMonitor.swift -// Box42 -// -// Created by Chan on 2023/03/16. -// - -import Cocoa - public class EventMonitor { private var monitor: Any? private let mask: NSEvent.EventTypeMask diff --git a/Box42/Resources/Info.plist b/Box42/Resources/Info.plist index a6a98a7..6529386 100644 --- a/Box42/Resources/Info.plist +++ b/Box42/Resources/Info.plist @@ -28,5 +28,26 @@ Main NSPrincipalClass NSApplication + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + + UISceneDelegateClassName + + UISceneConfigurationName + + UISceneStoryboardFile + + + + + diff --git a/Box42/Shared/StateManager.swift b/Box42/Shared/StateManager.swift index e544e11..c5a0fec 100644 --- a/Box42/Shared/StateManager.swift +++ b/Box42/Shared/StateManager.swift @@ -8,9 +8,37 @@ class StateManager { static let shared = StateManager() - var isPin: Bool! + private var isPin: Bool! + private var isShowCPUUsage: Bool! + private var isShowWindow: Bool! private init() { isPin = false + isShowCPUUsage = false + isShowWindow = false + } + + func getIsPin() -> Bool { + return isPin + } + + func setToggleIsPin() { + isPin.toggle() + } + + func getIsShowCPUUsage() -> Bool { + return isShowCPUUsage + } + + func setToggleIsShowCPUUsage() { + isShowCPUUsage.toggle() + } + + func getToggleIsShowWindow() -> Bool { + return isShowWindow + } + + func setToggleIsShowWindow() { + isShowWindow.toggle() } } diff --git a/Box42/URL/URLModel.swift b/Box42/URL/URLModel.swift index 209828e..9763fce 100644 --- a/Box42/URL/URLModel.swift +++ b/Box42/URL/URLModel.swift @@ -8,20 +8,21 @@ import Foundation struct URLModel { - let URLdict: [String: URL] = [ - "home": URL(string: "https://42box.github.io/front-end/")!, - // "home": URL(string: "http://127.0.0.1:3000/")!, - "Box 42": URL(string: "https://42box.github.io/front-end/#/box")!, - "Intra 42": URL(string: "https://intra.42.fr")!, - "Jiphyeonjeon" : URL(string:"https://42library.kr")!, - "E-Library": URL(string:"https://42seoul.dkyobobook.co.kr/main.ink")!, - "24Hane": URL(string:"https://24hoursarenotenough.42seoul.kr")!, - "80000Coding": URL(string:"https://80000coding.oopy.io")!, - "where42": URL(string:"https://www.where42.kr")!, - "cabi": URL(string:"https://cabi.42seoul.io/")!, - "42gg": URL(string:"https://42gg.kr/")!, - ] + var id: UUID + var name: String + var url: String + init(name: String, url: String) { + self.id = UUID() + self.name = name + self.url = url + } +} + +struct URLModels { + var info: [URLModel] + + // Network logic let URLstring: [(String, String)] = [ ("home", "https://42box.github.io/front-end/"), // ("home", "http://127.0.0.1:3000/"), @@ -34,5 +35,12 @@ struct URLModel { ("where42", "https://www.where42.kr"), ("cabi", "https://cabi.42seoul.io/"), ("42gg", "https://42gg.kr/"), + ("textart", "https://textart.sh/") ] + + mutating func urlSetup() { + URLstring.forEach { (name, url) in + info.append(URLModel(name: name, url: url)) + } + } } diff --git a/Box42/WebView/WebViewController.swift b/Box42/WebView/WebViewController.swift index 13909a4..984f888 100644 --- a/Box42/WebView/WebViewController.swift +++ b/Box42/WebView/WebViewController.swift @@ -9,12 +9,13 @@ import Cocoa import WebKit class WebViewController: NSViewController, WKScriptMessageHandler, WKUIDelegate, WKNavigationDelegate { - + var URLVM = BoxViewModel() + func loadWebViewInit() { - for i in 0.. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +