diff --git a/.github/Release-note.yml b/.github/Release-note.yml new file mode 100644 index 0000000..e2d8534 --- /dev/null +++ b/.github/Release-note.yml @@ -0,0 +1,23 @@ +name-template: "v$NEXT_MINOR_VERSION 🌈" +tag-template: "v$NEXT_MINOR_VERSION" +categories: + - title: "πŸš€ Features" + labels: + - "✨ Enhancement" + - "βš’ Refactor" + - title: "πŸ› Bug Fixes" + labels: + - "🐞 Bug" +exclude-labels: + - "πŸ“„ Documentation" + - "🌐 DevOps" + - "πŸ’„ UI/UX" + - "πŸ› Structure" + - "πŸ’– Question" + - "β˜‚οΈ Umbrella" +change-template: "- $TITLE (#$NUMBER)" +change-title-escapes: '\<*_&' +template: | + ## Changes + + $CHANGES diff --git a/.github/workflows/Deployment.yml b/.github/workflows/Deployment.yml new file mode 100644 index 0000000..9129b19 --- /dev/null +++ b/.github/workflows/Deployment.yml @@ -0,0 +1,74 @@ +# Author by chanhihi +# Date 2023.08.09 + +name: Deployment + +on: + pull_request: + branches: + - cluster_main + - main + types: + - closed + +jobs: + build: + name: Deploy on macOS 11 + runs-on: macos-11 + env: + XCODE_VERSION: "12.4.0" + SWIFT_VERSION: "5.3" + XCODE_PROJECT: "Box42.xcodeproj" + XCODE_SCHEME: "Box42" + XCODE_ARCHIVE_PATH: "Box42.xcarchive" + XCODE_EXPORT_PATH: "./artifacts" + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set Xcode version + run: sudo xcode-select -s '/Applications/Xcode_12.4.0.app/Contents/Developer' + + - name: Set SDK version + run: echo 'SDKROOT=/Applications/Xcode_12.4.0.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk' >> $GITHUB_ENV + + - name: setup-swift + uses: swift-actions/setup-swift@v1 + with: + swift-version: $SWIFT_VERSION + + - name: Build + run: | + mkdir Sources && + mv Box42 Sources/Box42 && + swift build + + - name: Archive + run: | + mv Sources/Box42/Resources/ExportOptions.plist . && + xcodebuild archive -project $XCODE_PROJECT -scheme $XCODE_SCHEME -archivePath $XCODE_ARCHIVE_PATH + + - name: Distribute + run: | + mkdir -p artifacts && + xcodebuild -exportArchive -archivePath "$XCODE_ARCHIVE_PATH" -exportOptionsPlist ExportOptions.plist -exportPath "$XCODE_EXPORT_PATH" + + - name: Tagging + id: tag_version + uses: mathieudutour/github-tag-action@v6.1 + with: + github_token: ${{ secrets.CHANHIHI }} + + - name: Draft Release + id: draft_release + uses: release-drafter/release-drafter@v5 + with: + config-name: Release-note.yml + env: + GITHUB_TOKEN: ${{ secrets.CHANHIHI }} + + - name: Upload Box42-Artifacts + uses: actions/upload-artifact@v2 + with: + name: Box42-${{ steps.tag_version.outputs.new_tag }} + path: $XCODE_EXPORT_PATH diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml new file mode 100644 index 0000000..976d883 --- /dev/null +++ b/.github/workflows/swift.yml @@ -0,0 +1,43 @@ +# Author by chanhihi +# Date 2023.08.09 + +name: Swift Build + +on: + push: + branches: + - feat/* + - fix/* + - refactor/* + + pull_request: + branches: + - cluster_develop + +jobs: + build: + name: Swift 5.3 on macOS 11 + runs-on: macos-11 + env: + XCODE_VERSION: "12.4.0" + SWIFT_VERSION: "5.3" + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set Xcode version + run: sudo xcode-select -s '/Applications/Xcode_12.4.0.app/Contents/Developer' + + - name: Set SDK version + run: echo 'SDKROOT=/Applications/Xcode_12.4.0.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk' >> $GITHUB_ENV + + - name: setup-swift + uses: swift-actions/setup-swift@v1 + with: + swift-version: ${{ env.SWIFT_VERSION }} + + - name: Build + run: | + mkdir Sources && + mv Box42 Sources/Box42 && + swift build diff --git a/.gitignore b/.gitignore index dd2592e..ed7c9da 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,101 @@ +### Swift ### +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 + +## Obj-C/Swift specific +*.hmap + +## App packaging +*.ipa +*.dSYM.zip +*.dSYM + +## Playgrounds +timeline.xctimeline +playground.xcworkspace + +# Swift Package Manager +# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. +# Packages/ +# Package.pins +# Package.resolved +# *.xcodeproj +# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata +# hence it is not needed unless you have added a package configuration file to your project +# .swiftpm + +.build/ + +# CocoaPods +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# Pods/ +# Add this line if you want to avoid checking in source code from the Xcode workspace +# *.xcworkspace + +# Carthage +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build/ + +# Accio dependency management +Dependencies/ +.accio/ + +# fastlane +# It is recommended to not store the screenshots in the git repo. +# Instead, use fastlane to re-generate the screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots/**/*.png +fastlane/test_output + +# Code Injection +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + +iOSInjectionProject/ + +### Xcode ### + +## Xcode 8 and earlier + +### Xcode Patch ### +*.xcodeproj/* +!*.xcodeproj/project.pbxproj +!*.xcodeproj/xcshareddata/ +!*.xcodeproj/project.xcworkspace/ +!*.xcworkspace/contents.xcworkspacedata +/*.gcno +**/xcshareddata/WorkspaceSettings.xcsettings + .DS_Store Box42/.DS_Store +.prettierrc +.swift-format \ No newline at end of file diff --git a/.tuist-version b/.tuist-version new file mode 100644 index 0000000..8912835 --- /dev/null +++ b/.tuist-version @@ -0,0 +1 @@ +3.22.0 \ No newline at end of file diff --git a/Box42.xcodeproj/project.pbxproj b/Box42.xcodeproj/project.pbxproj index 8fbe226..54be299 100644 --- a/Box42.xcodeproj/project.pbxproj +++ b/Box42.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ @@ -15,18 +15,58 @@ DE018BE72A509B1E00FF0AA3 /* WebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE018BE62A509B1E00FF0AA3 /* WebViewController.swift */; }; DE018BEA2A509B2100FF0AA3 /* WebViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE018BE92A509B2100FF0AA3 /* WebViewModel.swift */; }; DE018BED2A509B2600FF0AA3 /* URLModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE018BEC2A509B2600FF0AA3 /* URLModel.swift */; }; - DE018BF02A509B2F00FF0AA3 /* MenubarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE018BEF2A509B2F00FF0AA3 /* MenubarController.swift */; }; + DE018BF02A509B2F00FF0AA3 /* MenubarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE018BEF2A509B2F00FF0AA3 /* MenubarViewController.swift */; }; DE018BF32A509B3300FF0AA3 /* MenubarModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE018BF22A509B3300FF0AA3 /* MenubarModel.swift */; }; - DE018BF62A509B3600FF0AA3 /* MenubarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE018BF52A509B3600FF0AA3 /* MenubarView.swift */; }; - DE018BF92A509B3B00FF0AA3 /* BoxController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE018BF82A509B3B00FF0AA3 /* BoxController.swift */; }; - DE018BFC2A509B3E00FF0AA3 /* BoxModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE018BFB2A509B3E00FF0AA3 /* BoxModel.swift */; }; - DE018BFF2A509B4200FF0AA3 /* BoxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE018BFE2A509B4200FF0AA3 /* BoxView.swift */; }; DE018C032A509B5D00FF0AA3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DE018C022A509B5D00FF0AA3 /* Main.storyboard */; }; - DE7A257A2A6D8CA20043225A /* PreferencesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE7A25792A6D8CA20043225A /* PreferencesController.swift */; }; + DE0A915D2A8E348D00D1D6F1 /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = DE0A915C2A8E348D00D1D6F1 /* SnapKit */; }; + DE0A91632A8E6A5400D1D6F1 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0A91622A8E6A5400D1D6F1 /* Constants.swift */; }; + DE0A91672A8E6CA700D1D6F1 /* WebViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0A91662A8E6CA700D1D6F1 /* WebViewManager.swift */; }; + DE0A916D2A8E7DD700D1D6F1 /* HoverButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0A916C2A8E7DD700D1D6F1 /* HoverButton.swift */; }; + DE0A91782A8F014F00D1D6F1 /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0A91772A8F014F00D1D6F1 /* WebView.swift */; }; + DE0A917B2A8F0CA800D1D6F1 /* AppleScripts+ShowMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0A917A2A8F0CA800D1D6F1 /* AppleScripts+ShowMessage.swift */; }; + DE0A917F2A8F865400D1D6F1 /* BoxToolbarViewGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0A917E2A8F865400D1D6F1 /* BoxToolbarViewGroup.swift */; }; + DE0A91832A8F889000D1D6F1 /* GoHomePageViaToolbar().swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0A91822A8F889000D1D6F1 /* GoHomePageViaToolbar().swift */; }; + DE0A91862A8F889F00D1D6F1 /* RefreshPageViaToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0A91852A8F889F00D1D6F1 /* RefreshPageViaToolbar.swift */; }; + DE0A918A2A8F88A900D1D6F1 /* GoForwardInToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0A91892A8F88A900D1D6F1 /* GoForwardInToolbar.swift */; }; + DE0A918D2A8F88BC00D1D6F1 /* GoBackInToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0A918C2A8F88BC00D1D6F1 /* GoBackInToolbar.swift */; }; + DE0A91902A8F88CA00D1D6F1 /* DisplayURLInToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0A918F2A8F88CA00D1D6F1 /* DisplayURLInToolbar.swift */; }; + DE0A91982A8F977F00D1D6F1 /* ToolbarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0A91972A8F977F00D1D6F1 /* ToolbarViewController.swift */; }; + DE0A91A72A8FC66600D1D6F1 /* SideBarLeading.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0A91A62A8FC66600D1D6F1 /* SideBarLeading.swift */; }; + DE1F1A142A8B506600A88DD8 /* importMacOSInfo.sh in Resources */ = {isa = PBXBuildFile; fileRef = DE1F1A112A8B506600A88DD8 /* importMacOSInfo.sh */; }; + DE1F1A152A8B506600A88DD8 /* exportMacOSInfo.sh in Resources */ = {isa = PBXBuildFile; fileRef = DE1F1A122A8B506600A88DD8 /* exportMacOSInfo.sh */; }; + DE1F1A162A8B506600A88DD8 /* keyMapping.sh in Resources */ = {isa = PBXBuildFile; fileRef = DE1F1A132A8B506600A88DD8 /* keyMapping.sh */; }; + DE1F1A1C2A8B50C500A88DD8 /* BoxBaseContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE1F1A192A8B50C500A88DD8 /* BoxBaseContainerViewController.swift */; }; + DE1F1A1D2A8B50C500A88DD8 /* BoxContentsViewGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE1F1A1A2A8B50C500A88DD8 /* BoxContentsViewGroup.swift */; }; + DE1F1A1E2A8B50C500A88DD8 /* BoxButtonViewGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE1F1A1B2A8B50C500A88DD8 /* BoxButtonViewGroup.swift */; }; + DE1F1A262A8B50D500A88DD8 /* BoxViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE1F1A232A8B50D500A88DD8 /* BoxViewController.swift */; }; + DE1F1A292A8B50E200A88DD8 /* BoxSizeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE1F1A282A8B50E200A88DD8 /* BoxSizeManager.swift */; }; + DE1F1A2E2A8BCC9800A88DD8 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE1F1A2D2A8BCC9800A88DD8 /* Storage.swift */; }; + DE1F1A312A8BD68F00A88DD8 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE1F1A302A8BD68F00A88DD8 /* Double.swift */; }; + DE1F1A362A8BDDDF00A88DD8 /* StorageConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE1F1A352A8BDDDF00A88DD8 /* StorageConfig.swift */; }; + DE24E6352A8FE02A00E29F5D /* MovableContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE24E6342A8FE02A00E29F5D /* MovableContainerView.swift */; }; + DE24E6382A8FE10400E29F5D /* BoxBaseSplitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE24E6372A8FE10300E29F5D /* BoxBaseSplitView.swift */; }; + DE24E63B2A8FE93900E29F5D /* NSImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE24E63A2A8FE93900E29F5D /* NSImage.swift */; }; + DE2AD3292A824EEB00002D51 /* Accessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE2AD3282A824EEB00002D51 /* Accessibility.swift */; }; + DE4407FA2A923E860091937A /* BoxFunctionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4407F92A923E860091937A /* BoxFunctionViewController.swift */; }; + DE4407FE2A923EA90091937A /* PreferenceButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4407FD2A923EA90091937A /* PreferenceButtonView.swift */; }; + DE4408022A923EB60091937A /* PinButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4408012A923EB60091937A /* PinButtonView.swift */; }; + DE4408052A923EC00091937A /* QuitButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4408042A923EC00091937A /* QuitButtonView.swift */; }; + DE4408082A9240300091937A /* BoxFunctionButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4408072A9240300091937A /* BoxFunctionButtonView.swift */; }; + DE44080C2A924B520091937A /* BoxFunctionViewGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE44080B2A924B520091937A /* BoxFunctionViewGroup.swift */; }; + DE4408152A92750D0091937A /* keyDown+BoxViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4408142A92750D0091937A /* keyDown+BoxViewController.swift */; }; + DE44081D2A928F760091937A /* TopDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE44081C2A928F760091937A /* TopDivider.swift */; }; + DE77BA512A82580400713683 /* MenubarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE77BA502A82580400713683 /* MenubarViewModel.swift */; }; + DE77BA562A82637900713683 /* StateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE77BA552A82637900713683 /* StateManager.swift */; }; + DE7A257A2A6D8CA20043225A /* PreferencesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE7A25792A6D8CA20043225A /* PreferencesViewController.swift */; }; DE874F4E2A591DEA00FC3B77 /* Hotkey.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE874F4D2A591DEA00FC3B77 /* Hotkey.swift */; }; DE874F542A591F1400FC3B77 /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE874F532A591F1400FC3B77 /* PreferencesView.swift */; }; DE874F572A591F2500FC3B77 /* Icon.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE874F562A591F2500FC3B77 /* Icon.swift */; }; - DE874F5F2A5935CC00FC3B77 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE874F5E2A5935CC00FC3B77 /* StringExtension.swift */; }; + DE874F5F2A5935CC00FC3B77 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE874F5E2A5935CC00FC3B77 /* String.swift */; }; + DEB862D42A85124500278FCD /* cleanCache.sh in Resources */ = {isa = PBXBuildFile; fileRef = DEB862D32A85124500278FCD /* cleanCache.sh */; }; + DEB862D92A852C4500278FCD /* brewInGoinfre.sh in Resources */ = {isa = PBXBuildFile; fileRef = DEB862D82A852C4500278FCD /* brewInGoinfre.sh */; }; + DEB862DC2A85347400278FCD /* Scripts.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEB862DB2A85347400278FCD /* Scripts.swift */; }; + DEB862EB2A853F7F00278FCD /* BoxWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEB862E92A853F7F00278FCD /* BoxWindowController.swift */; }; + DEF749322A85657600D987C8 /* NSScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEF749312A85657600D987C8 /* NSScreen.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -40,19 +80,59 @@ DE018BE62A509B1E00FF0AA3 /* WebViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebViewController.swift; sourceTree = ""; }; DE018BE92A509B2100FF0AA3 /* WebViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebViewModel.swift; sourceTree = ""; }; DE018BEC2A509B2600FF0AA3 /* URLModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLModel.swift; sourceTree = ""; }; - DE018BEF2A509B2F00FF0AA3 /* MenubarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenubarController.swift; sourceTree = ""; }; + DE018BEF2A509B2F00FF0AA3 /* MenubarViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenubarViewController.swift; sourceTree = ""; }; DE018BF22A509B3300FF0AA3 /* MenubarModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenubarModel.swift; sourceTree = ""; }; - DE018BF52A509B3600FF0AA3 /* MenubarView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenubarView.swift; sourceTree = ""; }; - DE018BF82A509B3B00FF0AA3 /* BoxController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoxController.swift; sourceTree = ""; }; - DE018BFB2A509B3E00FF0AA3 /* BoxModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoxModel.swift; sourceTree = ""; }; - DE018BFE2A509B4200FF0AA3 /* BoxView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoxView.swift; sourceTree = ""; }; DE018C022A509B5D00FF0AA3 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; DE018C192A509DBA00FF0AA3 /* Box42.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Box42.entitlements; sourceTree = ""; }; - DE7A25792A6D8CA20043225A /* PreferencesController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesController.swift; sourceTree = ""; }; + DE0A91622A8E6A5400D1D6F1 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; + DE0A91662A8E6CA700D1D6F1 /* WebViewManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewManager.swift; sourceTree = ""; }; + DE0A916C2A8E7DD700D1D6F1 /* HoverButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HoverButton.swift; sourceTree = ""; }; + DE0A91772A8F014F00D1D6F1 /* WebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebView.swift; sourceTree = ""; }; + DE0A917A2A8F0CA800D1D6F1 /* AppleScripts+ShowMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppleScripts+ShowMessage.swift"; sourceTree = ""; }; + DE0A917E2A8F865400D1D6F1 /* BoxToolbarViewGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoxToolbarViewGroup.swift; sourceTree = ""; }; + DE0A91822A8F889000D1D6F1 /* GoHomePageViaToolbar().swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GoHomePageViaToolbar().swift"; sourceTree = ""; }; + DE0A91852A8F889F00D1D6F1 /* RefreshPageViaToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshPageViaToolbar.swift; sourceTree = ""; }; + DE0A91892A8F88A900D1D6F1 /* GoForwardInToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoForwardInToolbar.swift; sourceTree = ""; }; + DE0A918C2A8F88BC00D1D6F1 /* GoBackInToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoBackInToolbar.swift; sourceTree = ""; }; + DE0A918F2A8F88CA00D1D6F1 /* DisplayURLInToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayURLInToolbar.swift; sourceTree = ""; }; + DE0A91972A8F977F00D1D6F1 /* ToolbarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarViewController.swift; sourceTree = ""; }; + DE0A91A62A8FC66600D1D6F1 /* SideBarLeading.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SideBarLeading.swift; sourceTree = ""; }; + DE1F1A112A8B506600A88DD8 /* importMacOSInfo.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = importMacOSInfo.sh; sourceTree = ""; }; + DE1F1A122A8B506600A88DD8 /* exportMacOSInfo.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = exportMacOSInfo.sh; sourceTree = ""; }; + DE1F1A132A8B506600A88DD8 /* keyMapping.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = keyMapping.sh; sourceTree = ""; }; + DE1F1A192A8B50C500A88DD8 /* BoxBaseContainerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BoxBaseContainerViewController.swift; path = Box/BoxBaseContainerViewController.swift; sourceTree = ""; }; + DE1F1A1A2A8B50C500A88DD8 /* BoxContentsViewGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoxContentsViewGroup.swift; sourceTree = ""; }; + DE1F1A1B2A8B50C500A88DD8 /* BoxButtonViewGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoxButtonViewGroup.swift; sourceTree = ""; }; + DE1F1A232A8B50D500A88DD8 /* BoxViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BoxViewController.swift; path = Main/BoxViewController.swift; sourceTree = ""; }; + DE1F1A282A8B50E200A88DD8 /* BoxSizeManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoxSizeManager.swift; sourceTree = ""; }; + DE1F1A2D2A8BCC9800A88DD8 /* Storage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = ""; }; + DE1F1A302A8BD68F00A88DD8 /* Double.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Double.swift; sourceTree = ""; }; + DE1F1A352A8BDDDF00A88DD8 /* StorageConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageConfig.swift; sourceTree = ""; }; + DE24E6342A8FE02A00E29F5D /* MovableContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MovableContainerView.swift; sourceTree = ""; }; + DE24E6372A8FE10300E29F5D /* BoxBaseSplitView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoxBaseSplitView.swift; sourceTree = ""; }; + DE24E63A2A8FE93900E29F5D /* NSImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSImage.swift; sourceTree = ""; }; + DE2AD3282A824EEB00002D51 /* Accessibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Accessibility.swift; sourceTree = ""; }; + DE4407F92A923E860091937A /* BoxFunctionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoxFunctionViewController.swift; sourceTree = ""; }; + DE4407FD2A923EA90091937A /* PreferenceButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferenceButtonView.swift; sourceTree = ""; }; + DE4408012A923EB60091937A /* PinButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinButtonView.swift; sourceTree = ""; }; + DE4408042A923EC00091937A /* QuitButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuitButtonView.swift; sourceTree = ""; }; + DE4408072A9240300091937A /* BoxFunctionButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoxFunctionButtonView.swift; sourceTree = ""; }; + DE44080B2A924B520091937A /* BoxFunctionViewGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoxFunctionViewGroup.swift; sourceTree = ""; }; + DE4408142A92750D0091937A /* keyDown+BoxViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "keyDown+BoxViewController.swift"; path = "Main/keyDown+BoxViewController.swift"; sourceTree = ""; }; + DE44081C2A928F760091937A /* TopDivider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopDivider.swift; sourceTree = ""; }; + DE77BA502A82580400713683 /* MenubarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenubarViewModel.swift; sourceTree = ""; }; + DE77BA552A82637900713683 /* StateManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateManager.swift; sourceTree = ""; }; + DE7A25792A6D8CA20043225A /* PreferencesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesViewController.swift; sourceTree = ""; }; DE874F4D2A591DEA00FC3B77 /* Hotkey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Hotkey.swift; sourceTree = ""; }; DE874F532A591F1400FC3B77 /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = ""; }; DE874F562A591F2500FC3B77 /* Icon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Icon.swift; sourceTree = ""; }; - DE874F5E2A5935CC00FC3B77 /* StringExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtension.swift; sourceTree = ""; }; + DE874F5E2A5935CC00FC3B77 /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = ""; }; + DEB862D32A85124500278FCD /* cleanCache.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = cleanCache.sh; sourceTree = ""; }; + DEB862D82A852C4500278FCD /* brewInGoinfre.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = brewInGoinfre.sh; sourceTree = ""; }; + DEB862DB2A85347400278FCD /* Scripts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Scripts.swift; path = Box42/Scripts/Scripts.swift; sourceTree = SOURCE_ROOT; }; + DEB862E92A853F7F00278FCD /* BoxWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoxWindowController.swift; sourceTree = ""; }; + DEF7492E2A85603700D987C8 /* nodeInstall.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = nodeInstall.sh; sourceTree = ""; }; + DEF749312A85657600D987C8 /* NSScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSScreen.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -60,6 +140,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + DE0A915D2A8E348D00D1D6F1 /* SnapKit in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -71,6 +152,7 @@ children = ( DE018BB12A5099F900FF0AA3 /* Box42 */, DE018BB02A5099F900FF0AA3 /* Products */, + DE17AF722A834A1600325BF4 /* Frameworks */, ); sourceTree = ""; }; @@ -85,31 +167,43 @@ DE018BB12A5099F900FF0AA3 /* Box42 */ = { isa = PBXGroup; children = ( + DE0A916B2A8E7DC700D1D6F1 /* UI */, + DE1F1A202A8B50CA00A88DD8 /* Main */, + DEF749302A85655E00D987C8 /* Extensions */, + DEB862E82A853F6800278FCD /* Window */, + DEB862D22A8511D600278FCD /* Scripts */, + DE77BA542A82636500713683 /* Shared */, DE874F512A591EC600FC3B77 /* Preferences */, - DE874F4C2A591DC400FC3B77 /* Hotkey */, DE018C0C2A509BDF00FF0AA3 /* Resources */, - DE018C062A509B9000FF0AA3 /* CPU */, + DE018C062A509B9000FF0AA3 /* System */, DE018C082A509BB500FF0AA3 /* WebView */, - DE018C0B2A509BC100FF0AA3 /* URL */, + DE0A917D2A8F864300D1D6F1 /* Toolbar */, + DE4407F82A923E5B0091937A /* FunctionButton */, + DE1F1A182A8B50BB00A88DD8 /* Box */, DE018C0E2A509C0C00FF0AA3 /* Menubar */, - DE018C102A509C1A00FF0AA3 /* Box */, ); path = Box42; sourceTree = ""; }; - DE018C062A509B9000FF0AA3 /* CPU */ = { + DE018C062A509B9000FF0AA3 /* System */ = { isa = PBXGroup; children = ( + DE018BDC2A509AEB00FF0AA3 /* EventMonitor.swift */, DE018BE32A509B1700FF0AA3 /* CPU.swift */, + DE1F1A2D2A8BCC9800A88DD8 /* Storage.swift */, + DE1F1A352A8BDDDF00A88DD8 /* StorageConfig.swift */, ); - path = CPU; + path = System; sourceTree = ""; }; DE018C082A509BB500FF0AA3 /* WebView */ = { isa = PBXGroup; children = ( + DE018C0B2A509BC100FF0AA3 /* URL */, + DE0A91662A8E6CA700D1D6F1 /* WebViewManager.swift */, DE018BE92A509B2100FF0AA3 /* WebViewModel.swift */, DE018BE62A509B1E00FF0AA3 /* WebViewController.swift */, + DE0A91772A8F014F00D1D6F1 /* WebView.swift */, ); path = WebView; sourceTree = ""; @@ -125,14 +219,13 @@ DE018C0C2A509BDF00FF0AA3 /* Resources */ = { isa = PBXGroup; children = ( + DEB862DE2A85348600278FCD /* sh */, DE018C192A509DBA00FF0AA3 /* Box42.entitlements */, DE018BB22A5099F900FF0AA3 /* AppDelegate.swift */, DE018BDF2A509B0600FF0AA3 /* Assets.xcassets */, DE018BBE2A5099FA00FF0AA3 /* Info.plist */, DE018C022A509B5D00FF0AA3 /* Main.storyboard */, - DE018BDC2A509AEB00FF0AA3 /* EventMonitor.swift */, DE018BB62A5099F900FF0AA3 /* Box42.xcdatamodeld */, - DE874F5E2A5935CC00FC3B77 /* StringExtension.swift */, ); path = Resources; sourceTree = ""; @@ -140,41 +233,166 @@ DE018C0E2A509C0C00FF0AA3 /* Menubar */ = { isa = PBXGroup; children = ( - DE018BEF2A509B2F00FF0AA3 /* MenubarController.swift */, + DE018BEF2A509B2F00FF0AA3 /* MenubarViewController.swift */, DE018BF22A509B3300FF0AA3 /* MenubarModel.swift */, - DE018BF52A509B3600FF0AA3 /* MenubarView.swift */, + DE77BA502A82580400713683 /* MenubarViewModel.swift */, ); path = Menubar; sourceTree = ""; }; - DE018C102A509C1A00FF0AA3 /* Box */ = { + DE0A916B2A8E7DC700D1D6F1 /* UI */ = { isa = PBXGroup; children = ( - DE018BF82A509B3B00FF0AA3 /* BoxController.swift */, - DE018BFB2A509B3E00FF0AA3 /* BoxModel.swift */, - DE018BFE2A509B4200FF0AA3 /* BoxView.swift */, + DE0A916C2A8E7DD700D1D6F1 /* HoverButton.swift */, + DE24E6342A8FE02A00E29F5D /* MovableContainerView.swift */, ); - path = Box; + path = UI; sourceTree = ""; }; - DE874F4C2A591DC400FC3B77 /* Hotkey */ = { + DE0A917D2A8F864300D1D6F1 /* Toolbar */ = { isa = PBXGroup; children = ( - DE874F4D2A591DEA00FC3B77 /* Hotkey.swift */, + DE0A919E2A8FA15300D1D6F1 /* View */, + DE0A91972A8F977F00D1D6F1 /* ToolbarViewController.swift */, + ); + path = Toolbar; + sourceTree = ""; + }; + DE0A919E2A8FA15300D1D6F1 /* View */ = { + isa = PBXGroup; + children = ( + DE0A91A62A8FC66600D1D6F1 /* SideBarLeading.swift */, + DE0A91822A8F889000D1D6F1 /* GoHomePageViaToolbar().swift */, + DE0A918F2A8F88CA00D1D6F1 /* DisplayURLInToolbar.swift */, + DE0A918C2A8F88BC00D1D6F1 /* GoBackInToolbar.swift */, + DE0A91892A8F88A900D1D6F1 /* GoForwardInToolbar.swift */, + DE0A91852A8F889F00D1D6F1 /* RefreshPageViaToolbar.swift */, + DE0A917E2A8F865400D1D6F1 /* BoxToolbarViewGroup.swift */, + ); + path = View; + sourceTree = ""; + }; + DE17AF722A834A1600325BF4 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; + DE1F1A182A8B50BB00A88DD8 /* Box */ = { + isa = PBXGroup; + children = ( + DE4408202A9297EE0091937A /* View */, + DE1F1A192A8B50C500A88DD8 /* BoxBaseContainerViewController.swift */, + ); + name = Box; + sourceTree = ""; + }; + DE1F1A202A8B50CA00A88DD8 /* Main */ = { + isa = PBXGroup; + children = ( + DE1F1A232A8B50D500A88DD8 /* BoxViewController.swift */, + DE4408142A92750D0091937A /* keyDown+BoxViewController.swift */, ); - path = Hotkey; + name = Main; + sourceTree = ""; + }; + DE4407F82A923E5B0091937A /* FunctionButton */ = { + isa = PBXGroup; + children = ( + DE4407FC2A923E920091937A /* View */, + DE4407F92A923E860091937A /* BoxFunctionViewController.swift */, + ); + path = FunctionButton; + sourceTree = ""; + }; + DE4407FC2A923E920091937A /* View */ = { + isa = PBXGroup; + children = ( + DE44081C2A928F760091937A /* TopDivider.swift */, + DE4407FD2A923EA90091937A /* PreferenceButtonView.swift */, + DE4408012A923EB60091937A /* PinButtonView.swift */, + DE4408042A923EC00091937A /* QuitButtonView.swift */, + DE4408072A9240300091937A /* BoxFunctionButtonView.swift */, + DE44080B2A924B520091937A /* BoxFunctionViewGroup.swift */, + ); + path = View; + sourceTree = ""; + }; + DE4408202A9297EE0091937A /* View */ = { + isa = PBXGroup; + children = ( + DE1F1A1B2A8B50C500A88DD8 /* BoxButtonViewGroup.swift */, + DE1F1A1A2A8B50C500A88DD8 /* BoxContentsViewGroup.swift */, + DE24E6372A8FE10300E29F5D /* BoxBaseSplitView.swift */, + ); + name = View; + path = Box/View; + sourceTree = ""; + }; + DE77BA542A82636500713683 /* Shared */ = { + isa = PBXGroup; + children = ( + DE1F1A282A8B50E200A88DD8 /* BoxSizeManager.swift */, + DE77BA552A82637900713683 /* StateManager.swift */, + DE0A91622A8E6A5400D1D6F1 /* Constants.swift */, + ); + path = Shared; sourceTree = ""; }; DE874F512A591EC600FC3B77 /* Preferences */ = { isa = PBXGroup; children = ( - DE7A25792A6D8CA20043225A /* PreferencesController.swift */, + DE7A25792A6D8CA20043225A /* PreferencesViewController.swift */, DE874F532A591F1400FC3B77 /* PreferencesView.swift */, DE874F562A591F2500FC3B77 /* Icon.swift */, + DE2AD3282A824EEB00002D51 /* Accessibility.swift */, + DE874F4D2A591DEA00FC3B77 /* Hotkey.swift */, ); path = Preferences; sourceTree = ""; }; + DEB862D22A8511D600278FCD /* Scripts */ = { + isa = PBXGroup; + children = ( + DEB862DB2A85347400278FCD /* Scripts.swift */, + DE0A917A2A8F0CA800D1D6F1 /* AppleScripts+ShowMessage.swift */, + ); + path = Scripts; + sourceTree = ""; + }; + DEB862DE2A85348600278FCD /* sh */ = { + isa = PBXGroup; + children = ( + DE1F1A122A8B506600A88DD8 /* exportMacOSInfo.sh */, + DE1F1A112A8B506600A88DD8 /* importMacOSInfo.sh */, + DE1F1A132A8B506600A88DD8 /* keyMapping.sh */, + DEB862D32A85124500278FCD /* cleanCache.sh */, + DEB862D82A852C4500278FCD /* brewInGoinfre.sh */, + DEF7492E2A85603700D987C8 /* nodeInstall.sh */, + ); + path = sh; + sourceTree = ""; + }; + DEB862E82A853F6800278FCD /* Window */ = { + isa = PBXGroup; + children = ( + DEB862E92A853F7F00278FCD /* BoxWindowController.swift */, + ); + path = Window; + sourceTree = ""; + }; + DEF749302A85655E00D987C8 /* Extensions */ = { + isa = PBXGroup; + children = ( + DE874F5E2A5935CC00FC3B77 /* String.swift */, + DEF749312A85657600D987C8 /* NSScreen.swift */, + DE1F1A302A8BD68F00A88DD8 /* Double.swift */, + DE24E63A2A8FE93900E29F5D /* NSImage.swift */, + ); + path = Extensions; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -191,6 +409,9 @@ dependencies = ( ); name = Box42; + packageProductDependencies = ( + DE0A915C2A8E348D00D1D6F1 /* SnapKit */, + ); productName = Box42; productReference = DE018BAF2A5099F900FF0AA3 /* Box42.app */; productType = "com.apple.product-type.application"; @@ -218,6 +439,9 @@ Base, ); mainGroup = DE018BA62A5099F900FF0AA3; + packageReferences = ( + DE0A915B2A8E348D00D1D6F1 /* XCRemoteSwiftPackageReference "SnapKit" */, + ); productRefGroup = DE018BB02A5099F900FF0AA3 /* Products */; projectDirPath = ""; projectRoot = ""; @@ -232,7 +456,12 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + DE1F1A142A8B506600A88DD8 /* importMacOSInfo.sh in Resources */, DE018C032A509B5D00FF0AA3 /* Main.storyboard in Resources */, + DE1F1A152A8B506600A88DD8 /* exportMacOSInfo.sh in Resources */, + DE1F1A162A8B506600A88DD8 /* keyMapping.sh in Resources */, + DEB862D42A85124500278FCD /* cleanCache.sh in Resources */, + DEB862D92A852C4500278FCD /* brewInGoinfre.sh in Resources */, DE018BE02A509B0600FF0AA3 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -244,23 +473,57 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - DE018BFF2A509B4200FF0AA3 /* BoxView.swift in Sources */, + DE0A91A72A8FC66600D1D6F1 /* SideBarLeading.swift in Sources */, + DE0A917B2A8F0CA800D1D6F1 /* AppleScripts+ShowMessage.swift in Sources */, + DE1F1A262A8B50D500A88DD8 /* BoxViewController.swift in Sources */, DE018BB82A5099F900FF0AA3 /* Box42.xcdatamodeld in Sources */, DE874F542A591F1400FC3B77 /* PreferencesView.swift in Sources */, - DE018BF62A509B3600FF0AA3 /* MenubarView.swift in Sources */, + DE0A91982A8F977F00D1D6F1 /* ToolbarViewController.swift in Sources */, + DE4408082A9240300091937A /* BoxFunctionButtonView.swift in Sources */, + DE77BA562A82637900713683 /* StateManager.swift in Sources */, + DE1F1A1C2A8B50C500A88DD8 /* BoxBaseContainerViewController.swift in Sources */, DE018BE72A509B1E00FF0AA3 /* WebViewController.swift in Sources */, - DE018BF92A509B3B00FF0AA3 /* BoxController.swift in Sources */, - DE018BF02A509B2F00FF0AA3 /* MenubarController.swift in Sources */, + DE4407FA2A923E860091937A /* BoxFunctionViewController.swift in Sources */, + DE4407FE2A923EA90091937A /* PreferenceButtonView.swift in Sources */, + DEF749322A85657600D987C8 /* NSScreen.swift in Sources */, + DE018BF02A509B2F00FF0AA3 /* MenubarViewController.swift in Sources */, + DE77BA512A82580400713683 /* MenubarViewModel.swift in Sources */, + DE44080C2A924B520091937A /* BoxFunctionViewGroup.swift in Sources */, DE018BE42A509B1700FF0AA3 /* CPU.swift in Sources */, - DE874F5F2A5935CC00FC3B77 /* StringExtension.swift in Sources */, + DE874F5F2A5935CC00FC3B77 /* String.swift in Sources */, + DE0A91862A8F889F00D1D6F1 /* RefreshPageViaToolbar.swift in Sources */, DE874F4E2A591DEA00FC3B77 /* Hotkey.swift in Sources */, + DE0A91832A8F889000D1D6F1 /* GoHomePageViaToolbar().swift in Sources */, DE018BB32A5099F900FF0AA3 /* AppDelegate.swift in Sources */, + DE0A91632A8E6A5400D1D6F1 /* Constants.swift in Sources */, + DE0A91902A8F88CA00D1D6F1 /* DisplayURLInToolbar.swift in Sources */, DE018BF32A509B3300FF0AA3 /* MenubarModel.swift in Sources */, - DE7A257A2A6D8CA20043225A /* PreferencesController.swift in Sources */, + DE7A257A2A6D8CA20043225A /* PreferencesViewController.swift in Sources */, + DE24E63B2A8FE93900E29F5D /* NSImage.swift in Sources */, + DE0A916D2A8E7DD700D1D6F1 /* HoverButton.swift in Sources */, + DE4408022A923EB60091937A /* PinButtonView.swift in Sources */, + DE0A91672A8E6CA700D1D6F1 /* WebViewManager.swift in Sources */, + DE4408152A92750D0091937A /* keyDown+BoxViewController.swift in Sources */, DE018BED2A509B2600FF0AA3 /* URLModel.swift in Sources */, - DE018BFC2A509B3E00FF0AA3 /* BoxModel.swift in Sources */, + DE4408052A923EC00091937A /* QuitButtonView.swift in Sources */, + DE0A918A2A8F88A900D1D6F1 /* GoForwardInToolbar.swift in Sources */, + DE1F1A1E2A8B50C500A88DD8 /* BoxButtonViewGroup.swift in Sources */, + DEB862EB2A853F7F00278FCD /* BoxWindowController.swift in Sources */, + DE0A918D2A8F88BC00D1D6F1 /* GoBackInToolbar.swift in Sources */, DE018BDD2A509AEB00FF0AA3 /* EventMonitor.swift in Sources */, + DE1F1A292A8B50E200A88DD8 /* BoxSizeManager.swift in Sources */, + DEB862DC2A85347400278FCD /* Scripts.swift in Sources */, + DE1F1A1D2A8B50C500A88DD8 /* BoxContentsViewGroup.swift in Sources */, + DE24E6352A8FE02A00E29F5D /* MovableContainerView.swift in Sources */, + DE1F1A362A8BDDDF00A88DD8 /* StorageConfig.swift in Sources */, + DE2AD3292A824EEB00002D51 /* Accessibility.swift in Sources */, + DE24E6382A8FE10400E29F5D /* BoxBaseSplitView.swift in Sources */, + DE44081D2A928F760091937A /* TopDivider.swift in Sources */, DE874F572A591F2500FC3B77 /* Icon.swift in Sources */, + DE1F1A2E2A8BCC9800A88DD8 /* Storage.swift in Sources */, + DE0A91782A8F014F00D1D6F1 /* WebView.swift in Sources */, + DE1F1A312A8BD68F00A88DD8 /* Double.swift in Sources */, + DE0A917F2A8F865400D1D6F1 /* BoxToolbarViewGroup.swift in Sources */, DE018BEA2A509B2100FF0AA3 /* WebViewModel.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -388,7 +651,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_ENTITLEMENTS = Box42/Box42.entitlements; + CODE_SIGN_ENTITLEMENTS = Box42/Resources/Box42.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Box42/Resources/Info.plist; @@ -396,6 +659,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = com.chanheki.Box42; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -407,7 +671,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_ENTITLEMENTS = Box42/Box42.entitlements; + CODE_SIGN_ENTITLEMENTS = Box42/Resources/Box42.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Box42/Resources/Info.plist; @@ -415,6 +679,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = com.chanheki.Box42; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -444,6 +709,25 @@ }; /* End XCConfigurationList section */ +/* Begin XCRemoteSwiftPackageReference section */ + DE0A915B2A8E348D00D1D6F1 /* XCRemoteSwiftPackageReference "SnapKit" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/SnapKit/SnapKit.git"; + requirement = { + kind = exactVersion; + version = 5.6.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + DE0A915C2A8E348D00D1D6F1 /* SnapKit */ = { + isa = XCSwiftPackageProductDependency; + package = DE0A915B2A8E348D00D1D6F1 /* XCRemoteSwiftPackageReference "SnapKit" */; + productName = SnapKit; + }; +/* End XCSwiftPackageProductDependency section */ + /* Begin XCVersionGroup section */ DE018BB62A5099F900FF0AA3 /* Box42.xcdatamodeld */ = { isa = XCVersionGroup; diff --git a/Box42.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Box42.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..19d4e8c --- /dev/null +++ b/Box42.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,16 @@ +{ + "object": { + "pins": [ + { + "package": "SnapKit", + "repositoryURL": "https://github.com/SnapKit/SnapKit.git", + "state": { + "branch": null, + "revision": "f222cbdf325885926566172f6f5f06af95473158", + "version": "5.6.0" + } + } + ] + }, + "version": 1 +} diff --git a/Box42.xcodeproj/project.xcworkspace/xcuserdata/chanheki.xcuserdatad/UserInterfaceState.xcuserstate b/Box42.xcodeproj/project.xcworkspace/xcuserdata/chanheki.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index d95c6a9..0000000 Binary files a/Box42.xcodeproj/project.xcworkspace/xcuserdata/chanheki.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ diff --git a/Box42.xcodeproj/project.xcworkspace/xcuserdata/daskim.xcuserdatad/UserInterfaceState.xcuserstate b/Box42.xcodeproj/project.xcworkspace/xcuserdata/daskim.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..8f50922 Binary files /dev/null and b/Box42.xcodeproj/project.xcworkspace/xcuserdata/daskim.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Box42.xcodeproj/xcshareddata/xcschemes/Box42.xcscheme b/Box42.xcodeproj/xcshareddata/xcschemes/Box42.xcscheme new file mode 100644 index 0000000..d8294f7 --- /dev/null +++ b/Box42.xcodeproj/xcshareddata/xcschemes/Box42.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Box42.xcodeproj/xcuserdata/chanheki.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Box42.xcodeproj/xcuserdata/chanheki.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist deleted file mode 100644 index e9d969f..0000000 --- a/Box42.xcodeproj/xcuserdata/chanheki.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - diff --git a/Box42.xcodeproj/xcuserdata/chanheki.xcuserdatad/xcschemes/xcschememanagement.plist b/Box42.xcodeproj/xcuserdata/chanheki.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index 2d4f387..0000000 --- a/Box42.xcodeproj/xcuserdata/chanheki.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,14 +0,0 @@ - - - - - SchemeUserState - - Box42.xcscheme_^#shared#^_ - - orderHint - 0 - - - - diff --git a/Box42/Box/BoxBaseContainerViewController.swift b/Box42/Box/BoxBaseContainerViewController.swift new file mode 100644 index 0000000..538078f --- /dev/null +++ b/Box42/Box/BoxBaseContainerViewController.swift @@ -0,0 +1,129 @@ +// +// BoxBaseContainerViewController.swift +// Box42 +// +// Created by Chan on 2023/03/17. +// + +import Cocoa +import SnapKit + +class BoxBaseContainerViewController: NSViewController { + var splitView: BoxBaseSplitView! = BoxBaseSplitView() + var contentGroup: BoxContentsViewGroup! = BoxContentsViewGroup() + var toolbarGroup: BoxToolbarViewGroup! = BoxToolbarViewGroup() + var functionGroupVC: BoxFunctionViewController! = BoxFunctionViewController() + var buttonGroup: BoxButtonViewGroup! + var leftContainer: MovableContainerView! + + override func loadView() { + self.view = NSView() + self.view.addSubview(splitView) + splitView.delegate = self + + buttonGroup = BoxButtonViewGroupInit() + + leftContainerInit() + viewInit() + } + + func BoxButtonViewGroupInit() -> BoxButtonViewGroup { + let buttonGroup = BoxButtonViewGroup { sender in + self.clickBtn(sender: sender) + } + return buttonGroup + } + + func clickBtn(sender: NSButton) { + guard let clickCount = NSApp.currentEvent?.clickCount else { return } + if clickCount == 2 { + WebViewManager.shared.list[sender.title]!.reload() + print("Dobule Click") + } else if clickCount > 2 { + if let currentURL = WebViewManager.shared.hostingWebView?.url { + NSWorkspace.shared.open(currentURL) + } + print("Triple Click") + } else if clickCount < 2 { + contentGroup.removeAllSubviews() + contentGroup.showWebviews(sender) + } + } + + private func leftContainerInit() { + leftContainer = MovableContainerView() + leftContainer.addSubview(buttonGroup) + leftContainer.addSubview(toolbarGroup) + leftContainer.addSubview(functionGroupVC.view) + leftContainerAutolayout() + leftContainer.frame.size.width = BoxSizeManager.shared.windowButtonGroupSize.width + } + + private func leftContainerAutolayout() { + toolbarGroup.snp.makeConstraints { make in + make.top.equalTo(leftContainer).offset(Constants.UI.GroupAutolayout) + make.right.equalTo(leftContainer).offset(-Constants.UI.GroupAutolayout) + make.left.equalTo(leftContainer) + } + + buttonGroup.snp.makeConstraints { make in + make.top.equalTo(toolbarGroup.snp.bottom).offset(Constants.UI.GroupAutolayout) + make.right.equalTo(leftContainer).offset(-Constants.UI.GroupAutolayout) + make.left.equalTo(leftContainer) + } + + functionGroupVC.view.snp.makeConstraints { make in + make.top.equalTo(buttonGroup.snp.bottom).offset(Constants.UI.GroupAutolayout) + make.right.equalTo(leftContainer).offset(-Constants.UI.GroupAutolayout) + make.left.bottom.equalTo(leftContainer) + } + } + + func viewInit() { + self.boxViewSizeInit() + + splitView.addArrangedSubview(leftContainer) + splitView.addArrangedSubview(contentGroup) + self.view.addSubview(splitView) + + splitView.snp.makeConstraints { make in + make.top.equalTo(self.view).offset(Constants.UI.GroupAutolayout) + make.left.equalTo(self.view).offset(Constants.UI.GroupAutolayout) + make.right.equalTo(self.view).offset(-Constants.UI.GroupAutolayout) + make.bottom.equalTo(self.view).offset(-Constants.UI.GroupAutolayout) + } + } + + func boxViewSizeInit() { + self.view.frame.size.width = BoxSizeManager.shared.size.width + self.view.frame.size.height = BoxSizeManager.shared.size.height + } +} + +extension BoxBaseContainerViewController: NSSplitViewDelegate { + func splitView(_ splitView: NSSplitView, constrainMinCoordinate proposedMinimumPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat { + + if dividerIndex == 0 { + return 132 + } + return proposedMinimumPosition + } + + func splitView(_ splitView: NSSplitView, constrainMaxCoordinate proposedMaximumPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat { + if dividerIndex == 0 { + return 200 + } + return proposedMaximumPosition + } + + func splitView(_ splitView: NSSplitView, resizeSubviewsWithOldSize oldSize: NSSize) { + let dividerThickness = splitView.dividerThickness + let newWidth = splitView.frame.width - dividerThickness + + let leftWidth = leftContainer.frame.width + let contentWidth = newWidth - leftWidth + + leftContainer.frame = NSRect(x: 0, y: 0, width: leftWidth, height: splitView.bounds.height) + contentGroup.frame = NSRect(x: leftWidth + dividerThickness, y: 0, width: contentWidth, height: splitView.bounds.height) + } +} diff --git a/Box42/Box/BoxController.swift b/Box42/Box/BoxController.swift deleted file mode 100644 index 0c5b533..0000000 --- a/Box42/Box/BoxController.swift +++ /dev/null @@ -1,268 +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) { - 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) { - ad?.boxStatus.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 deleted file mode 100644 index b188c95..0000000 --- a/Box42/Box/BoxModel.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// BoxViewModel.swift -// Box42 -// -// Created by Chan on 2023/03/16. -// - -import WebKit - -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 -} diff --git a/Box42/Box/View/BoxBaseSplitView.swift b/Box42/Box/View/BoxBaseSplitView.swift new file mode 100644 index 0000000..3def6e3 --- /dev/null +++ b/Box42/Box/View/BoxBaseSplitView.swift @@ -0,0 +1,20 @@ +// +// BoxBaseSplitView.swift +// Box42 +// +// Created by Chanhee Kim on 8/19/23. +// + +import AppKit + +class BoxBaseSplitView: NSSplitView { + init() { + super.init(frame: .zero) + self.isVertical = true + self.dividerStyle = .thick + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/Box42/Box/View/BoxButtonViewGroup.swift b/Box42/Box/View/BoxButtonViewGroup.swift new file mode 100644 index 0000000..44a2299 --- /dev/null +++ b/Box42/Box/View/BoxButtonViewGroup.swift @@ -0,0 +1,92 @@ +// +// BoxButtonView.swift +// Box42 +// +// Created by Chanhee Kim on 8/11/23. +// + +import Cocoa +import SnapKit + +class BoxButtonViewGroup: NSView { + var boxVM: WebViewModel! = WebViewModel() + var pinSwitch : NSSwitch = NSSwitch() + var clickAction: ((NSButton) -> Void)? + var lastAddedButton: NSView? + var loginInfo: NSView? + + init(clickAction: @escaping (NSButton) -> Void) { + self.clickAction = clickAction + super.init(frame: BoxSizeManager.shared.buttonGroupSizeNSRect) + setupButtons() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func draw(_ dirtyRect: NSRect) { + // 뷰의 μ»€μŠ€ν…€ λ Œλ”λ§μ— μ‚¬μš©λ¨. + } + + private func setupButtons() { + for subview in self.subviews { + subview.removeFromSuperview() + } + + for (name, _) in boxVM.webViewURL.URLstring { + self.createButton(name) + } + } + @objc private func clickBtn(sender: NSButton) { + clickAction?(sender) + } + + private func createButton(_ title: String) { + let button: NSButton + + if title == "home" { + button = NSButton(title: "home", image: NSImage(imageLiteralResourceName: "42box_logo"), target: self, action: #selector(clickBtn(sender:))) + button.imagePosition = .imageOnly + button.isBordered = false + } else { + button = HoverButton() + button.title = title + + button.wantsLayer = true + button.contentTintColor = NSColor.black + button.layer?.borderColor = NSColor.black.cgColor + button.layer?.borderWidth = 1.0 + button.layer?.cornerRadius = 5.0 + button.layer?.opacity = 0.7 + } + super.addSubview(button) + + button.target = self + button.action = #selector(clickBtn(sender:)) + + let fontSize: CGFloat = 16.0 + button.font = NSFont.systemFont(ofSize: fontSize) + button.setButtonType(.momentaryLight) + button.translatesAutoresizingMaskIntoConstraints = false + + button.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.leading.equalToSuperview().offset(10) + make.trailing.equalToSuperview().offset(-10) + + if title == "home" { + make.height.equalTo(50) + } else { + make.height.equalTo(50) + } + + if let lastButton = lastAddedButton { + make.top.equalTo(lastButton.snp.bottom).offset(10) + } else { + make.top.equalToSuperview().offset(10) + } + } + lastAddedButton = button + } +} diff --git a/Box42/Box/View/BoxContentsViewGroup.swift b/Box42/Box/View/BoxContentsViewGroup.swift new file mode 100644 index 0000000..215d0ce --- /dev/null +++ b/Box42/Box/View/BoxContentsViewGroup.swift @@ -0,0 +1,75 @@ +// +// BoxContentsViewGroup.swift +// Box42 +// +// Created by Chanhee Kim on 8/13/23. +// + +import WebKit +import SnapKit + +class BoxContentsViewGroup: NSView { + var webVC: WebViewController? + var preferencesVC = PreferencesViewController() + + init() { + webVC = WebViewController(nibName: nil, bundle: nil) + + super.init(frame: NSRect(x: 0, y: 0, width: BoxSizeManager.shared.size.width - BoxSizeManager.shared.buttonGroupSize.width, height: BoxSizeManager.shared.buttonGroupSize.height)) + + self.frame.size.width = BoxSizeManager.shared.size.width - BoxSizeManager.shared.buttonGroupSize.width + self.frame.size.height = BoxSizeManager.shared.size.height + + self.wantsLayer = true + self.addSubview(webVC!.view) + + webVC?.view.translatesAutoresizingMaskIntoConstraints = false + webVC?.view.snp.makeConstraints { make in + make.edges.equalTo(self) + } + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func draw(_ dirtyRect: NSRect) { + super.draw(dirtyRect) + // Drawing code here. + } + + func removeAllSubviews() { + for subview in self.subviews { + subview.removeFromSuperview() + } + } + + func showPreferences() { + self.addSubview(preferencesVC.view) + preferencesVC.viewDidAppear() + } + + func showWebviews(_ sender: NSButton) { + guard let currentWebview = WebViewManager.shared.list[sender.title] else { + print("No WebView found for title: \(sender.title)") + return + } + + WebViewManager.shared.hostingname = sender.title + WebViewManager.shared.hostingWebView = currentWebview + + self.addSubview(currentWebview) + + currentWebview.snp.makeConstraints { make in + make.edges.equalTo(self) + } + + if currentWebview.url == nil { + print("WebView for \(sender.title) has no content loaded.") + } + + currentWebview.viewDidMoveToSuperview() + currentWebview.becomeFirstResponder() + } + +} diff --git a/Box42/Extensions/Double.swift b/Box42/Extensions/Double.swift new file mode 100644 index 0000000..c539a74 --- /dev/null +++ b/Box42/Extensions/Double.swift @@ -0,0 +1,12 @@ +// +// Double.swift +// Box42 +// +// Created by Chanhee Kim on 8/16/23. +// + +extension Double { + var roundedToTwoDecimalPlaces: Double { + return (self * 100).rounded() / 100 + } +} diff --git a/Box42/Extensions/NSImage.swift b/Box42/Extensions/NSImage.swift new file mode 100644 index 0000000..602020e --- /dev/null +++ b/Box42/Extensions/NSImage.swift @@ -0,0 +1,30 @@ +// +// NSImage.swift +// Box42 +// +// Created by Chanhee Kim on 8/19/23. +// + +import Cocoa + +extension NSImage { + func resized(to newSize: CGSize) -> NSImage? { + if let bitmapRepresentation = NSBitmapImageRep( + bitmapDataPlanes: nil, pixelsWide: Int(newSize.width), pixelsHigh: Int(newSize.height), + bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, + colorSpaceName: NSColorSpaceName.deviceRGB, bytesPerRow: 0, bitsPerPixel: 0) { + + bitmapRepresentation.size = newSize + NSGraphicsContext.saveGraphicsState() + NSGraphicsContext.current = NSGraphicsContext(bitmapImageRep: bitmapRepresentation) + self.draw(in: NSRect(x: 0, y: 0, width: newSize.width, height: newSize.height), from: .zero, operation: .copy, fraction: 1.0) + NSGraphicsContext.restoreGraphicsState() + + let resizedImage = NSImage(size: newSize) + resizedImage.addRepresentation(bitmapRepresentation) + return resizedImage + } + + return nil + } +} 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/String.swift similarity index 94% rename from Box42/Resources/StringExtension.swift rename to Box42/Extensions/String.swift index fd1f378..f04a1ed 100644 --- a/Box42/Resources/StringExtension.swift +++ b/Box42/Extensions/String.swift @@ -1,5 +1,5 @@ // -// StringExtension.swift +// String.swift // Box42 // // Created by Chanhee Kim on 7/8/23. diff --git a/Box42/FunctionButton/BoxFunctionViewController.swift b/Box42/FunctionButton/BoxFunctionViewController.swift new file mode 100644 index 0000000..a2a482e --- /dev/null +++ b/Box42/FunctionButton/BoxFunctionViewController.swift @@ -0,0 +1,42 @@ +// +// FunctionButtonViewController.swift +// Box42 +// +// Created by Chanhee Kim on 8/20/23. +// + +import Cocoa + +class BoxFunctionViewController: NSViewController { + override func loadView() { + let functionViewGroup = BoxFunctionViewGroup() + + functionViewGroup.preferenceAction = preference + functionViewGroup.pinAction = pin + functionViewGroup.quitAction = quit + functionViewGroup.boxAction = box + + self.view = functionViewGroup + } + + override func viewDidLoad() { + super.viewDidLoad() + } + + func preference() { + print("preference") + } + + func pin() { + print("pin") + } + + func quit() { + print("quit") + NSApplication.shared.terminate(self) + } + + func box() { + print("box") + } +} diff --git a/Box42/FunctionButton/View/BoxFunctionButtonView.swift b/Box42/FunctionButton/View/BoxFunctionButtonView.swift new file mode 100644 index 0000000..01eb568 --- /dev/null +++ b/Box42/FunctionButton/View/BoxFunctionButtonView.swift @@ -0,0 +1,31 @@ +// +// BoxFunctionButtonView.swift +// Box42 +// +// Created by Chanhee Kim on 8/20/23. +// + +import AppKit + +class BoxFunctionButtonView: NSButton { + + private var callback: (() -> Void)? + + init(image: NSImage, completion: @escaping () -> Void) { + super.init(frame: .zero) + + self.image = image + self.bezelStyle = .texturedRounded + self.target = self + self.action = #selector(BoxFunction) + self.callback = completion + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc func BoxFunction() { + callback?() + } +} diff --git a/Box42/FunctionButton/View/BoxFunctionViewGroup.swift b/Box42/FunctionButton/View/BoxFunctionViewGroup.swift new file mode 100644 index 0000000..9e5fa88 --- /dev/null +++ b/Box42/FunctionButton/View/BoxFunctionViewGroup.swift @@ -0,0 +1,75 @@ +// +// BoxFunctionViewGroup.swift +// Box42 +// +// Created by Chanhee Kim on 8/20/23. +// + +import AppKit +import SnapKit + +class BoxFunctionViewGroup: NSView { + lazy var preferenceButton: PreferenceButtonView! = PreferenceButtonView(image: NSImage(imageLiteralResourceName: "plus"), completion: { self.preferenceAction?() }) + lazy var pinButton: PinButtonView! = PinButtonView(image: NSImage(imageLiteralResourceName: "pin"), completion: { self.pinAction?() }) + lazy var quitButton: QuitButtonView! = QuitButtonView(image: NSImage(imageLiteralResourceName: "figure.snowboarding"), completion: { self.quitAction?() }) + lazy var boxButton: BoxFunctionButtonView! = BoxFunctionButtonView(image: NSImage(imageLiteralResourceName: "shippingbox"), completion: { self.boxAction?() }) + lazy var divider: NSBox! = TopDivider(completion: { self.dividerAction?() }) + + var preferenceAction: (() -> Void)? + var pinAction: (() -> Void)? + var quitAction: (() -> Void)? + var boxAction: (() -> Void)? + var dividerAction: (() -> Void)? + + override init(frame: NSRect) { + super.init(frame: frame) + setupViews() + setupConstraints() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + setupViews() + setupConstraints() + } + + private func setupViews() { + self.addSubview(preferenceButton) + self.addSubview(pinButton) + self.addSubview(quitButton) + self.addSubview(boxButton) + self.addSubview(divider) + } + + private func setupConstraints() { + divider.snp.makeConstraints { make in + make.top.equalToSuperview() + make.left.right.equalToSuperview() + } + + preferenceButton.snp.makeConstraints { make in + make.top.equalTo(divider).offset(10) + make.bottom.equalToSuperview() + make.left.equalToSuperview() + make.width.equalTo(pinButton) + } + + pinButton.snp.makeConstraints { make in + make.top.bottom.equalTo(preferenceButton) + make.left.equalTo(preferenceButton.snp.right).offset(10) + make.width.equalTo(quitButton) + } + + quitButton.snp.makeConstraints { make in + make.top.bottom.equalTo(preferenceButton) + make.left.equalTo(pinButton.snp.right).offset(10) + make.width.equalTo(boxButton) + } + + boxButton.snp.makeConstraints { make in + make.top.bottom.equalTo(preferenceButton) + make.left.equalTo(quitButton.snp.right).offset(10) + make.right.equalToSuperview() + } + } +} diff --git a/Box42/FunctionButton/View/PinButtonView.swift b/Box42/FunctionButton/View/PinButtonView.swift new file mode 100644 index 0000000..a91036b --- /dev/null +++ b/Box42/FunctionButton/View/PinButtonView.swift @@ -0,0 +1,31 @@ +// +// PinButtonView.swift +// Box42 +// +// Created by Chanhee Kim on 8/20/23. +// + +import AppKit + +class PinButtonView: NSButton { + + private var callback: (() -> Void)? + + init(image: NSImage, completion: @escaping () -> Void) { + super.init(frame: .zero) + + self.image = image + self.bezelStyle = .texturedRounded + self.target = self + self.action = #selector(pin) + self.callback = completion + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc func pin() { + callback?() + } +} diff --git a/Box42/FunctionButton/View/PreferenceButtonView.swift b/Box42/FunctionButton/View/PreferenceButtonView.swift new file mode 100644 index 0000000..ffc8102 --- /dev/null +++ b/Box42/FunctionButton/View/PreferenceButtonView.swift @@ -0,0 +1,30 @@ +// +// PreferenceButtonView.swift +// Box42 +// +// Created by Chanhee Kim on 8/20/23. +// + +import AppKit + +class PreferenceButtonView: NSButton { + + private var callback: (() -> Void)? + + init(image: NSImage, completion: @escaping () -> Void) { + super.init(frame: .zero) + self.image = image + self.bezelStyle = .texturedRounded + self.target = self + self.action = #selector(preference) + self.callback = completion + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc func preference() { + callback?() + } +} diff --git a/Box42/FunctionButton/View/QuitButtonView.swift b/Box42/FunctionButton/View/QuitButtonView.swift new file mode 100644 index 0000000..aaf9259 --- /dev/null +++ b/Box42/FunctionButton/View/QuitButtonView.swift @@ -0,0 +1,31 @@ +// +// QuitButtonView.swift +// Box42 +// +// Created by Chanhee Kim on 8/20/23. +// + +import AppKit + +class QuitButtonView: NSButton { + + private var callback: (() -> Void)? + + init(image: NSImage, completion: @escaping () -> Void) { + super.init(frame: .zero) + + self.image = image + self.bezelStyle = .texturedRounded + self.target = self + self.action = #selector(QuitButton) + self.callback = completion + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc func QuitButton() { + callback?() + } +} diff --git a/Box42/FunctionButton/View/TopDivider.swift b/Box42/FunctionButton/View/TopDivider.swift new file mode 100644 index 0000000..81a39de --- /dev/null +++ b/Box42/FunctionButton/View/TopDivider.swift @@ -0,0 +1,28 @@ +// +// TopDivider.swift +// Box42 +// +// Created by Chanhee Kim on 8/21/23. +// + +import AppKit + +class TopDivider: NSBox { + + private var callback: (() -> Void)? + + init(completion: @escaping () -> Void) { + super.init(frame: .zero) + self.title = "" + self.boxType = .separator + self.callback = completion + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc func preference() { + callback?() + } +} diff --git a/Box42/Login/LoginViewController.swift b/Box42/Login/LoginViewController.swift new file mode 100644 index 0000000..6020ea4 --- /dev/null +++ b/Box42/Login/LoginViewController.swift @@ -0,0 +1,44 @@ +// +// LoginViewController.swift +// Box42 +// +// Created by Chanhee Kim on 8/13/23. +// + +import Cocoa + +class LoginViewController: NSViewController { + var loginContainerView: NSView = { + let loginView = NSView() + loginView.translatesAutoresizingMaskIntoConstraints = false + loginView.wantsLayer = true + loginView.layer?.backgroundColor = NSColor.gray.cgColor + return loginView + }() + + override init(nibName nibNameOrNil: NSNib.Name?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nil, bundle: nil) // μ—¬κΈ°μ—μ„œ nibName을 nil둜 전달 + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + self.view = NSView() // κΈ°λ³Έ λ·° μ„€μ • + } + + override func viewDidLoad() { + super.viewDidLoad() + // Do view setup here. + view.addSubview(loginContainerView) + + // loginContainerViewκ°€ λ·° 컨트둀러의 전체 λ·° μ˜μ—­μ„ μ°¨μ§€ν•˜λ„λ‘ μ œμ•½ μΆ”κ°€ + NSLayoutConstraint.activate([ + loginContainerView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + loginContainerView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + loginContainerView.topAnchor.constraint(equalTo: view.topAnchor), + loginContainerView.bottomAnchor.constraint(equalTo: view.bottomAnchor) + ]) + } +} diff --git a/Box42/Main/BoxViewController.swift b/Box42/Main/BoxViewController.swift new file mode 100644 index 0000000..a9692c8 --- /dev/null +++ b/Box42/Main/BoxViewController.swift @@ -0,0 +1,63 @@ +// +// BoxViewController.swift +// Box42 +// +// Created by Chan on 2023/03/16. +// + +import AppKit +import WebKit + +class BoxViewController: NSViewController { + var boxView: BoxBaseContainerViewController! = BoxBaseContainerViewController() + var gradientLayer: CAGradientLayer! + let preferencesVC = PreferencesViewController() + weak var menubarVCDelegate: MenubarViewControllerDelegate? + + + override func loadView() { + self.view = boxView.view + } + + override func viewDidLoad() { + super.viewDidLoad() + + menubarVCDelegate = (NSApplication.shared.delegate as? AppDelegate)?.menubarController + + self.view.wantsLayer = true + setupGradientLayer() + + NotificationCenter.default.addObserver(self, selector: #selector(boundsDidChange), name: NSWindow.didResizeNotification, object: self.view.window) + } + + func setupGradientLayer() { + gradientLayer = CAGradientLayer() + gradientLayer.frame = self.view.bounds + let startingColor = NSColor(red: 1.0, green: 0.804, blue: 0.0, alpha: 0.9).cgColor + let endingColor = NSColor(red: 1.0, green: 0.447, blue: 0.0, alpha: 0.7).cgColor + gradientLayer.colors = [startingColor, endingColor] + + self.view.layer?.addSublayer(gradientLayer) + } + + @objc func boundsDidChange(notification: NSNotification) { + if let window = notification.object as? NSWindow { + gradientLayer.frame = window.contentView!.bounds + } + } + + @objc + func doubleClickBtn(sender: NSButton) { + WebViewManager.shared.list[sender.title]!.reload() + } + + @objc + func pin(_ sender: NSSwitch) { + StateManager.shared.setToggleIsPin() + print(sender.state) + } + + func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { + print(message.name) + } +} diff --git a/Box42/Main/keyDown+BoxViewController.swift b/Box42/Main/keyDown+BoxViewController.swift new file mode 100644 index 0000000..63b89e2 --- /dev/null +++ b/Box42/Main/keyDown+BoxViewController.swift @@ -0,0 +1,33 @@ +// +// keyDown+BoxViewController.swift +// Box42 +// +// Created by Chanhee Kim on 8/21/23. +// + +import AppKit + +extension BoxViewController { + override func keyDown(with event: NSEvent) { + print(event.keyCode) + if event.keyCode == 1 { + StorageConfig.shared.setThreshold(.percentage50) + StorageConfig.shared.setPeriod(.period10s) + } + if event.keyCode == 2 { + // SdtorageConfig.shared.setThreshold(.percentage30) + DispatchQueue.main.async { + StorageConfig.shared.setThreshold(.percentage30) + } + StorageConfig.shared.setPeriod(.period1s) + } + + + if event.keyCode == 53 { // Escape ν‚€μ˜ keyCodeλŠ” 53μž…λ‹ˆλ‹€. + print("escape") + menubarVCDelegate?.toggleWindow(sender: nil) + } else { + super.keyDown(with: event) // 기타 ν‚€λ₯Ό μ²˜λ¦¬ν•˜κΈ° μœ„ν•΄ μƒμœ„ ν΄λž˜μŠ€μ—κ²Œ 전달 + } + } +} diff --git a/Box42/Menubar/MenubarController.swift b/Box42/Menubar/MenubarController.swift deleted file mode 100644 index 8ac85ac..0000000 --- a/Box42/Menubar/MenubarController.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// MenubarController.swift -// Box42 -// -// Created by Chan on 2023/03/16. -// - -import Foundation - -import AppKit - -class MenuBarController: NSWorkspace { - let cpu = CPU() - let statusBar = StatusBar() - let menuBarView = MenuBarView() - - func buttonInit() { - buttonImageChange("box") - menuBarView.buttonAppear(statusBar) - } - - func startRunning() { - statusBar.isRunning = cpu.processCPU(statusBar) - animate() - } - - func stopRunning() { - statusBar.isRunning = cpu.StopCPU() - } - - 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 buttonImageChange(_ img: String) { - menuBarView.imageChange("box", statusBar) - } -} diff --git a/Box42/Menubar/MenubarModel.swift b/Box42/Menubar/MenubarModel.swift index 0a223f5..24a9a73 100644 --- a/Box42/Menubar/MenubarModel.swift +++ b/Box42/Menubar/MenubarModel.swift @@ -7,11 +7,22 @@ import AppKit -public class StatusBar { - var statusItem = NSStatusItem() - var frames = [NSImage]() - var cnt: Int = 0 - var isRunning: Bool = false - var interval: Double = 1.0 - var alertCount: Int = 0 +class StatusBar { + static let shared = StatusBar() + + var statusItem: NSStatusItem + var frames: [NSImage] + var cnt: Int + var isRunning: Bool + var interval: Double + var alertCount: Int + + init() { + self.statusItem = NSStatusItem() + self.frames = [NSImage]() + self.cnt = 0 + self.isRunning = false + self.interval = 1.0 + self.alertCount = 0 + } } diff --git a/Box42/Menubar/MenubarView.swift b/Box42/Menubar/MenubarView.swift deleted file mode 100644 index 8f69493..0000000 --- a/Box42/Menubar/MenubarView.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// MenubarView.swift -// Box42 -// -// Created by Chan on 2023/03/16. -// - -import Foundation -import AppKit - -class MenuBarView { - - func buttonAppear(_ statusBar: StatusBar) { - let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) - - statusBar.statusItem = statusItem - } - - func imageChange(_ imgName: String, _ statusBar: StatusBar) { - statusBar.frames.removeAll() - switch imgName { - 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: "lee_\(i)"))} - case "gam": 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 "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)"))} - } - } -} diff --git a/Box42/Menubar/MenubarViewController.swift b/Box42/Menubar/MenubarViewController.swift new file mode 100644 index 0000000..2cb1a3f --- /dev/null +++ b/Box42/Menubar/MenubarViewController.swift @@ -0,0 +1,133 @@ +// +// MenubarController.swift +// Box42 +// +// Created by Chan on 2023/03/16. +// + +import Foundation +import AppKit + +class MenubarViewController: NSWorkspace { + var popover = NSPopover() + var statusBarVM = StatusBarViewModel() + lazy var eventMonitor: EventMonitor = self.setupEventMonitor() + var boxWindowController: BoxWindowController? + + func menubarViewControllerInit() { + self.buttonInit() + } + + func menubarViewControllerStart() { + self.menubarStartRunning() + self.buttonActionInit() + self.popoverCoentViewInit() + self.startEventMonitoring() + } + + func startEventMonitoring() { + eventMonitor.start() + } + + func stopEventMonitoring() { + eventMonitor.stop() + } + + func menubarStartRunning() { + statusBarVM.startRunning() + } + + func menubarStopRunning() { + statusBarVM.stopRunning() + } + + func buttonInit() { + buttonImageChange("Cat") + statusBarVM.statusButtonAppear() + } + + func buttonImageChange(_ img: String) { + statusBarVM.changeStatusBarIcon(img) + } + + func buttonActionInit() { + statusBarVM.statusBar.statusItem.button?.action = #selector(togglePopover(_:)) + statusBarVM.statusBar.statusItem.button?.target = self + } + + func popoverCoentViewInit() { + let boxViewController = BoxViewController(nibName: nil, bundle: nil) + popover.contentViewController = boxViewController + } + + func setupEventMonitor() -> EventMonitor { + return EventMonitor(mask: [.leftMouseDown, .rightMouseDown, .otherMouseDown]) { [weak self] event in + if let strongSelf = self, strongSelf.popover.isShown { + if StateManager.shared.getIsPin() == false && event?.buttonNumber != 2 { + strongSelf.closePopover(sender: event) + } + } else if let strongSelf = self, !strongSelf.popover.isShown { + if event?.buttonNumber == 2 { + strongSelf.popoverHandler(sender: event) + } + } + } + } + + @objc func togglePopover(_ sender: Any?) { + if popover.isShown { + closePopover(sender: sender) + } else { + popoverHandler(sender: sender) + } + } + + func popoverHandler(sender: Any?) { + if let event = sender as? NSEvent { + if event.type == .otherMouseDown { + self.toggleWindow(sender: sender) + } + } else if let button = statusBarVM.statusBar.statusItem.button { + popover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY) + } + } + + func closePopover(sender: Any?) { + popover.performClose(sender) + } +} + +extension MenubarViewController: MenubarViewControllerDelegate { + func toggleWindow(sender: Any?) { + StateManager.shared.setToggleIsShowWindow() + if StateManager.shared.getIsShowWindow() == false { + if let window = boxWindowController?.window { + if window.isVisible { + window.orderOut(sender) + print("hide") + } + } + } else { + if boxWindowController == nil { + boxWindowController = BoxWindowController(window: nil) + } + if let button = statusBarVM.statusBar.statusItem.button, + let window = boxWindowController?.window { + if StateManager.shared.getIsShowFirstWindow() == false { + let buttonFrame = button.window?.convertToScreen(button.frame) ?? NSZeroRect + let desiredPosition = NSPoint(x: buttonFrame.origin.x - (BoxSizeManager.shared.size.width / 2) - 10, y: buttonFrame.origin.y - window.frame.height) + + window.setFrameOrigin(desiredPosition) + StateManager.shared.setToggleIsShowFirstWindow() + } + window.level = .floating + } + boxWindowController?.showWindow(sender) + } + } + +} + +protocol MenubarViewControllerDelegate: AnyObject { + func toggleWindow(sender: Any?) +} diff --git a/Box42/Menubar/MenubarViewModel.swift b/Box42/Menubar/MenubarViewModel.swift new file mode 100644 index 0000000..7a7fb9e --- /dev/null +++ b/Box42/Menubar/MenubarViewModel.swift @@ -0,0 +1,75 @@ +// +// MenubarViewModel.swift +// Box42 +// +// Created by Chanhee Kim on 8/8/23. +// + +import AppKit + +class StatusBarViewModel { + let cpu: CPU + let statusBar: StatusBar + private var currentAnimationWorkItem: DispatchWorkItem? + + init () { + self.statusBar = StatusBar.shared + self.cpu = CPU() + } + + func statusButtonAppear() { + statusBar.statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) + } + + 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 "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 "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)"))} + } + } + + func startRunning() { + statusBar.isRunning = cpu.processCPU(statusBar) + 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/Accessibility.swift b/Box42/Preferences/Accessibility.swift new file mode 100644 index 0000000..7121713 --- /dev/null +++ b/Box42/Preferences/Accessibility.swift @@ -0,0 +1,23 @@ +// +// Accessibility.swift +// Box42 +// +// Created by Chanhee Kim on 8/8/23. +// + +import Cocoa + +func alertAccessibility() { + let alert = NSAlert() + alert.messageText = "Permission Required" + alert.informativeText = "Please allow accessibility permissions in System Preferences to enable this feature." + alert.addButton(withTitle: "Open System Preferences") + alert.addButton(withTitle: "Cancel") + let response = alert.runModal() + + if response == .alertFirstButtonReturn { + if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility") { + NSWorkspace.shared.open(url) + } + } +} diff --git a/Box42/Preferences/Hotkey.swift b/Box42/Preferences/Hotkey.swift new file mode 100644 index 0000000..64a71f1 --- /dev/null +++ b/Box42/Preferences/Hotkey.swift @@ -0,0 +1,38 @@ +// +// Hotkey.swift +// Box42 +// +// Created by Chanhee Kim on 7/8/23. +// + +import Foundation + +import Cocoa + +func hotkey() { + let eventMask: CGEventMask = (1 << CGEventType.keyDown.rawValue) | (1 << CGEventType.keyUp.rawValue) + guard let eventTap = CGEvent.tapCreate(tap: .cghidEventTap, place: .headInsertEventTap, options: .defaultTap, eventsOfInterest: eventMask, callback: { (proxy, type, event, refcon) -> Unmanaged? in + if [.keyDown, .keyUp].contains(type) { + let flags = event.flags + let isCommandPressed = flags.contains(.maskCommand) + let isControlPressed = flags.contains(.maskControl) + let keyCode = event.getIntegerValueField(.keyboardEventKeycode) + + // keyCode 11 corresponds to the 'b' key + if isCommandPressed, isControlPressed, keyCode == 11 { + print("Command + Control + B pressed!") + } + } + + return Unmanaged.passRetained(event) + }, userInfo: nil) else { + print("Failed to create event tap") + return + } + + let runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0) + CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, .commonModes) + CGEvent.tapEnable(tap: eventTap, enable: true) + + CFRunLoopRun() +} 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/Preferences/PreferencesView.swift b/Box42/Preferences/PreferencesView.swift new file mode 100644 index 0000000..d2abcff --- /dev/null +++ b/Box42/Preferences/PreferencesView.swift @@ -0,0 +1,9 @@ +// +// PreferencesView.swift +// Box42 +// +// Created by Chanhee Kim on 7/8/23. +// + +import Foundation + diff --git a/Box42/Preferences/PreferencesViewController.swift b/Box42/Preferences/PreferencesViewController.swift new file mode 100644 index 0000000..6604203 --- /dev/null +++ b/Box42/Preferences/PreferencesViewController.swift @@ -0,0 +1,152 @@ +// +// 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 icons = iconModel().icon + icons.forEach { (icon) in + stackBox.append(NSButton(title: "Change \(icon) Icon", target: self, action: #selector(changeIconButtonPressed))) + } + + 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/Resources/AppDelegate.swift b/Box42/Resources/AppDelegate.swift index 4ab862a..26df5dd 100644 --- a/Box42/Resources/AppDelegate.swift +++ b/Box42/Resources/AppDelegate.swift @@ -9,165 +9,124 @@ 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 - } - + var menubarController = MenubarViewController() + lazy var storage = Storage() + + func applicationWillFinishLaunching(_ notification: Notification) { + menubarController.menubarViewControllerInit() + } + + func applicationDidFinishLaunching(_ aNotification: Notification) { + menubarController.menubarViewControllerStart() +// alertAccessibility() +// hotkey() + storage.storageTimerEvent() + } + + 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 + } + } diff --git a/Box42/Resources/Assets.xcassets/Icons/Contents.json b/Box42/Resources/Assets.xcassets/Icons/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Box42/Resources/Assets.xcassets/Icons/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Box42/Resources/Assets.xcassets/Icons/arrow.clockwise.imageset/Contents.json b/Box42/Resources/Assets.xcassets/Icons/arrow.clockwise.imageset/Contents.json new file mode 100644 index 0000000..e6da493 --- /dev/null +++ b/Box42/Resources/Assets.xcassets/Icons/arrow.clockwise.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "arrow.clockwise@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Box42/Resources/Assets.xcassets/Icons/arrow.clockwise.imageset/arrow.clockwise@2x.png b/Box42/Resources/Assets.xcassets/Icons/arrow.clockwise.imageset/arrow.clockwise@2x.png new file mode 100644 index 0000000..be10d0b Binary files /dev/null and b/Box42/Resources/Assets.xcassets/Icons/arrow.clockwise.imageset/arrow.clockwise@2x.png differ diff --git a/Box42/Resources/Assets.xcassets/Icons/arrow.left.imageset/Contents.json b/Box42/Resources/Assets.xcassets/Icons/arrow.left.imageset/Contents.json new file mode 100644 index 0000000..4b93ed1 --- /dev/null +++ b/Box42/Resources/Assets.xcassets/Icons/arrow.left.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "arrow.left@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Box42/Resources/Assets.xcassets/Icons/arrow.left.imageset/arrow.left@2x.png b/Box42/Resources/Assets.xcassets/Icons/arrow.left.imageset/arrow.left@2x.png new file mode 100644 index 0000000..dd616af Binary files /dev/null and b/Box42/Resources/Assets.xcassets/Icons/arrow.left.imageset/arrow.left@2x.png differ diff --git a/Box42/Resources/Assets.xcassets/Icons/arrow.right.imageset/Contents.json b/Box42/Resources/Assets.xcassets/Icons/arrow.right.imageset/Contents.json new file mode 100644 index 0000000..483e2db --- /dev/null +++ b/Box42/Resources/Assets.xcassets/Icons/arrow.right.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "arrow.right@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Box42/Resources/Assets.xcassets/Icons/arrow.right.imageset/arrow.right@2x.png b/Box42/Resources/Assets.xcassets/Icons/arrow.right.imageset/arrow.right@2x.png new file mode 100644 index 0000000..f3362b8 Binary files /dev/null and b/Box42/Resources/Assets.xcassets/Icons/arrow.right.imageset/arrow.right@2x.png differ diff --git a/Box42/Resources/Assets.xcassets/Icons/doc.on.doc.imageset/Contents.json b/Box42/Resources/Assets.xcassets/Icons/doc.on.doc.imageset/Contents.json new file mode 100644 index 0000000..97e4fcf --- /dev/null +++ b/Box42/Resources/Assets.xcassets/Icons/doc.on.doc.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "doc.on.doc@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Box42/Resources/Assets.xcassets/Icons/doc.on.doc.imageset/doc.on.doc@2x.png b/Box42/Resources/Assets.xcassets/Icons/doc.on.doc.imageset/doc.on.doc@2x.png new file mode 100644 index 0000000..5a880b3 Binary files /dev/null and b/Box42/Resources/Assets.xcassets/Icons/doc.on.doc.imageset/doc.on.doc@2x.png differ diff --git a/Box42/Resources/Assets.xcassets/Icons/ellipsis.imageset/Contents.json b/Box42/Resources/Assets.xcassets/Icons/ellipsis.imageset/Contents.json new file mode 100644 index 0000000..849e448 --- /dev/null +++ b/Box42/Resources/Assets.xcassets/Icons/ellipsis.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "ellipsis@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Box42/Resources/Assets.xcassets/Icons/ellipsis.imageset/ellipsis@2x.png b/Box42/Resources/Assets.xcassets/Icons/ellipsis.imageset/ellipsis@2x.png new file mode 100644 index 0000000..e027e56 Binary files /dev/null and b/Box42/Resources/Assets.xcassets/Icons/ellipsis.imageset/ellipsis@2x.png differ diff --git a/Box42/Resources/Assets.xcassets/Icons/figure.skating.imageset/Contents.json b/Box42/Resources/Assets.xcassets/Icons/figure.skating.imageset/Contents.json new file mode 100644 index 0000000..99f8ebe --- /dev/null +++ b/Box42/Resources/Assets.xcassets/Icons/figure.skating.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "figure.skating@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Box42/Resources/Assets.xcassets/Icons/figure.skating.imageset/figure.skating@2x.png b/Box42/Resources/Assets.xcassets/Icons/figure.skating.imageset/figure.skating@2x.png new file mode 100644 index 0000000..1ddfa0f Binary files /dev/null and b/Box42/Resources/Assets.xcassets/Icons/figure.skating.imageset/figure.skating@2x.png differ diff --git a/Box42/Resources/Assets.xcassets/Icons/figure.snowboarding.imageset/Contents.json b/Box42/Resources/Assets.xcassets/Icons/figure.snowboarding.imageset/Contents.json new file mode 100644 index 0000000..f437f7e --- /dev/null +++ b/Box42/Resources/Assets.xcassets/Icons/figure.snowboarding.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "figure.snowboarding@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Box42/Resources/Assets.xcassets/Icons/figure.snowboarding.imageset/figure.snowboarding@2x.png b/Box42/Resources/Assets.xcassets/Icons/figure.snowboarding.imageset/figure.snowboarding@2x.png new file mode 100644 index 0000000..d797233 Binary files /dev/null and b/Box42/Resources/Assets.xcassets/Icons/figure.snowboarding.imageset/figure.snowboarding@2x.png differ diff --git a/Box42/Resources/Assets.xcassets/Icons/figure.surfing.imageset/Contents.json b/Box42/Resources/Assets.xcassets/Icons/figure.surfing.imageset/Contents.json new file mode 100644 index 0000000..faa8a6b --- /dev/null +++ b/Box42/Resources/Assets.xcassets/Icons/figure.surfing.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "figure.surfing@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Box42/Resources/Assets.xcassets/Icons/figure.surfing.imageset/figure.surfing@2x.png b/Box42/Resources/Assets.xcassets/Icons/figure.surfing.imageset/figure.surfing@2x.png new file mode 100644 index 0000000..3e6b0e9 Binary files /dev/null and b/Box42/Resources/Assets.xcassets/Icons/figure.surfing.imageset/figure.surfing@2x.png differ diff --git a/Box42/Resources/Assets.xcassets/Icons/minus.imageset/Contents.json b/Box42/Resources/Assets.xcassets/Icons/minus.imageset/Contents.json new file mode 100644 index 0000000..c437350 --- /dev/null +++ b/Box42/Resources/Assets.xcassets/Icons/minus.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "minus@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Box42/Resources/Assets.xcassets/Icons/minus.imageset/minus@2x.png b/Box42/Resources/Assets.xcassets/Icons/minus.imageset/minus@2x.png new file mode 100644 index 0000000..2a101f6 Binary files /dev/null and b/Box42/Resources/Assets.xcassets/Icons/minus.imageset/minus@2x.png differ diff --git a/Box42/Resources/Assets.xcassets/Icons/pin.fill.imageset/Contents.json b/Box42/Resources/Assets.xcassets/Icons/pin.fill.imageset/Contents.json new file mode 100644 index 0000000..ff506bf --- /dev/null +++ b/Box42/Resources/Assets.xcassets/Icons/pin.fill.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "pin.fill@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Box42/Resources/Assets.xcassets/Icons/pin.fill.imageset/pin.fill@2x.png b/Box42/Resources/Assets.xcassets/Icons/pin.fill.imageset/pin.fill@2x.png new file mode 100644 index 0000000..164fbcf Binary files /dev/null and b/Box42/Resources/Assets.xcassets/Icons/pin.fill.imageset/pin.fill@2x.png differ diff --git a/Box42/Resources/Assets.xcassets/Icons/pin.imageset/Contents.json b/Box42/Resources/Assets.xcassets/Icons/pin.imageset/Contents.json new file mode 100644 index 0000000..832a223 --- /dev/null +++ b/Box42/Resources/Assets.xcassets/Icons/pin.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "pin@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Box42/Resources/Assets.xcassets/Icons/pin.imageset/pin@2x.png b/Box42/Resources/Assets.xcassets/Icons/pin.imageset/pin@2x.png new file mode 100644 index 0000000..28b65a3 Binary files /dev/null and b/Box42/Resources/Assets.xcassets/Icons/pin.imageset/pin@2x.png differ diff --git a/Box42/Resources/Assets.xcassets/Icons/plus.imageset/Contents.json b/Box42/Resources/Assets.xcassets/Icons/plus.imageset/Contents.json new file mode 100644 index 0000000..ace344d --- /dev/null +++ b/Box42/Resources/Assets.xcassets/Icons/plus.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "plus@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Box42/Resources/Assets.xcassets/Icons/plus.imageset/plus@2x.png b/Box42/Resources/Assets.xcassets/Icons/plus.imageset/plus@2x.png new file mode 100644 index 0000000..3b9f621 Binary files /dev/null and b/Box42/Resources/Assets.xcassets/Icons/plus.imageset/plus@2x.png differ diff --git a/Box42/Resources/Assets.xcassets/Icons/shippingbox.imageset/Contents.json b/Box42/Resources/Assets.xcassets/Icons/shippingbox.imageset/Contents.json new file mode 100644 index 0000000..e79e1f2 --- /dev/null +++ b/Box42/Resources/Assets.xcassets/Icons/shippingbox.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "shippingbox@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Box42/Resources/Assets.xcassets/Icons/shippingbox.imageset/shippingbox@2x.png b/Box42/Resources/Assets.xcassets/Icons/shippingbox.imageset/shippingbox@2x.png new file mode 100644 index 0000000..9a0a5b3 Binary files /dev/null and b/Box42/Resources/Assets.xcassets/Icons/shippingbox.imageset/shippingbox@2x.png differ diff --git a/Box42/Resources/Assets.xcassets/Icons/sidebar.leading.imageset/Contents.json b/Box42/Resources/Assets.xcassets/Icons/sidebar.leading.imageset/Contents.json new file mode 100644 index 0000000..0ea6145 --- /dev/null +++ b/Box42/Resources/Assets.xcassets/Icons/sidebar.leading.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "sidebar.leading@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Box42/Resources/Assets.xcassets/Icons/sidebar.leading.imageset/sidebar.leading@2x.png b/Box42/Resources/Assets.xcassets/Icons/sidebar.leading.imageset/sidebar.leading@2x.png new file mode 100644 index 0000000..c5c2618 Binary files /dev/null and b/Box42/Resources/Assets.xcassets/Icons/sidebar.leading.imageset/sidebar.leading@2x.png differ 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 deleted file mode 100644 index 9f0087f..0000000 --- a/Box42/Resources/EventMonitor.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// EventMonitor.swift -// Box42 -// -// Created by Chan on 2023/03/16. -// - -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 - } - } -} diff --git a/Box42/Resources/ExportOptions.plist b/Box42/Resources/ExportOptions.plist new file mode 100644 index 0000000..31694a6 --- /dev/null +++ b/Box42/Resources/ExportOptions.plist @@ -0,0 +1,14 @@ + + + + + destination + export + method + development + signingStyle + automatic + teamID + QUAC995NAA + + diff --git a/Box42/Resources/Info.plist b/Box42/Resources/Info.plist index a6a98a7..1520f65 100644 --- a/Box42/Resources/Info.plist +++ b/Box42/Resources/Info.plist @@ -2,8 +2,11 @@ - LSUIElement - + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable @@ -24,9 +27,32 @@ 1 LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) + LSUIElement + NSMainStoryboardFile Main NSPrincipalClass NSApplication + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + + UISceneConfigurationName + + UISceneDelegateClassName + + UISceneStoryboardFile + + + + + diff --git a/Box42/Resources/Main.storyboard b/Box42/Resources/Main.storyboard index dbd2ec4..f542723 100644 --- a/Box42/Resources/Main.storyboard +++ b/Box42/Resources/Main.storyboard @@ -3,7 +3,6 @@ - @@ -79,24 +78,36 @@ - + + + + - + + + + + + + + + + - + - + @@ -107,7 +118,7 @@ - + @@ -133,19 +144,326 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -173,107 +491,5 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Box42/Resources/sh/brewInGoinfre.sh b/Box42/Resources/sh/brewInGoinfre.sh new file mode 100644 index 0000000..c97c200 --- /dev/null +++ b/Box42/Resources/sh/brewInGoinfre.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +#42Box: https://github.com/42Box +#Author: chanheki +#Date: 2023/08/10 + +# BOXY FOX +echo "" +echo "\033[38;5;208m Boxy Fox, Brew download in goinfre" +echo "" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’" +echo " β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo "β–‘β–‘β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo "β–‘β–‘β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo "β–‘β–‘β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo "β–‘β–‘β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo "β–‘β–‘β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆ" +echo "β–‘β–‘β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–’β–’β–ˆβ–ˆβ–“β–“β–“β–“" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–’β–’β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–‘β–‘β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–“β–“β–“β–“β–“β–“β–“β–“β–ˆβ–ˆβ–ˆβ–ˆβ–“β–“β–‘β–‘β–‘β–‘β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–“β–“β–“β–“β–“β–“β–“β–“β–’β–’β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–’β–’β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–’β–’β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–’β–’β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–’β–’ β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–‘β–‘β–“β–“β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–’β–’β–“β–“β–“β–“β–“β–“β–“β–“β–’β–’β–’β–’β–‘β–‘ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–‘β–‘β–‘β–‘β–“β–“β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–“β–“β–ˆβ–ˆβ–’β–’β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘ β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–‘β–‘ β–ˆβ–ˆ β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–ˆβ–ˆ" +echo " β–‘β–‘β–‘β–‘β–“β–“β–“β–“β–“β–“β–“β–“β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘ β–ˆβ–ˆ β–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–’ β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘ β–’β–’β–ˆβ–ˆ β–‘β–‘β–‘β–‘ β–’β–’β–’β–’ β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–‘β–‘ β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘ β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–ˆβ–ˆβ–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–ˆβ–ˆβ–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘" +echo "" + +brew --version || echo "export PATH=/goinfre/.brew/bin:$PATH" >> ~/.zshrc && brew --version || git clone --depth=1 https://github.com/Homebrew/brew /goinfre/.brew && export PATH=/goinfre/.brew/bin:$PATH && brew update && ln -s /goinfre/.brew ~/.brew + +echo "Download Complete" diff --git a/Box42/Resources/sh/cleanCache.sh b/Box42/Resources/sh/cleanCache.sh new file mode 100755 index 0000000..4e0024f --- /dev/null +++ b/Box42/Resources/sh/cleanCache.sh @@ -0,0 +1,157 @@ +#!/bin/bash + +#42Box: https://github.com/42Box +#Author: chanheki +#Date: 2023/08/10 + +# BOXY FOX +echo "" +echo "\033[38;5;208m Boxy Fox Cleaning Cache" +echo "" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’" +echo " β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo "β–‘β–‘β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo "β–‘β–‘β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo "β–‘β–‘β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo "β–‘β–‘β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo "β–‘β–‘β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆ" +echo "β–‘β–‘β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–’β–’β–ˆβ–ˆβ–“β–“β–“β–“" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–’β–’β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–‘β–‘β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–“β–“β–“β–“β–“β–“β–“β–“β–ˆβ–ˆβ–ˆβ–ˆβ–“β–“β–‘β–‘β–‘β–‘β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–“β–“β–“β–“β–“β–“β–“β–“β–’β–’β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–’β–’β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–’β–’β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–’β–’β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–’β–’ β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–‘β–‘β–“β–“β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–’β–’β–“β–“β–“β–“β–“β–“β–“β–“β–’β–’β–’β–’β–‘β–‘ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–‘β–‘β–‘β–‘β–“β–“β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–“β–“β–ˆβ–ˆβ–’β–’β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘ β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–‘β–‘ β–ˆβ–ˆ β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–ˆβ–ˆ" +echo " β–‘β–‘β–‘β–‘β–“β–“β–“β–“β–“β–“β–“β–“β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘ β–ˆβ–ˆ β–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–’ β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘ β–’β–’β–ˆβ–ˆ β–‘β–‘β–‘β–‘ β–’β–’β–’β–’ β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–‘β–‘ β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘ β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–ˆβ–ˆβ–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–ˆβ–ˆβ–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘" +echo "" + +# Command +RED="\033[31m" +GREEN="\033[32m" +YELLOW="\033[33m" +BLUE="\033[34m" +ORANGE="\033[38;5;208m" +# DELINE="\033[K" +# CURSUP="\033[A" +MAGENTA="\033[35m" +CYAN="\033[36m" +RESET="\033[0m" + +# Currently Size +Size=$(df -h ~ | grep ~ | awk '{print($2)}' | tr 'i' 'B') + +# Currently used capacity +Used=$(df -h ~ | grep ~ | awk '{print($3)}' | tr 'i' 'B') + +# Currently available capacity +Avail=$(df -h ~ | grep ~ | awk '{print($4)}' | tr 'i' 'B') +if [ "$Avail" == "0BB" ]; +then + Avail="0B" +fi + +echo "$CYAN Currently used capacity $Used/$Size $RESET\n" + +echo "$MAGENTA Clearing 🧹 cache ... $DELINE $RESET $CURSUP " + +# Trash +echo "$RED Clearing 🧹 trash can ...$DELINE $RESET $CURSUP " +rm -rf ~/.Trash/* &>/dev/null + +# 42 Caches +echo "$RED Clearing 🧹 42Cache ...$DELINE $RESET $CURSUP" +rm -rf ~/Library/*.42* &>/dev/null +rm -rf ~/*.42* &>/dev/null +rm -rf ~/.zcompdump* &>/dev/null +rm -rf ~/.cocoapods.42_cache_bak* &>/dev/null + +# General Caches +echo "$RED Clearing 🧹 Library ...$DELINE $RESET $CURSUP" +chmod -R 644 ~/Library/Caches/Homebrew &>/dev/null +rm -rf ~/Library/Caches/* &>/dev/null +rm -rf ~/Library/Application\ Support/Caches/* &>/dev/null + +echo "$RED Clearing 🧹 Slack ...$DELINE $RESET $CURSUP" +rm -rf ~/Library/Application\ Support/Slack/Service\ Worker/CacheAvail/* &>/dev/null +rm -rf ~/Library/Application\ Support/Slack/Cache/* &>/dev/null + +echo "$RED Clearing 🧹 Discord ...$DELINE $RESET $CURSUP" +rm -rf ~/Library/Application\ Support/discord/Cache/* &>/dev/null +rm -rf ~/Library/Application\ Support/discord/Code\ Cache/js* &>/dev/null +rm -rf ~/Library/Application\ Support/discord/Crashpad/completed/* &>/dev/null + +echo "$RED Clearing 🧹 VS Code ...$DELINE $RESET $CURSUP" +rm -rf ~/Library/Application\ Support/Code/Cache/* &>/dev/null +rm -rf ~/Library/Application\ Support/Code/CachedData/* &>/dev/null +rm -rf ~/Library/Application\ Support/Code/CachedExtensionVSIXs/* &>/dev/null +rm -rf ~/Library/Application\ Support/Code/Crashpad/completed/* &>/dev/null +rm -rf ~/Library/Application\ Support/Code/User/workspaceAvail/* &>/dev/null + +echo "$RED Clearing 🧹 Chrome ...$DELINE $RESET $CURSUP" +rm -rf ~/Library/Application\ Support/Google/Chrome/Profile\ [0-9]/Service\ Worker/CacheAvail/* &>/dev/null +rm -rf ~/Library/Application\ Support/Google/Chrome/Default/Service\ Worker/CacheAvail/* &>/dev/null +rm -rf ~/Library/Application\ Support/Google/Chrome/Profile\ [0-9]/Application\ Cache/* &>/dev/null +rm -rf ~/Library/Application\ Support/Google/Chrome/Default/Application\ Cache/* &>/dev/null +rm -rf ~/Library/Application\ Support/Google/Chrome/Crashpad/completed/* &>/dev/null +# tmp downloaded files with browsers +rm -rf ~/Library/Application\ Support/Chromium/Default/File\ System &>/dev/null +rm -rf ~/Library/Application\ Support/Chromium/Profile\ [0-9]/File\ System &>/dev/null +rm -rf ~/Library/Application\ Support/Google/Chrome/Default/File\ System &>/dev/null +rm -rf ~/Library/Application\ Support/Google/Chrome/Profile\ [0-9]/File\ System &>/dev/null + +# .DS_Store files +#echo "$RED Clearing 🧹 All .DS_Store ...$DELINE $RESET $CURSUP" +#find ~ -name .DS_Store -depth -exec rm {} \; &>/dev/null + +# Delete desktop +rm -rf ~/Desktop/Relocated Items &>/dev/null + +# Calculate usage after cleaning +Used=$(df -h ~ | grep ~ | awk '{print($3)}' | tr 'i' 'B') + +# Calculate usage after cleaning +Avail2=$(df -h ~ | grep ~ | awk '{print($4)}' | tr 'i' 'B') +if [ "$Avail2" == "0BB" ]; +then + Avail2="0B" +fi + +# Output the result +echo "\n$MAGENTA ✨ Complete Clearing cache ✨ $RESET \n" +echo "$GREEN Available/"$RED"Used/"$BLUE"Size "$GREEN"$Avail2/"$RED"$Used/"$BLUE"$Size $RESET\n" +echo "πŸ“¦: https://github.com/42Box" +echo "🦊: chanheki in 42Box" +echo "" diff --git a/Box42/Resources/sh/exportMacOSInfo.sh b/Box42/Resources/sh/exportMacOSInfo.sh new file mode 100644 index 0000000..32eed6b --- /dev/null +++ b/Box42/Resources/sh/exportMacOSInfo.sh @@ -0,0 +1 @@ +defaults export -g ~/.mysettings.plist diff --git a/Box42/Resources/sh/importMacOSInfo.sh b/Box42/Resources/sh/importMacOSInfo.sh new file mode 100644 index 0000000..070f87a --- /dev/null +++ b/Box42/Resources/sh/importMacOSInfo.sh @@ -0,0 +1 @@ +defaults -currentHost import ~/.mysettings.plist diff --git a/Box42/Resources/sh/keyMapping.sh b/Box42/Resources/sh/keyMapping.sh new file mode 100644 index 0000000..3d8010f --- /dev/null +++ b/Box42/Resources/sh/keyMapping.sh @@ -0,0 +1,146 @@ +#!/bin/sh + +# keyMapping.sh +# Box42 +# +# Created by Chanhee Kim on 8/13/23. +# + +mac_old=(0 0xff00000005 0xff00000004 0xff0100000010 0xff010004 0xff00000009 0xff00000008 0xc000000b4 0xc000000cd 0xc000000b3 0xc000000e2 0xc000000ea 0xc000000e9) +mac_new=(0 0xff00000005 0xff00000004 0xff0100000010 0xc00000221 0xc000000cf 0x10000009b 0xc000000b4 0xc000000cd 0xc000000b3 0xc000000e2 0xc000000ea 0xc000000e9) + +this_mac=(${mac_new[@]}) # change based on "old" or "new" mac / magic keyboard layout + +fn_keys=(0 0x70000003a 0x70000003b 0x70000003c 0x70000003d 0x70000003e 0x70000003f 0x700000040 0x700000041 0x700000042 0x700000043 0x700000044 0x700000045 0x700000068 0x700000069 0x70000006a 0x70000006b 0x70000006c 0x70000006d 0x70000006e) +fn_bri_dec=0xff0100000021 # or 0xc00000070 +fn_bri_inc=0xff0100000020 # or 0xc0000006f +fn_missionc=0xff0100000010 +fn_spotl=0xff0100000001 # or 0xc00000221 +fn_dict=0xc000000cf +fn_dnd=0x10000009b +fn_rew=0xc000000b4 +fn_play=0xc000000cd +fn_fwd=0xc000000b3 +fn_mute=0xc000000e2 +fn_vol_inc=0xc000000ea +fn_vol_dec=0xc000000e9 +fn_kbd_inc=0xff00000008 +fn_kbd_dec=0xff00000009 +fn_launchp=0xff0100000004 +fn_globe=0xff0100000030 +fn_desktop=0x700000044 # or f11 +fn_num_div=0x700000054 +fn_num_mul=0x700000055 +fn_num_sub=0x700000056 +fn_num_add=0x700000057 +fn_num_enter=0x700000058 +fn_num1=0x700000059 +fn_num2=0x70000005a +fn_num3=0x70000005b +fn_num4=0x70000005c +fn_num5=0x70000005d +fn_num6=0x70000005e +fn_num7=0x70000005f +fn_num8=0x700000060 +fn_num9=0x700000061 +fn_num0=0x700000062 +fn_num_dot=0x700000063 +fn_num_equ=0x700000067 + +function help() { + echo "$LESS_TERMCAP_mb$0 $LESS_TERMCAP_md[command]$LESS_TERMCAP_me + where $LESS_TERMCAP_md[command]$LESS_TERMCAP_me is one of: + show display the current user key map + export output the current user key map for creating a LaunchAgent + reset reset user key map to default + default display the default key map (from ioreg) +$LESS_TERMCAP_mb$0 $LESS_TERMCAP_md[n=keycode ...]$LESS_TERMCAP_me + where ${LESS_TERMCAP_us}n$LESS_TERMCAP_ue is 1 to 12 for thefunction key, and + ${LESS_TERMCAP_us}keycode$LESS_TERMCAP_ue is a hex key code starting with 0x +$LESS_TERMCAP_mb$0 $LESS_TERMCAP_md[n=function ...]$LESS_TERMCAP_me + where ${LESS_TERMCAP_us}n$LESS_TERMCAP_ue is 1 to 12 for the function key, and + ${LESS_TERMCAP_us}function$LESS_TERMCAP_ue is one of: + bri_dec | bri_inc decrease / increase display brightness + kbd_dec | kbd_inc decrease / increase keyboard backlight brightness + missionc | launchp show mission control / launchpad + spotl | dict spotlight search / dictation (hold for Siri) + dnd | mute toggle do not disturb / mute + rew | play | fwd rewind / play or pause / fast-forward media + vol_dec | vol_inc decrease / increase volume + globe | desktop show emoji / desktop (same as F11) + num0 to num9 number pad keys, along with: + num_add | num_sub | num_mul | num_div | num_dot | num_equ | num_enter +" +} +function show() { + echo Current user key map + hidutil property -g UserKeyMapping +} +function reset() { + echo Reset user key map + hidutil property -s "{\"UserKeyMapping\":[]}" >/dev/null +} +function default() { + echo Show default key map + ioreg -l | grep -o "\"FnFunctionUsageMap\" = .*" +} +function export() { + x=$(hidutil property -g UserKeyMapping | sed -E "s/(HIDKeyboardModifierMappingDst) = (.*);/\"\1\": \2,/g;s/(HIDKeyboardModifierMappingSrc) = (.*);/\"\1\": \2/g;s/\(/[/;s/\)/]/") + echo ' + + + + Label + com.local.KeyRemapping + ProgramArguments + + /usr/bin/hidutil + property + --set + {"UserKeyMapping":'"$x"' + } + + RunAtLoad + + +' +} +function map() { + y="" + for x in "$@"; do + x=(${x//=/ }) + x0=${x[0]} + x1=${x[1]} + if [[ ${#x[@]} -eq 2 && ( $x0 == [1-9] || $x0 == 1[012]) ]]; then + fn=${this_mac[$x0]} + [[ "$fn" == "" ]] && echo "Error no such key F$x0" && exit -1 + if [[ "$x1" == f[1-9] || "$x1" == f1[0-9] ]]; then + kc=${x1:1} + kc=${fn_keys[$kc]} + [[ "$kc" == "" ]] && echo "Error mapping F$x0 [$fn] to unknown $x1" && exit -1 + echo "Mapping F$x0 [$fn] to HID $x1 [$kc]" + y="{\"HIDKeyboardModifierMappingSrc\":$fn,\"HIDKeyboardModifierMappingDst\":$kc},$y" + elif [[ "$kc" == 0x[0-9A-Fa-f]* && ( ${#kc} -ge 11 && ${#kc} -le 14 ) ]]; then + echo "Mapping F$x0 [$fn] to HID hex code [$kc]" + y="{\"HIDKeyboardModifierMappingSrc\":$fn,\"HIDKeyboardModifierMappingDst\":$kc},$y" + else + kc=fn_$x1 + kc=${!kc} + [[ "$kc" == "" ]] && echo "Error mapping F$x0 [$fn] to unknown $x1" && exit -1 + echo "Mapping F$x0 [$fn] to HID $x1 [$kc]" + y="{\"HIDKeyboardModifierMappingSrc\":$fn,\"HIDKeyboardModifierMappingDst\":$kc},$y" + fi + fi + hidutil property -s "{\"UserKeyMapping\":[${y%?}]}" >/dev/null + done +} +function kbd() { + map 4=kbd_dec 5=kbd_inc +} +if [[ ${#@} -eq 1 && "$1" != *=* ]]; then + [[ $(LC_ALL=C type -t "$1") == "function" && "$1" != "map" ]] && $1 && exit $? +elif [[ ${#@} -ge 1 ]]; then + map "$@" + exit $? +fi +help diff --git a/Box42/Resources/sh/nodeInstall.sh b/Box42/Resources/sh/nodeInstall.sh new file mode 100644 index 0000000..767a31a --- /dev/null +++ b/Box42/Resources/sh/nodeInstall.sh @@ -0,0 +1,69 @@ +#!/bin/sh + +#42Box: https://github.com/42Box +#Author: chanheki +#Date: 2023/08/10 + +# BOXY FOX +echo "" +echo "\033[38;5;208m Boxy Fox Node install" +echo "" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’β–’" +echo " β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo "β–‘β–‘β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo "β–‘β–‘β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo "β–‘β–‘β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo "β–‘β–‘β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo "β–‘β–‘β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆ" +echo "β–‘β–‘β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–’β–’β–ˆβ–ˆβ–“β–“β–“β–“" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–’β–’β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–‘β–‘β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–“β–“β–“β–“β–“β–“β–“β–“β–ˆβ–ˆβ–ˆβ–ˆβ–“β–“β–‘β–‘β–‘β–‘β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–“β–“β–“β–“β–“β–“β–“β–“β–’β–’β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–’β–’β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–’β–’β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–’β–’β–’β–’β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–’β–’ β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–‘β–‘β–“β–“β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–’β–’β–“β–“β–“β–“β–“β–“β–“β–“β–’β–’β–’β–’β–‘β–‘ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–ˆβ–ˆ" +echo " β–‘β–‘β–‘β–‘β–“β–“β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–“β–“β–ˆβ–ˆβ–’β–’β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘ β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–‘β–‘ β–ˆβ–ˆ β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–ˆβ–ˆ" +echo " β–‘β–‘β–‘β–‘β–“β–“β–“β–“β–“β–“β–“β–“β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘ β–ˆβ–ˆ β–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–’ β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘ β–’β–’β–ˆβ–ˆ β–‘β–‘β–‘β–‘ β–’β–’β–’β–’ β–‘β–‘β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–‘β–‘ β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆ" +echo " β–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘ β–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–ˆβ–ˆβ–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘ β–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–‘β–‘β–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆ β–‘β–‘β–ˆβ–ˆβ–‘β–‘ β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ" +echo " β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘" +echo "" + + +export N_PREFIX=/goinfre +curl -fsSL https://raw.githubusercontent.com/tj/n/master/bin/n | bash -s lts +echo "# bin folder for node.js">>~/.zshrc +echo 'export PATH="$PATH:$HOME/bin"' >> ~/.zshrc +export PATH=/goinfre/bin:$PATH +ln -s /goinfre/bin ~/bin + +echo "Download Complete" diff --git a/Box42/Scripts/AppleScripts+ShowMessage.swift b/Box42/Scripts/AppleScripts+ShowMessage.swift new file mode 100644 index 0000000..3a7411b --- /dev/null +++ b/Box42/Scripts/AppleScripts+ShowMessage.swift @@ -0,0 +1,42 @@ +// +// AppleScripts+ShowMessage.swift +// Box42 +// +// Created by Chanhee Kim on 8/18/23. +// + +import Foundation +import AppKit + +func showMessageWithAppleScript(_ message: String) { + let appleScript = """ + display dialog "\(message)" buttons {"OK"} default button "OK" + """ + + var error: NSDictionary? + if let scriptObject = NSAppleScript(source: appleScript) { + scriptObject.executeAndReturnError(&error) + if let error = error { + print("AppleScript Error: \(error)") + } + } +} + +func showMessageWithAppleScript(_ message: String, _ button: String, completion: @escaping (String?) -> Void) { + let appleScript = """ + display dialog "\(message)" buttons {"\(button)", "μ·¨μ†Œ"} default button "\(button)" + """ + + var error: NSDictionary? + if let scriptObject = NSAppleScript(source: appleScript) { + let output = scriptObject.executeAndReturnError(&error) + let buttonReturned = output.forKeyword(keyDirectObject) + print("output", output.description) +// completion(output.stringValue) + completion(buttonReturned?.stringValue) + if let error = error { + print("AppleScript Error: \(error)") + completion(nil) + } + } +} diff --git a/Box42/Scripts/Scripts.swift b/Box42/Scripts/Scripts.swift new file mode 100644 index 0000000..96323f7 --- /dev/null +++ b/Box42/Scripts/Scripts.swift @@ -0,0 +1,25 @@ +// +// Scripts.swift +// Box42 +// +// Created by Chanhee Kim on 8/11/23. +// + +import Foundation + +struct Scripts { + var info: [(name: String, description: String)] = [("cleanCache", "cleaning cache"), ("brewInGoinfre", + "brew download in goinfre")] +} + +struct Script { + var id: UUID + var name: String + var description: String + + init(name: String, description: String) { + self.id = UUID() + self.name = name + self.description = description + } +} diff --git a/Box42/Shared/BoxSizeManager.swift b/Box42/Shared/BoxSizeManager.swift new file mode 100644 index 0000000..acd32f4 --- /dev/null +++ b/Box42/Shared/BoxSizeManager.swift @@ -0,0 +1,34 @@ +// +// BoxSizeManager.swift +// Box42 +// +// Created by Chan on 2023/08/11. +// + +import Cocoa + +struct BoxSizeManager { + static let shared = BoxSizeManager() + + var halfSize: (width: CGFloat, height: CGFloat)! + var size: (width: CGFloat, height: CGFloat)! + var buttonGroupSize: (width: CGFloat, height: CGFloat)! + var toolbarGroupSize: (width: CGFloat, height: CGFloat)! + var viewStack: [NSView?] + var boxViewSizeNSRect: NSRect + var boxViewSizeNSSize: NSSize + var buttonGroupSizeNSRect: NSRect + var windowButtonGroupSize: (width: CGFloat, height: CGFloat)! + + init() { + halfSize = (NSScreen.halfOfScreen.x, NSScreen.halfOfScreen.y) + size = (NSScreen.customScreenSize.x, NSScreen.customScreenSize.y) + buttonGroupSize = (CGFloat(132), NSScreen.customScreenSize.y) + toolbarGroupSize = (CGFloat(132), CGFloat(100)) + viewStack = [NSView()] + boxViewSizeNSRect = NSRect(x: 0, y: 0, width: size.width, height: size.height) + boxViewSizeNSSize = NSSize(width: size.width, height: size.height) + buttonGroupSizeNSRect = NSRect(x: 0, y: 0, width: buttonGroupSize.width, height: buttonGroupSize.height) + windowButtonGroupSize = (CGFloat(200), NSScreen.customScreenSize.y) + } +} diff --git a/Box42/Shared/Constants.swift b/Box42/Shared/Constants.swift new file mode 100644 index 0000000..322faa9 --- /dev/null +++ b/Box42/Shared/Constants.swift @@ -0,0 +1,17 @@ +// +// Constants.swift +// Box42 +// +// Created by Chanhee Kim on 8/17/23. +// + +struct Constants { + struct url { + static let InitialName = "home" + static let InitialPage = "https://42box.github.io/front-end/" + } + + struct UI { + static let GroupAutolayout = 12 + } +} diff --git a/Box42/Shared/StateManager.swift b/Box42/Shared/StateManager.swift new file mode 100644 index 0000000..e73da57 --- /dev/null +++ b/Box42/Shared/StateManager.swift @@ -0,0 +1,68 @@ +// +// StateManager.swift +// Box42 +// +// Created by Chanhee Kim on 8/8/23. +// + +class StateManager { + static let shared = StateManager() + + private var isPin: Bool! + private var isShowCPUUsage: Bool! + private var isShowWindow: Bool! + private var isShowFirstWindow: Bool! + private var isAutoStorage: Bool! + + private init() { + isPin = false + isShowCPUUsage = false + isShowWindow = false + isShowFirstWindow = false + isAutoStorage = true + } + + func getIsPin() -> Bool { + return isPin + } + + func setToggleIsPin() { + isPin.toggle() + } + + func getIsShowCPUUsage() -> Bool { + return isShowCPUUsage + } + + func setToggleIsShowCPUUsage() { + isShowCPUUsage.toggle() + } + + func getIsShowWindow() -> Bool { + return isShowWindow + } + + func setToggleIsShowWindow() { + isShowWindow.toggle() + } + + func getIsShowFirstWindow() -> Bool { + return isShowFirstWindow + } + + func setToggleIsShowFirstWindow() { + isShowFirstWindow.toggle() + } + + func getIsAutoStorage() -> Bool { + return isAutoStorage + } + + func setOffIsAutoStorage() { + isAutoStorage = false + } + + func setOnIsAutoStorage() { + isAutoStorage = true + } +} diff --git a/Box42/CPU/CPU.swift b/Box42/System/CPU.swift similarity index 85% rename from Box42/CPU/CPU.swift rename to Box42/System/CPU.swift index 33c11a9..f7a8dbf 100644 --- a/Box42/CPU/CPU.swift +++ b/Box42/System/CPU.swift @@ -8,9 +8,8 @@ import Foundation -public class CPU { +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/System/EventMonitor.swift b/Box42/System/EventMonitor.swift new file mode 100644 index 0000000..ecc7f8d --- /dev/null +++ b/Box42/System/EventMonitor.swift @@ -0,0 +1,36 @@ +// +// EventMonitor.swift +// Box42 +// +// Created by Chan on 2023/03/16. +// + +import Cocoa + +class EventMonitor { + private var monitor: Any? + private let mask: NSEvent.EventTypeMask + private let handler: (NSEvent?) -> Void + + init(monitor: Any? = nil, mask: NSEvent.EventTypeMask, handler: @escaping (NSEvent?) -> Void) { + self.mask = mask + self.handler = handler + } + + deinit { + stop() + } + + func start() { + print("EventMonitor: Starting") + monitor = NSEvent.addGlobalMonitorForEvents(matching: mask, handler: handler) + } + + func stop() { + if monitor != nil { + print("EventMonitor: Stoping") + NSEvent.removeMonitor(monitor!) + monitor = nil + } + } +} diff --git a/Box42/System/Storage.swift b/Box42/System/Storage.swift new file mode 100644 index 0000000..4024446 --- /dev/null +++ b/Box42/System/Storage.swift @@ -0,0 +1,129 @@ +// +// Storage.swift +// Box42 +// +// Created by Chanhee Kim on 8/16/23. +// + +import Foundation +import Combine + +class Storage { + var storageTimer: Timer? = nil + var usage: (value: Double, description:String) = (0.0, "") + var count = 0 + let gibiByte = Double(1 << 30) + var config: StorageConfig + + private var subscriptions = Set() + + private var availableUsage: Double? + private var usedUsage: Double? + private var totalUsage: Double? + + init(config: StorageConfig = StorageConfig.shared) { + self.config = config + + config.$threshold.sink { [weak self] newThreshold in + self?.storageTimerEvent() + }.store(in: &subscriptions) + + config.$period.sink { [weak self] newPeriod in + self?.storageTimerEvent() + }.store(in: &subscriptions) + } + + func checkStorage() -> Bool { + do { + let fileSystemAttributes = try FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory()) + if let freeSpace = fileSystemAttributes[.systemFreeSize] as? NSNumber { + availableUsage = freeSpace.doubleValue / gibiByte + } + if let totalSpace = fileSystemAttributes[.systemSize] as? NSNumber { + totalUsage = totalSpace.doubleValue / gibiByte + } + if totalUsage != nil && availableUsage != nil { + usedUsage = totalUsage! - availableUsage! + } + } catch { + print("Error obtaining system storage info: \(error)") + return true + } + return false + } + + func storageTimerEvent(){ + storageTimer?.invalidate() + + if StateManager.shared.getIsAutoStorage() == false { + return + } + + storageTimer = Timer.scheduledTimer(withTimeInterval: config.period.rawValue, repeats: true, block: { [weak self] _ in + guard let self = self else { return } + + if self.checkStorage() { + print("FileSystem정보λ₯Ό κ°€μ Έμ˜€λŠ”λ° μ‹€νŒ¨ ν•˜μ˜€μŠ΅λ‹ˆλ‹€.") + return + } + + if let usedUsage = self.usedUsage, let totalUsage = self.totalUsage, totalUsage != 0 { + let usagePercentage = (totalUsage - usedUsage) / totalUsage + if usagePercentage < self.config.threshold.rawValue { + self.cleanSh() + self.count += 1 + if self.count > 2 { +// showMessageWithAppleScript("μΊμ‹œ λ¬Έμ œκ°€ μ•„λ‹™λ‹ˆλ‹€. ncdu ~ λ₯Ό ν™•μΈν•΄μ£Όμ„Έμš”.", "μž¬μ‹œμž‘") { button in +// print("timer") +// dump(button) +// if let button = button { +// switch button { +// case "μž¬μ‹œμž‘": +// StateManager.shared.setOnIsAutoStorage() +// print("μž¬μ‹œμž‘ λ²„νŠΌμ„ ν΄λ¦­ν–ˆμŠ΅λ‹ˆλ‹€.") +// case "μ·¨μ†Œ": +// // μ·¨μ†Œ κ΄€λ ¨ 둜직 μ‹€ν–‰ +// print("μ·¨μ†Œ λ²„νŠΌμ„ ν΄λ¦­ν–ˆμŠ΅λ‹ˆλ‹€.") +// default: +// break +// } +// } +// } + StateManager.shared.setOffIsAutoStorage() + // μ—¬κΈ°μ„œλ„ 타이머λ₯Ό μ€‘μ§€μ‹œμΌœμ•Ό ν•©λ‹ˆλ‹€. + self.storageTimer?.invalidate() + } else { + print("\(usedUsage.roundedToTwoDecimalPlaces) GB", "Storage used is less than 30%") + } + } else { + self.count = 0 + } + } else { + print("Failed to get storage usage details") + } + }) + + storageTimer?.fire() + } + + + func cleanSh() { + if let scriptPath = Bundle.main.path(forResource: "cleanCache", ofType: "sh") { + let task = Process() + task.launchPath = "/bin/sh" + task.arguments = [scriptPath] + + task.launch() + task.waitUntilExit() + + // μ‹€ν–‰λ˜μ—ˆλ‹€λŠ” 것을 μ•Œλ €μ£Όκ³  μ‹ΆμœΌλ©΄ νŒŒμ΄ν”„ λ½‘μ•„μ„œ ν•˜λ©΄λ¨. + } else { + print("Script not found") + } + } + + func change() { + config.setThreshold(.percentage30) + config.setPeriod(.period10s) + } +} diff --git a/Box42/System/StorageConfig.swift b/Box42/System/StorageConfig.swift new file mode 100644 index 0000000..002581c --- /dev/null +++ b/Box42/System/StorageConfig.swift @@ -0,0 +1,44 @@ +// +// StorageConfig.swift +// Box42 +// +// Created by Chanhee Kim on 8/16/23. +// + +enum StorageThreshold: Double { + case percentage05 = 0.05 + case percentage10 = 0.1 + case percentage30 = 0.3 + case percentage50 = 0.5 +} + +enum StoragePeriod: Double { + case period1s = 1.0 + case period3s = 3.0 + case period5s = 5.0 + case period10s = 10.0 +} + +import Combine + +class StorageConfig: ObservableObject { + static let shared = StorageConfig() + + @Published var threshold: StorageThreshold + @Published var period: StoragePeriod + + init(_ threshold: StorageThreshold = .percentage30, _ period: StoragePeriod = .period3s) { + self.threshold = threshold + self.period = period + } + + func setThreshold(_ threshold: StorageThreshold) { + self.threshold = threshold + print(self.threshold) + } + + func setPeriod(_ period: StoragePeriod) { + self.period = period + print(self.period) + } +} diff --git a/Box42/Toolbar/ToolbarViewController.swift b/Box42/Toolbar/ToolbarViewController.swift new file mode 100644 index 0000000..ea32aab --- /dev/null +++ b/Box42/Toolbar/ToolbarViewController.swift @@ -0,0 +1,57 @@ +// +// ToolbarViewController.swift +// Box42 +// +// Created by Chanhee Kim on 8/18/23. +// + +import Cocoa + +class ToolbarViewController: NSViewController { + var displayURL = DisplayURLInToolbar() + var goBackButton: GoBackInToolbar? + var goForwardButton: GoForwardInToolbar? + var reloadPageButton: ReloadPageViaToolbar? + var goHomePageViaButton: GoHomePageViaToolbar? + var sidebarLeading: SideBarLeading? + + override func loadView() { + displayURL = DisplayURLInToolbar() + sidebarLeading = SideBarLeading(image: NSImage(imageLiteralResourceName: "sidebar.leading"), completion: sidebar) + goBackButton = GoBackInToolbar(image: NSImage(imageLiteralResourceName: "arrow.left"), completion: goBack) + goForwardButton = GoForwardInToolbar(image: NSImage(imageLiteralResourceName: "arrow.right"), completion: goFoward) + reloadPageButton = ReloadPageViaToolbar(image: NSImage(imageLiteralResourceName: "arrow.clockwise"), completion: reloadPage) + goHomePageViaButton = GoHomePageViaToolbar(image: NSImage(imageLiteralResourceName: "figure.skating"), completion: goToHome) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + // Do view setup here. + } + + func sidebar() { + print("sidebar") + } + + func goBack() { + WebViewManager.shared.hostingWebView?.goBack() + } + + func goFoward() { + WebViewManager.shared.hostingWebView?.goForward() + } + + func reloadPage() { + WebViewManager.shared.hostingWebView?.reload() + } + + func goToHome() { + if let item = WebViewManager.shared.hostingWebView?.backForwardList.backList.first { + WebViewManager.shared.hostingWebView?.go(to: item) + } + } +} diff --git a/Box42/Toolbar/View/BoxToolbarViewGroup.swift b/Box42/Toolbar/View/BoxToolbarViewGroup.swift new file mode 100644 index 0000000..ac17e8c --- /dev/null +++ b/Box42/Toolbar/View/BoxToolbarViewGroup.swift @@ -0,0 +1,31 @@ +// +// BoxToolbarViewGroup.swift +// Box42 +// +// Created by Chanhee Kim on 8/18/23. +// + +import AppKit +import SnapKit + +class BoxToolbarViewGroup: NSView { + var toolbarVC: ToolbarViewController? + + init() { +// toolbarVC = ToolbarViewController(nibName: nil, bundle: nil) + + super.init(frame: NSRect(x: 0, y: 0, width: BoxSizeManager.shared.size.width - BoxSizeManager.shared.toolbarGroupSize.width, height: BoxSizeManager.shared.toolbarGroupSize.height)) + + self.wantsLayer = true +// self.addSubview(toolbarVC!.view) + + toolbarVC?.view.translatesAutoresizingMaskIntoConstraints = false + toolbarVC?.view.snp.makeConstraints { make in + make.edges.equalTo(self) + } + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/Box42/Toolbar/View/DisplayURLInToolbar.swift b/Box42/Toolbar/View/DisplayURLInToolbar.swift new file mode 100644 index 0000000..d8026dd --- /dev/null +++ b/Box42/Toolbar/View/DisplayURLInToolbar.swift @@ -0,0 +1,33 @@ +// +// displayURLInToolbar.swift +// Box42 +// +// Created by Chanhee Kim on 8/18/23. +// + +import AppKit + +class DisplayURLInToolbar: NSTextField { + + override init(frame frameRect: NSRect) { + super.init(frame: frameRect) + + self.isEditable = true + self.isBordered = false // ν…Œλ‘λ¦¬λ₯Ό μ œκ±°ν•©λ‹ˆλ‹€. + self.backgroundColor = NSColor.clear // 배경색을 투λͺ…ν•˜κ²Œ λ§Œλ“­λ‹ˆλ‹€. + + if let url = WebViewManager.shared.hostingWebView?.url { + self.stringValue = url.absoluteString + } + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func updateURL() { + if let url = WebViewManager.shared.hostingWebView?.url { + self.stringValue = url.absoluteString + } + } +} diff --git a/Box42/Toolbar/View/GoBackInToolbar.swift b/Box42/Toolbar/View/GoBackInToolbar.swift new file mode 100644 index 0000000..6bb209f --- /dev/null +++ b/Box42/Toolbar/View/GoBackInToolbar.swift @@ -0,0 +1,31 @@ +// +// GoBackInToolbar.swift +// Box42 +// +// Created by Chanhee Kim on 8/18/23. +// + +import AppKit + +class GoBackInToolbar: NSButton { + + private var callback: (() -> Void)? + + init(image: NSImage, completion: @escaping () -> Void) { + super.init(frame: .zero) + + self.image = image + self.bezelStyle = .texturedRounded + self.target = self + self.action = #selector(goBackWebView) + self.callback = completion + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc func goBackWebView() { + callback?() + } +} diff --git a/Box42/Toolbar/View/GoForwardInToolbar.swift b/Box42/Toolbar/View/GoForwardInToolbar.swift new file mode 100644 index 0000000..e5f04fb --- /dev/null +++ b/Box42/Toolbar/View/GoForwardInToolbar.swift @@ -0,0 +1,31 @@ +// +// GoForwardInToolbar.swift +// Box42 +// +// Created by Chanhee Kim on 8/18/23. +// + +import AppKit + +class GoForwardInToolbar: NSButton { + + private var callback: (() -> Void)? + + init(image: NSImage, completion: @escaping () -> Void) { + super.init(frame: .zero) + + self.image = image + self.bezelStyle = .texturedRounded + self.target = self + self.action = #selector(goForwardWebView) + self.callback = completion + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc func goForwardWebView() { + callback?() + } +} diff --git a/Box42/Toolbar/View/GoHomePageViaToolbar().swift b/Box42/Toolbar/View/GoHomePageViaToolbar().swift new file mode 100644 index 0000000..2728ff3 --- /dev/null +++ b/Box42/Toolbar/View/GoHomePageViaToolbar().swift @@ -0,0 +1,31 @@ +// +// GoHomePageViaToolbar.swift +// Box42 +// +// Created by Chanhee Kim on 8/18/23. +// + +import AppKit + +class GoHomePageViaToolbar: NSButton { + + private var callback: (() -> Void)? + + init(image: NSImage, completion: @escaping () -> Void) { + super.init(frame: .zero) + + self.image = image + self.bezelStyle = .texturedRounded + self.target = self + self.action = #selector(goToHomePageWebView) + self.callback = completion + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc func goToHomePageWebView() { + callback?() + } +} diff --git a/Box42/Toolbar/View/RefreshPageViaToolbar.swift b/Box42/Toolbar/View/RefreshPageViaToolbar.swift new file mode 100644 index 0000000..8be72bc --- /dev/null +++ b/Box42/Toolbar/View/RefreshPageViaToolbar.swift @@ -0,0 +1,31 @@ +// +// ReloadPageViaToolbar.swift +// Box42 +// +// Created by Chanhee Kim on 8/18/23. +// + +import AppKit + +class ReloadPageViaToolbar: NSButton { + + private var callback: (() -> Void)? + + init(image: NSImage, completion: @escaping () -> Void) { + super.init(frame: .zero) + + self.image = image + self.bezelStyle = .texturedRounded + self.target = self + self.action = #selector(reloadWebView) + self.callback = completion + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc func reloadWebView() { + callback?() + } +} diff --git a/Box42/Toolbar/View/SideBarLeading.swift b/Box42/Toolbar/View/SideBarLeading.swift new file mode 100644 index 0000000..9849a05 --- /dev/null +++ b/Box42/Toolbar/View/SideBarLeading.swift @@ -0,0 +1,31 @@ +// +// SideBarLeading.swift +// Box42 +// +// Created by Chanhee Kim on 8/18/23. +// + +import AppKit + +class SideBarLeading: NSButton { + + private var callback: (() -> Void)? + + init(image: NSImage, completion: @escaping () -> Void) { + super.init(frame: .zero) + + self.image = image + self.bezelStyle = .texturedRounded + self.target = self + self.action = #selector(sideBarLeading) + self.callback = completion + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc func sideBarLeading() { + callback?() + } +} diff --git a/Box42/UI/HoverButton.swift b/Box42/UI/HoverButton.swift new file mode 100644 index 0000000..c7bbcfe --- /dev/null +++ b/Box42/UI/HoverButton.swift @@ -0,0 +1,46 @@ +// +// HoverButton.swift +// Box42 +// +// Created by Chanhee Kim on 8/18/23. +// + +import Cocoa + +class HoverButton: NSButton { + + private var trackingArea: NSTrackingArea? + + override func awakeFromNib() { + super.awakeFromNib() + + self.wantsLayer = true + self.layer?.borderColor = NSColor.black.cgColor + self.layer?.borderWidth = 1.0 + self.layer?.cornerRadius = 5.0 + } + + override func updateTrackingAreas() { + super.updateTrackingAreas() + + if let trackingArea = self.trackingArea { + self.removeTrackingArea(trackingArea) + } + + let options: NSTrackingArea.Options = [.mouseEnteredAndExited, .activeAlways] + trackingArea = NSTrackingArea(rect: self.bounds, options: options, owner: self, userInfo: nil) + self.addTrackingArea(trackingArea!) + } + + override func mouseEntered(with event: NSEvent) { + // ν˜Έλ²„ μƒνƒœμΌ λ•Œμ˜ μŠ€νƒ€μΌμ„ μ •μ˜ν•©λ‹ˆλ‹€. + self.layer?.backgroundColor = NSColor.gray.cgColor + self.layer?.opacity = 1.0 + } + + override func mouseExited(with event: NSEvent) { + // ν˜Έλ²„ μƒνƒœκ°€ 아닐 λ•Œμ˜ μŠ€νƒ€μΌμ„ μ •μ˜ν•©λ‹ˆλ‹€. +// self.layer?.backgroundColor = NSColor.white.cgColor + self.layer?.opacity = 0.7 + } +} diff --git a/Box42/UI/MovableContainerView.swift b/Box42/UI/MovableContainerView.swift new file mode 100644 index 0000000..69c4042 --- /dev/null +++ b/Box42/UI/MovableContainerView.swift @@ -0,0 +1,24 @@ +// +// MovableContainerView.swift +// Box42 +// +// Created by Chanhee Kim on 8/19/23. +// + +import AppKit + +class MovableContainerView: NSView { + init() { + super.init(frame: NSRect(x: 0, y: 0, width: 300, height: BoxSizeManager.shared.size.height)) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func mouseDown(with event: NSEvent) { + if let window = self.window { + window.performDrag(with: event) + } + } +} diff --git a/Box42/URL/URLModel.swift b/Box42/URL/URLModel.swift deleted file mode 100644 index 209828e..0000000 --- a/Box42/URL/URLModel.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// URLModel.swift -// Box42 -// -// Created by Chan on 2023/03/16. -// - -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/")!, - ] - - let URLstring: [(String, String)] = [ - ("home", "https://42box.github.io/front-end/"), - // ("home", "http://127.0.0.1:3000/"), - ("Box 42", "https://42box.github.io/front-end/#/box"), - ("Intra 42", "https://intra.42.fr"), - ("Jiphyeonjeon", "https://42library.kr"), - ("E-Library", "https://42seoul.dkyobobook.co.kr/main.ink"), - ("24Hane", "https://24hoursarenotenough.42seoul.kr"), - ("80000Coding", "https://80000coding.oopy.io"), - ("where42", "https://www.where42.kr"), - ("cabi", "https://cabi.42seoul.io/"), - ("42gg", "https://42gg.kr/"), - ] -} diff --git a/Box42/WebView/URL/URLModel.swift b/Box42/WebView/URL/URLModel.swift new file mode 100644 index 0000000..014f62c --- /dev/null +++ b/Box42/WebView/URL/URLModel.swift @@ -0,0 +1,43 @@ +// +// URLModel.swift +// Box42 +// +// Created by Chan on 2023/03/16. +// + +import Foundation + +typealias nameUrl = (name: String, url: String) + +struct URLModel { + 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 api call λ‚ λ €μ„œ λ°›μ•„μ˜¬ 것. + let URLstring: [nameUrl] = [ + ("home", "http://42box.kr/"), + ("23Coaltheme", "https://42box.github.io/front-end/"), + // ("home", "http://127.0.0.1:3000/"), + ("Box 42", "https://42box.github.io/front-end/#/box"), + ("Intra 42", "https://intra.42.fr"), + ("Jiphyeonjeon", "https://42library.kr"), + ("42STAT", "https://stat.42seoul.kr/home"), + ("24Hane", "https://24hoursarenotenough.42seoul.kr"), + ("80kCoding", "https://80000coding.oopy.io"), + ("where42", "https://www.where42.kr"), + ("cabi", "https://cabi.42seoul.io/"), + ("42gg", "https://42gg.kr/"), + ("textart", "https://textart.sh/"), + ] +} diff --git a/Box42/WebView/WebView.swift b/Box42/WebView/WebView.swift new file mode 100644 index 0000000..0e909ad --- /dev/null +++ b/Box42/WebView/WebView.swift @@ -0,0 +1,42 @@ +// +// WebView.swift +// Box42 +// +// Created by Chanhee Kim on 8/18/23. +// + +import WebKit + +class WebView: WKWebView, WKScriptMessageHandler, WKUIDelegate, WKNavigationDelegate { + func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { + print("userContentController") + } + + + init() { + let preferences = WKPreferences() + preferences.javaScriptEnabled = true + preferences.javaScriptCanOpenWindowsAutomatically = true + + let contentController = WKUserContentController() + let configuration = WKWebViewConfiguration() + configuration.preferences = preferences + configuration.userContentController = contentController + + super.init(frame: .zero, configuration: configuration) + + contentController.add(self, name: "box") // Moved after super.init + + self.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true + self.configuration.preferences.javaScriptEnabled = true + self.configuration.preferences.setValue(true, forKey: "allowFileAccessFromFileURLs") + + self.uiDelegate = self + self.navigationDelegate = self + self.becomeFirstResponder() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/Box42/WebView/WebViewController.swift b/Box42/WebView/WebViewController.swift index 43b9033..e0d1f02 100644 --- a/Box42/WebView/WebViewController.swift +++ b/Box42/WebView/WebViewController.swift @@ -7,52 +7,69 @@ import Cocoa import WebKit +import Combine -class WebViewController: NSViewController, WKScriptMessageHandler, WKUIDelegate, WKNavigationDelegate { - - func loadWebViewInit() { - for i in 0.. = [] + + override func loadView() { + self.webView = WebView() + self.view = webView + webViewInit() + loadWebviewInit() +// bindViewModel() + } + + func loadWebviewInit() { + URLVM.setUpURLdict() + loadAllWebview() + } + + func loadWebView(_ name: String, _ url: URL) { + let wkWebView = WebView() + WebViewManager.shared.list[name] = wkWebView + DispatchQueue.main.async { + wkWebView.load(self.URLVM.requestURL(url)) + } + } + + func loadAllWebview() { + for (name, URL) in URLVM.URLdict { + loadWebView(name, URL) } } - func addWebView() -> WKWebView { - let preferences = WKPreferences() - preferences.javaScriptEnabled = true - preferences.javaScriptCanOpenWindowsAutomatically = true - - let contentController = WKUserContentController() - contentController.add(self, name: "box") - - let configuration = WKWebViewConfiguration() - configuration.preferences = preferences - configuration.userContentController = contentController - - let webView = WKWebView(frame: .zero, configuration: configuration) - - webView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true - webView.configuration.preferences.javaScriptEnabled = true - - webView.configuration.preferences.setValue(true, forKey: "allowFileAccessFromFileURLs") - if #available(macOS 11.0, *) { - webView.configuration.defaultWebpagePreferences.allowsContentJavaScript = true + func webViewInit() { + WebViewManager.shared.hostingWebView = self.webView + DispatchQueue.main.async { + self.webView.load(self.URLVM.requestURL(self.URLVM.safeURL())) } - - webView.uiDelegate = self - webView.navigationDelegate = self - return webView } - override func viewDidLoad() { - super.viewDidLoad() + func bindViewModel() { + URLVM.$URLdict + .sink { [weak self] _ in + self?.loadAllWebview() + } + .store(in: &cancellables) } - func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { - print(message.name) + override func viewDidLoad() { + super.viewDidLoad() + } + + func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { + print(message.name) + } + + func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { + if let url = navigationAction.request.url { + webView.load(URLRequest(url: url)) + } + return nil } } diff --git a/Box42/WebView/WebViewManager.swift b/Box42/WebView/WebViewManager.swift new file mode 100644 index 0000000..bdf0fe1 --- /dev/null +++ b/Box42/WebView/WebViewManager.swift @@ -0,0 +1,23 @@ +// +// WebViewList.swift +// Box42 +// +// Created by Chanhee Kim on 8/17/23. +// + +import WebKit + +typealias WebViewMapping = [String : WKWebView] + +class WebViewManager { + static let shared = WebViewManager() + + var hostingname: String? + var hostingWebView: WKWebView? + + var list: WebViewMapping! + + private init() { + list = [:] + } +} diff --git a/Box42/WebView/WebViewModel.swift b/Box42/WebView/WebViewModel.swift index 162069a..2e091a0 100644 --- a/Box42/WebView/WebViewModel.swift +++ b/Box42/WebView/WebViewModel.swift @@ -5,15 +5,70 @@ // Created by Chan on 2023/03/19. // +import Combine import WebKit -// Singleton -class WebViewList { - static let shared = WebViewList() +typealias URLMapping = [String: URL] + +// WebView κ΄€λ ¨ CRUD 4κ°€μ§€ ν˜•νƒœμ˜ 데이터 가곡 create, read, update, delete +class WebViewModel: ObservableObject { + @Published var webViewURL: URLModels + @Published var URLdict: URLMapping + private var cancellables = Set() + + init() { + self.webViewURL = URLModels(info: [URLModel(name: Constants.url.InitialName, url: Constants.url.InitialPage)]) + self.URLdict = URLMapping() + + $webViewURL.sink { (WVURL) in + self.setUpURLdict() + }.store(in: &cancellables) + } + + func setUpURLdict() { + for urlModel in webViewURL.URLstring { + URLdict[urlModel.name] = URL(string: urlModel.url) + } + } - var list: [String : WKWebView]! + // Create + func createURL(_ name: String, _ url: String) { + let newURL = URLModel(name: name, url: url) + self.webViewURL.info.append(newURL) + } - private init() { - list = [:] + // Read + func readURLString(_ index: Int) -> URLModel { + return webViewURL.info[index] } + + func readURL(_ index: Int) -> URL { + return URL(string: webViewURL.info[index].url) ?? URL(string: Constants.url.InitialPage)! + } + + func safeURL() -> URL { + return URL(string: webViewURL.info.first?.url ?? Constants.url.InitialPage)! + } + + func requestURL(_ url: URL) -> URLRequest { + return URLRequest(url: url) + } + + // Update + func updateURL(_ id: UUID, _ name: String, _ url: String) { + if let selectedIndex = webViewURL.info.firstIndex(where: { user in user.id == id }) { + webViewURL.info[selectedIndex].name = name + webViewURL.info[selectedIndex].url = url + } + } + + // Delete + func deleteURL(id: UUID) { + if let selectedIndex = webViewURL.info.firstIndex(where: { user in user.id == id }) { + cancellables.removeAll() + webViewURL.info.remove(at: selectedIndex) + } + } + } + diff --git a/Box42/Window/BoxWindowController.swift b/Box42/Window/BoxWindowController.swift new file mode 100644 index 0000000..dc69045 --- /dev/null +++ b/Box42/Window/BoxWindowController.swift @@ -0,0 +1,138 @@ +// +// BoxWindowController.swift +// Box42 +// +// Created by Chanhee Kim on 8/11/23. +// + +import Cocoa + +class BoxWindowController: NSWindowController, NSToolbarDelegate, NSWindowDelegate { + + override init(window: NSWindow?) { + let contentRect = BoxSizeManager.shared.boxViewSizeNSRect + let styleMask: NSWindow.StyleMask = [.resizable, .closable, .miniaturizable, .fullSizeContentView, .titled] + + let windowInstance = NSWindow(contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false) + + windowInstance.titlebarAppearsTransparent = true + windowInstance.titleVisibility = .hidden + windowInstance.title = "Box" + windowInstance.isReleasedWhenClosed = false + windowInstance.isOpaque = false + windowInstance.backgroundColor = .clear + windowInstance.isMovableByWindowBackground = true + + let boxViewController = BoxViewController(nibName: nil, bundle: nil) + windowInstance.contentViewController = boxViewController + + super.init(window: windowInstance) + + windowInstance.delegate = self + + setupToolbar() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +extension BoxWindowController { + func windowShouldClose(_ sender: NSWindow) -> Bool { +// NSApplication.shared.terminate(self) + StateManager.shared.setToggleIsShowWindow() + return true + } +} + +// MARK: - Toolbar +extension BoxWindowController { + func setupToolbar() { + let toolbar = NSToolbar(identifier: "MainToolbar") + toolbar.delegate = self + toolbar.displayMode = .iconOnly + toolbar.sizeMode = .small + self.window?.toolbar = toolbar + } + + func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { + return [.group] + } + + func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { + return [.group, .flexibleSpace, .sidebar, .flexibleSpace, .goBack, .flexibleSpace, .goFoward, .flexibleSpace, .reloadPage, .flexibleSpace, .goToHome] + } + + func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? { + switch itemIdentifier { + case .group: + let groupItem = NSToolbarItemGroup(itemIdentifier: .group) + + let sidebarItem = NSToolbarItem(itemIdentifier: .sidebar) + sidebarItem.label = "Sidebar" + sidebarItem.image = NSImage(named: NSImage.Name("sidebar.leading")) + sidebarItem.action = #selector(toggleSidebar) + sidebarItem.minSize = NSSize(width: 40, height: 40) + sidebarItem.maxSize = NSSize(width: 40, height: 40) + + let goBack = NSToolbarItem(itemIdentifier: .goBack) + goBack.label = "left" + goBack.image = NSImage(named: NSImage.Name("arrow.left")) // 이미지 μ„€μ • + goBack.action = #selector(goBackAction) // ν•΄λ‹Ή action μ„€μ • + + let goFoward = NSToolbarItem(itemIdentifier: .goFoward) + goFoward.label = "right" + goFoward.image = NSImage(named: NSImage.Name("arrow.right")) + goFoward.action = #selector(goFowardAction) + + let reloadPage = NSToolbarItem(itemIdentifier: .reloadPage) + reloadPage.label = "clockwise" + reloadPage.image = NSImage(named: NSImage.Name("arrow.clockwise")) + reloadPage.action = #selector(reloadPageAction) + + let goToHome = NSToolbarItem(itemIdentifier: .goToHome) + goToHome.label = "skating" + goToHome.image = NSImage(named: NSImage.Name("figure.skating")) + goToHome.action = #selector(goToHomeAction) + + groupItem.subitems = [sidebarItem, goBack, goFoward, reloadPage, goToHome] + + return groupItem + + default: + return nil + } + } + + @objc func toggleSidebar() { + print("sidebar") + } + + @objc func goBackAction() { + WebViewManager.shared.hostingWebView?.goBack() + } + + @objc func goFowardAction() { + WebViewManager.shared.hostingWebView?.goForward() + } + + @objc func reloadPageAction() { + WebViewManager.shared.hostingWebView?.reload() + } + + @objc func goToHomeAction() { + if let item = WebViewManager.shared.hostingWebView?.backForwardList.backList.first { + WebViewManager.shared.hostingWebView?.go(to: item) + } + } +} + +extension NSToolbarItem.Identifier { + static let sidebar = NSToolbarItem.Identifier(rawValue: "SidebarButton") + static let goBack = NSToolbarItem.Identifier(rawValue: "goBackButton") + static let goFoward = NSToolbarItem.Identifier(rawValue: "goFowardButton") + static let reloadPage = NSToolbarItem.Identifier(rawValue: "reloadPageButton") + static let goToHome = NSToolbarItem.Identifier(rawValue: "goToHomeButton") + static let group = NSToolbarItem.Identifier(rawValue: "ItemGroup") +} diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..32e0316 --- /dev/null +++ b/Package.swift @@ -0,0 +1,28 @@ +// swift-tools-version:5.3 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "Box42", + platforms: [ + .macOS(.v10_15), + ], + products: [ + .library( + name: "Box42", + targets: ["Box42"]), + ], + dependencies: [ + .package(url: "https://github.com/SnapKit/SnapKit", from: "5.6.0"), + ], + targets: [ + .target( + name: "Box42", + dependencies: ["SnapKit"], + resources: [.process("Box42/Resources/Assets.xcassets"), + .process("Box42/Resources/Main.storyboard"), + .process("Box42/Resources/sh/*.sh")] + ), + ] +) diff --git a/Project.swift b/Project.swift new file mode 100644 index 0000000..0c1c3d1 --- /dev/null +++ b/Project.swift @@ -0,0 +1,43 @@ +// +// Project.swift +// Config +// +// Created by Chan on 2023/08/16. +// + +import ProjectDescription + +// MARK: Constants +let projectName = "Box42" +let organizationName = "Box42" +let bundleID = "com.box42" +let targetVersion = "10.15" +let dependencies: [TargetDependency] = [ + .external(name: "SnapKit"), +] +// MARK: Struct +let project = Project( + name: projectName, + organizationName: organizationName, + packages: [], + settings: nil, + targets: [ + Target(name: projectName, + platform: .macOS, + product: .app, + bundleId: bundleID, + deploymentTarget: .macOS(targetVersion: targetVersion), + infoPlist: .file(path: "\(projectName)/Resources/Info.plist"), + sources: ["\(projectName)/**"], + resources: ["\(projectName)/Resources/Assets.xcassets", + "\(projectName)/Resources/Main.storyboard", + "\(projectName)/Resources/sh/*.sh",], + entitlements: "\(projectName)/Resources/Box42.entitlements", + dependencies: dependencies + ) + ], + schemes: [], + fileHeaderTemplate: nil, + additionalFiles: [], + resourceSynthesizers: [] +) diff --git a/README.md b/README.md index 5a8d29c..597f6e1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # macOS -[![Hits](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2F42Box%2FmacOS%2Freleases&count_bg=%23E7D166&title_bg=%23EB7F40&icon=dropbox.svg&icon_color=%23E7E7E7&title=Download+Count&edge_flat=false)](https://hits.seeyoufarm.com) +[![Hits](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2F42Box%2FmacOS%2Freleases&count_bg=%23E7D166&title_bg=%23EB7F40&icon=dropbox.svg&icon_color=%23E7E7E7&title=μ°Ύμ•„μ™€μ£Όμ…”μ„œ+κ°μ‚¬ν•©λ‹ˆλ‹€!&edge_flat=false)](https://hits.seeyoufarm.com) [v1.0.1 Beta Release Note](https://github.com/42Box/macOS/releases/tag/v1.0.1) diff --git a/Tuist/Dependencies.swift b/Tuist/Dependencies.swift new file mode 100644 index 0000000..a131a1f --- /dev/null +++ b/Tuist/Dependencies.swift @@ -0,0 +1,17 @@ +// +// Dependencies.swift +// Config +// +// Created by Chan on 2023/08/16. +// + +import ProjectDescription + +let spm = SwiftPackageManagerDependencies([ + .remote(url: "https://github.com/SnapKit/SnapKit", requirement: .exact("5.6.0")), +]) + +let dependencies = Dependencies( + swiftPackageManager: spm, + platforms: [.macOS] +)