diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 564549e..f426e86 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,49 +1,43 @@ name: Mars on: -# push: -# tags: -# - '*' - workflow_dispatch: + push: + tags: + - '*' env: - APP_NAME: CalendarX SPARKLE_KEY: ${{ secrets.SPARKLE_KEY }} - BODY_PATH: BODY_PATH.md + PERSONAL_TOKEN: ${{ secrets.PERSONAL_TOKEN }} jobs: Release: - runs-on: macos-latest + runs-on: macos-13 steps: - name: Checkout - uses: actions/checkout@v3.3.0 + uses: actions/checkout@v4.1.1 - name: Setup - uses: actions/setup-node@v3.6.0 - - - run: | - echo "APP_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV - - - name: Package - run: | - fastlane package + uses: actions/setup-node@v4.0.0 + + - name: Setup Xcode + uses: maxim-lobanov/setup-xcode@v1.6.0 - - name: Create + - name: Create DMG run: | - sh scripts/create_dmg.sh + fastlane create_dmg - name: Release uses: softprops/action-gh-release@v1 if: startsWith(github.ref, 'refs/tags/') with: - body_path: ${{ env.BODY_PATH }} - files: ${{ env.APP_NAME }}.dmg - + body_path: ${{ env.LOG_PATH }} + files: ${{ env.APP_PATH }} + - name: Appcast - uses: actions/github-script@v6 + uses: actions/github-script@v7.0.1 if: startsWith(github.ref, 'refs/tags/') with: github-token: ${{ secrets.PERSONAL_TOKEN }} @@ -51,4 +45,4 @@ jobs: github.rest.repos.requestPagesBuild({ owner: context.repo.owner, repo: context.repo.repo, - }) + }) \ No newline at end of file diff --git a/.gitignore b/.gitignore index 44c8ff5..ec930a1 100644 --- a/.gitignore +++ b/.gitignore @@ -45,39 +45,22 @@ 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 +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 @@ -85,8 +68,6 @@ 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/ diff --git a/CalendarX.xcodeproj/project.pbxproj b/CalendarX.xcodeproj/project.pbxproj index 6c44a2b..de00f68 100644 --- a/CalendarX.xcodeproj/project.pbxproj +++ b/CalendarX.xcodeproj/project.pbxproj @@ -3,83 +3,82 @@ archiveVersion = 1; classes = { }; - objectVersion = 55; + objectVersion = 60; objects = { /* Begin PBXBuildFile section */ - 9808C701297889FE0062B3B9 /* MenubarItemController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9808C700297889FE0062B3B9 /* MenubarItemController.swift */; }; - 980E46D629B489D500036309 /* AlertAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 980E46D529B489D500036309 /* AlertAction.swift */; }; - 980E46D829B48A0C00036309 /* AlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 980E46D729B48A0C00036309 /* AlertView.swift */; }; - 98139ECD299D98BC000EEF46 /* Schedule in Frameworks */ = {isa = PBXBuildFile; productRef = 98139ECC299D98BC000EEF46 /* Schedule */; }; - 98139ECF299EC229000EEF46 /* SegmentedPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98139ECE299EC229000EEF46 /* SegmentedPicker.swift */; }; - 98139ED1299EF504000EEF46 /* MenubarStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98139ED0299EF504000EEF46 /* MenubarStyle.swift */; }; - 98139ED3299EFFD0000EEF46 /* SettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98139ED2299EFFD0000EEF46 /* SettingsViewModel.swift */; }; - 98139ED5299F33D4000EEF46 /* AppearanceSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98139ED4299F33D4000EEF46 /* AppearanceSettingsView.swift */; }; - 9829B63C299980BC00C8AB8A /* MenubarPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9829B63B299980BC00C8AB8A /* MenubarPreference.swift */; }; - 9829B63E2999864E00C8AB8A /* MenubarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9829B63D2999864E00C8AB8A /* MenubarViewModel.swift */; }; - 9829F17227F2E2D90085F98E /* LaunchAtLogin in Frameworks */ = {isa = PBXBuildFile; productRef = 9829F17127F2E2D90085F98E /* LaunchAtLogin */; }; - 982DABC027C32FC9002891A3 /* weekSF.json in Resources */ = {isa = PBXBuildFile; fileRef = 982DABBF27C32FC9002891A3 /* weekSF.json */; }; - 982DABC227C330EC002891A3 /* weekAF.json in Resources */ = {isa = PBXBuildFile; fileRef = 982DABC127C330EC002891A3 /* weekAF.json */; }; - 982DABC427C332E1002891A3 /* Date+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 982DABC327C332E1002891A3 /* Date+.swift */; }; - 982DABC627C33343002891A3 /* Bundle+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 982DABC527C33343002891A3 /* Bundle+.swift */; }; - 982DABC927C37977002891A3 /* WrappingHStack in Frameworks */ = {isa = PBXBuildFile; productRef = 982DABC827C37977002891A3 /* WrappingHStack */; }; - 982DABCC27C60713002891A3 /* EventHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 982DABCB27C60713002891A3 /* EventHelper.swift */; }; - 984E5E5329AA9417009EBB24 /* CalendarSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 984E5E5229AA9417009EBB24 /* CalendarSettingsView.swift */; }; - 984E5E5529AF6BF0009EBB24 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 984E5E5429AF6BF0009EBB24 /* AboutView.swift */; }; - 984E5E5A29B0969D009EBB24 /* CalendarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 984E5E5929B0969D009EBB24 /* CalendarViewModel.swift */; }; - 984E5E5C29B096DE009EBB24 /* CalendarPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 984E5E5B29B096DE009EBB24 /* CalendarPreference.swift */; }; - 987E85C527BFD3E1003CC110 /* weekPF.json in Resources */ = {isa = PBXBuildFile; fileRef = 987E85C427BFD3E1003CC110 /* weekPF.json */; }; - 9885302428168D4800FD98BC /* Color+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9885302328168D4800FD98BC /* Color+.swift */; }; - 988A82CE279F8B1A000899B5 /* AppKit+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 988A82CD279F8B1A000899B5 /* AppKit+.swift */; }; - 988A82D6279FEC4E000899B5 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 988A82D8279FEC4E000899B5 /* Localizable.strings */; }; - 988A82DE279FEC9D000899B5 /* Language.swift in Sources */ = {isa = PBXBuildFile; fileRef = 988A82DA279FEC9D000899B5 /* Language.swift */; }; - 988A82E0279FEC9D000899B5 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 988A82DC279FEC9D000899B5 /* Theme.swift */; }; - 988A82E1279FEC9D000899B5 /* AppInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 988A82DD279FEC9D000899B5 /* AppInfo.swift */; }; - 988A82E3279FFB8A000899B5 /* Preference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 988A82E2279FFB8A000899B5 /* Preference.swift */; }; - 98AB002329A565E8006C6FC7 /* LaunchHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98AB002229A565E8006C6FC7 /* LaunchHelper.swift */; }; - 98AB002529A5670D006C6FC7 /* Updater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98AB002429A5670D006C6FC7 /* Updater.swift */; }; - 98B5B6C929427A8A00114483 /* TitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98B5B6C829427A8A00114483 /* TitleView.swift */; }; - 98B5B6CB294289F900114483 /* RecommendationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98B5B6CA294289F900114483 /* RecommendationsView.swift */; }; - 98B5B6CD2942A6D800114483 /* apps.json in Resources */ = {isa = PBXBuildFile; fileRef = 98B5B6CC2942A6D800114483 /* apps.json */; }; - 98BC335629A022DF00FC8400 /* RowTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BC335529A022DF00FC8400 /* RowTitleView.swift */; }; - 98BE991427A0E08500306061 /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 98BE991327A0E08500306061 /* Sparkle */; }; - 98BE991627A0F6AB00306061 /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BE991527A0F6AB00306061 /* RootView.swift */; }; - 98BE991827A0F75900306061 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BE991727A0F75900306061 /* MainView.swift */; }; - 98BE991C27A1397500306061 /* Calendar+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BE991B27A1397500306061 /* Calendar+.swift */; }; - 98BE991E27A1415F00306061 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BE991D27A1415F00306061 /* SettingsView.swift */; }; - 98C9BD0A290999F600F645AD /* MenubarSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98C9BD09290999F600F645AD /* MenubarSettingsView.swift */; }; - 98CE8BDB27BBAA93009E5674 /* tiaoxiu.json in Resources */ = {isa = PBXBuildFile; fileRef = 98CE8BDA27BBAA93009E5674 /* tiaoxiu.json */; }; - 98CE8BE027BDEF1D009E5674 /* chuxi.json in Resources */ = {isa = PBXBuildFile; fileRef = 98CE8BDF27BDEF1D009E5674 /* chuxi.json */; }; - 98CE8BE427BDFA12009E5674 /* terms.json in Resources */ = {isa = PBXBuildFile; fileRef = 98CE8BE327BDFA12009E5674 /* terms.json */; }; - 98CE8BE827BF43EB009E5674 /* solarPF.json in Resources */ = {isa = PBXBuildFile; fileRef = 98CE8BE727BF43EB009E5674 /* solarPF.json */; }; - 98CE8BEC27BF44A3009E5674 /* lunarPF.json in Resources */ = {isa = PBXBuildFile; fileRef = 98CE8BEB27BF44A3009E5674 /* lunarPF.json */; }; - 98CE8BEE27BF5105009E5674 /* solarAF.json in Resources */ = {isa = PBXBuildFile; fileRef = 98CE8BED27BF5105009E5674 /* solarAF.json */; }; - 98CED54B27F3057100E0F758 /* RotationArrow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98CED54A27F3057100E0F758 /* RotationArrow.swift */; }; - 98CED54E27F43CF100E0F758 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 98CED55027F43CF100E0F758 /* InfoPlist.strings */; }; - 98CED55327F4423A00E0F758 /* L10n.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98CED55227F4423A00E0F758 /* L10n.swift */; }; - 98D2479427842E5A00F2B278 /* MenubarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D2479327842E5A00F2B278 /* MenubarController.swift */; }; - 98D247962784324700F2B278 /* MenubarPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D247952784324700F2B278 /* MenubarPopover.swift */; }; - 98D2479827844D8F00F2B278 /* Constant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D2479727844D8F00F2B278 /* Constant.swift */; }; - 98D573D627571EB6001C2D8C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 98D573D527571EB6001C2D8C /* Assets.xcassets */; }; - 98D573D927571EB6001C2D8C /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 98D573D827571EB6001C2D8C /* Preview Assets.xcassets */; }; - 98ED365527A288E500AF578A /* DateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98ED365427A288E500AF578A /* DateView.swift */; }; - 98ED365727A289EC00AF578A /* View+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98ED365627A289EC00AF578A /* View+.swift */; }; - 98ED365927A354CC00AF578A /* ScacleButtonPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98ED365827A354CC00AF578A /* ScacleButtonPicker.swift */; }; - 98ED367427BB468700AF578A /* CalDay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98ED367327BB468700AF578A /* CalDay.swift */; }; - 98F4347427A23ABE009F18CC /* MainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98F4347327A23ABE009F18CC /* MainViewModel.swift */; }; - 98F4347727A24297009F18CC /* ScacleButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98F4347627A24297009F18CC /* ScacleButton.swift */; }; - 98F4347927A24AFC009F18CC /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98F4347827A24AFC009F18CC /* Router.swift */; }; - 98FEAB9D27F6D6B10034EC1F /* MonitorHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98FEAB9C27F6D6B10034EC1F /* MonitorHelper.swift */; }; - 98FEABB427F8298C0034EC1F /* CalendarXApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98FEABB327F8298C0034EC1F /* CalendarXApp.swift */; }; + 9816601A2B30D7440046558A /* CalendarXWidget.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 9816601D2B30D7440046558A /* CalendarXWidget.intentdefinition */; }; + 9816601B2B30D7440046558A /* CalendarXWidget.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 9816601D2B30D7440046558A /* CalendarXWidget.intentdefinition */; }; + 981660242B30DA2B0046558A /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 981660262B30DA2B0046558A /* Localizable.strings */; }; + 98712FA92B2BB160005163D4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 98712FA82B2BB160005163D4 /* Assets.xcassets */; }; + 98712FAC2B2BB160005163D4 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 98712FAB2B2BB160005163D4 /* Preview Assets.xcassets */; }; + 98712FD22B2BB29B005163D4 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98712FB92B2BB1B7005163D4 /* WidgetKit.framework */; }; + 98712FD32B2BB29B005163D4 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98712FBB2B2BB1B7005163D4 /* SwiftUI.framework */; }; + 98712FD62B2BB29B005163D4 /* CalendarXWidgetBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98712FD52B2BB29B005163D4 /* CalendarXWidgetBundle.swift */; }; + 98712FDA2B2BB29C005163D4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 98712FD92B2BB29C005163D4 /* Assets.xcassets */; }; + 98712FDF2B2BB29C005163D4 /* CalendarXWidget.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 98712FD12B2BB29B005163D4 /* CalendarXWidget.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 98712FE72B2BB3A6005163D4 /* LargeWidgetProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98712FE62B2BB3A6005163D4 /* LargeWidgetProvider.swift */; }; + 98712FE92B2BB3BC005163D4 /* LargeWidgetEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98712FE82B2BB3BC005163D4 /* LargeWidgetEntry.swift */; }; + 9886FCA82B2BC52700AE22DC /* CalendarXShared in Frameworks */ = {isa = PBXBuildFile; productRef = 9886FCA72B2BC52700AE22DC /* CalendarXShared */; }; + 9886FCAA2B2BC53000AE22DC /* CalendarXShared in Frameworks */ = {isa = PBXBuildFile; productRef = 9886FCA92B2BC53000AE22DC /* CalendarXShared */; }; + 9886FCAC2B2BC54400AE22DC /* LargeWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCAB2B2BC54400AE22DC /* LargeWidgetView.swift */; }; + 9886FCAF2B2CE15600AE22DC /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 9886FCAE2B2CE15600AE22DC /* Sparkle */; }; + 9886FCB22B2CE19C00AE22DC /* WrappingHStack in Frameworks */ = {isa = PBXBuildFile; productRef = 9886FCB12B2CE19C00AE22DC /* WrappingHStack */; }; + 9886FCB52B2CE1B900AE22DC /* Schedule in Frameworks */ = {isa = PBXBuildFile; productRef = 9886FCB42B2CE1B900AE22DC /* Schedule */; }; + 9886FCB82B2CE1F700AE22DC /* LaunchAtLogin in Frameworks */ = {isa = PBXBuildFile; productRef = 9886FCB72B2CE1F700AE22DC /* LaunchAtLogin */; }; + 9886FCBD2B2CE3AC00AE22DC /* MonitorHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCBA2B2CE3AC00AE22DC /* MonitorHelper.swift */; }; + 9886FCBE2B2CE3AC00AE22DC /* Updater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCBB2B2CE3AC00AE22DC /* Updater.swift */; }; + 9886FCBF2B2CE3AC00AE22DC /* LaunchHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCBC2B2CE3AC00AE22DC /* LaunchHelper.swift */; }; + 9886FCC62B2CE69A00AE22DC /* TitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCC12B2CE69A00AE22DC /* TitleView.swift */; }; + 9886FCC72B2CE69A00AE22DC /* ScacleButtonPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCC22B2CE69A00AE22DC /* ScacleButtonPicker.swift */; }; + 9886FCC82B2CE69A00AE22DC /* ScacleButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCC32B2CE69A00AE22DC /* ScacleButton.swift */; }; + 9886FCC92B2CE69A00AE22DC /* RowTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCC42B2CE69A00AE22DC /* RowTitleView.swift */; }; + 9886FCCA2B2CE69A00AE22DC /* RotationArrow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCC52B2CE69A00AE22DC /* RotationArrow.swift */; }; + 9886FCCF2B2CE69E00AE22DC /* CalendarPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCCC2B2CE69E00AE22DC /* CalendarPreference.swift */; }; + 9886FCD02B2CE69E00AE22DC /* MenubarStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCCD2B2CE69E00AE22DC /* MenubarStyle.swift */; }; + 9886FCD12B2CE69E00AE22DC /* MenubarPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCCE2B2CE69E00AE22DC /* MenubarPreference.swift */; }; + 9886FCE32B2CE6A400AE22DC /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCD42B2CE6A400AE22DC /* AboutView.swift */; }; + 9886FCE42B2CE6A400AE22DC /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCD52B2CE6A400AE22DC /* SettingsView.swift */; }; + 9886FCE52B2CE6A400AE22DC /* RecommendationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCD62B2CE6A400AE22DC /* RecommendationsView.swift */; }; + 9886FCE62B2CE6A400AE22DC /* MenubarSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCD72B2CE6A400AE22DC /* MenubarSettingsView.swift */; }; + 9886FCE72B2CE6A400AE22DC /* AppearanceSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCD82B2CE6A400AE22DC /* AppearanceSettingsView.swift */; }; + 9886FCE82B2CE6A400AE22DC /* CalendarSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCD92B2CE6A400AE22DC /* CalendarSettingsView.swift */; }; + 9886FCE92B2CE6A400AE22DC /* MenubarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCDB2B2CE6A400AE22DC /* MenubarController.swift */; }; + 9886FCEA2B2CE6A400AE22DC /* MenubarPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCDC2B2CE6A400AE22DC /* MenubarPopover.swift */; }; + 9886FCEB2B2CE6A400AE22DC /* MenubarItemController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCDD2B2CE6A400AE22DC /* MenubarItemController.swift */; }; + 9886FCEC2B2CE6A400AE22DC /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCDF2B2CE6A400AE22DC /* RootView.swift */; }; + 9886FCED2B2CE6A400AE22DC /* DateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCE02B2CE6A400AE22DC /* DateView.swift */; }; + 9886FCEE2B2CE6A400AE22DC /* AlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCE12B2CE6A400AE22DC /* AlertView.swift */; }; + 9886FCEF2B2CE6A400AE22DC /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCE22B2CE6A400AE22DC /* MainView.swift */; }; + 9886FCF72B2CE6AA00AE22DC /* AlertAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCF12B2CE6AA00AE22DC /* AlertAction.swift */; }; + 9886FCF82B2CE6AA00AE22DC /* SettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCF22B2CE6AA00AE22DC /* SettingsViewModel.swift */; }; + 9886FCF92B2CE6AA00AE22DC /* MenubarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCF32B2CE6AA00AE22DC /* MenubarViewModel.swift */; }; + 9886FCFA2B2CE6AA00AE22DC /* MainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCF42B2CE6AA00AE22DC /* MainViewModel.swift */; }; + 9886FCFB2B2CE6AA00AE22DC /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCF52B2CE6AA00AE22DC /* Router.swift */; }; + 9886FCFC2B2CE6AA00AE22DC /* CalendarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FCF62B2CE6AA00AE22DC /* CalendarViewModel.swift */; }; + 9886FD022B2D0E8D00AE22DC /* CalendarXApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9886FD012B2D0E8D00AE22DC /* CalendarXApp.swift */; }; + 98FFFC462B2D188F0047B692 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 98FFFC482B2D188F0047B692 /* Localizable.strings */; }; + 98FFFC492B2D18930047B692 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 98FFFC4B2B2D18930047B692 /* InfoPlist.strings */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 98712FDD2B2BB29C005163D4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 98712F992B2BB15E005163D4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 98712FD02B2BB29B005163D4; + remoteInfo = CalendarXWidgetExtension; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ - 98CA788C2996EE8C00E41D3B /* Embed Foundation Extensions */ = { + 98712FCC2B2BB1B9005163D4 /* Embed Foundation Extensions */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 13; files = ( + 98712FDF2B2BB29C005163D4 /* CalendarXWidget.appex in Embed Foundation Extensions */, ); name = "Embed Foundation Extensions"; runOnlyForDeploymentPostprocessing = 0; @@ -87,306 +86,329 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 9808C700297889FE0062B3B9 /* MenubarItemController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenubarItemController.swift; sourceTree = ""; }; - 980E46D529B489D500036309 /* AlertAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertAction.swift; sourceTree = ""; }; - 980E46D729B48A0C00036309 /* AlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertView.swift; sourceTree = ""; }; - 98139ECE299EC229000EEF46 /* SegmentedPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegmentedPicker.swift; sourceTree = ""; }; - 98139ED0299EF504000EEF46 /* MenubarStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenubarStyle.swift; sourceTree = ""; }; - 98139ED2299EFFD0000EEF46 /* SettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewModel.swift; sourceTree = ""; }; - 98139ED4299F33D4000EEF46 /* AppearanceSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceSettingsView.swift; sourceTree = ""; }; - 9829B63B299980BC00C8AB8A /* MenubarPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenubarPreference.swift; sourceTree = ""; }; - 9829B63D2999864E00C8AB8A /* MenubarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenubarViewModel.swift; sourceTree = ""; }; - 982DABBF27C32FC9002891A3 /* weekSF.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = weekSF.json; sourceTree = ""; }; - 982DABC127C330EC002891A3 /* weekAF.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = weekAF.json; sourceTree = ""; }; - 982DABC327C332E1002891A3 /* Date+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+.swift"; sourceTree = ""; }; - 982DABC527C33343002891A3 /* Bundle+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+.swift"; sourceTree = ""; }; - 982DABCB27C60713002891A3 /* EventHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventHelper.swift; sourceTree = ""; }; - 984E5E5229AA9417009EBB24 /* CalendarSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarSettingsView.swift; sourceTree = ""; }; - 984E5E5429AF6BF0009EBB24 /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = ""; }; - 984E5E5929B0969D009EBB24 /* CalendarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarViewModel.swift; sourceTree = ""; }; - 984E5E5B29B096DE009EBB24 /* CalendarPreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarPreference.swift; sourceTree = ""; }; - 987E85C427BFD3E1003CC110 /* weekPF.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = weekPF.json; sourceTree = ""; }; - 9885302328168D4800FD98BC /* Color+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+.swift"; sourceTree = ""; }; - 988A82CD279F8B1A000899B5 /* AppKit+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppKit+.swift"; sourceTree = ""; }; - 988A82D7279FEC4E000899B5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; - 988A82D9279FEC4F000899B5 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; - 988A82DA279FEC9D000899B5 /* Language.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Language.swift; sourceTree = ""; }; - 988A82DC279FEC9D000899B5 /* Theme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = ""; }; - 988A82DD279FEC9D000899B5 /* AppInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppInfo.swift; sourceTree = ""; }; - 988A82E2279FFB8A000899B5 /* Preference.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Preference.swift; sourceTree = ""; }; - 98AB002229A565E8006C6FC7 /* LaunchHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchHelper.swift; sourceTree = ""; }; - 98AB002429A5670D006C6FC7 /* Updater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Updater.swift; sourceTree = ""; }; - 98B5B6C829427A8A00114483 /* TitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleView.swift; sourceTree = ""; }; - 98B5B6CA294289F900114483 /* RecommendationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendationsView.swift; sourceTree = ""; }; - 98B5B6CC2942A6D800114483 /* apps.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = apps.json; sourceTree = ""; }; - 98BC335529A022DF00FC8400 /* RowTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RowTitleView.swift; sourceTree = ""; }; - 98BE991527A0F6AB00306061 /* RootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootView.swift; sourceTree = ""; }; - 98BE991727A0F75900306061 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; - 98BE991B27A1397500306061 /* Calendar+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Calendar+.swift"; sourceTree = ""; }; - 98BE991D27A1415F00306061 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; - 98C9BD09290999F600F645AD /* MenubarSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenubarSettingsView.swift; sourceTree = ""; }; - 98CE8BDA27BBAA93009E5674 /* tiaoxiu.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = tiaoxiu.json; sourceTree = ""; }; - 98CE8BDF27BDEF1D009E5674 /* chuxi.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = chuxi.json; sourceTree = ""; }; - 98CE8BE327BDFA12009E5674 /* terms.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = terms.json; sourceTree = ""; }; - 98CE8BE727BF43EB009E5674 /* solarPF.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = solarPF.json; sourceTree = ""; }; - 98CE8BEB27BF44A3009E5674 /* lunarPF.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = lunarPF.json; sourceTree = ""; }; - 98CE8BED27BF5105009E5674 /* solarAF.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = solarAF.json; sourceTree = ""; }; - 98CED54A27F3057100E0F758 /* RotationArrow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RotationArrow.swift; sourceTree = ""; }; - 98CED54F27F43CF100E0F758 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - 98CED55127F43CF300E0F758 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = ""; }; - 98CED55227F4423A00E0F758 /* L10n.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = L10n.swift; sourceTree = ""; }; - 98D2479327842E5A00F2B278 /* MenubarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenubarController.swift; sourceTree = ""; }; - 98D247952784324700F2B278 /* MenubarPopover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenubarPopover.swift; sourceTree = ""; }; - 98D2479727844D8F00F2B278 /* Constant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constant.swift; sourceTree = ""; }; - 98D573CE27571EB3001C2D8C /* CalendarX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CalendarX.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 98D573D527571EB6001C2D8C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 98D573D827571EB6001C2D8C /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; - 98D573DA27571EB6001C2D8C /* CalendarX.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = CalendarX.entitlements; sourceTree = ""; }; - 98D573E327586A8F001C2D8C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; - 98ED365427A288E500AF578A /* DateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateView.swift; sourceTree = ""; }; - 98ED365627A289EC00AF578A /* View+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+.swift"; sourceTree = ""; }; - 98ED365827A354CC00AF578A /* ScacleButtonPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScacleButtonPicker.swift; sourceTree = ""; }; - 98ED367327BB468700AF578A /* CalDay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalDay.swift; sourceTree = ""; }; - 98F4347327A23ABE009F18CC /* MainViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewModel.swift; sourceTree = ""; }; - 98F4347627A24297009F18CC /* ScacleButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScacleButton.swift; sourceTree = ""; }; - 98F4347827A24AFC009F18CC /* Router.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = ""; }; - 98FEAB9C27F6D6B10034EC1F /* MonitorHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MonitorHelper.swift; sourceTree = ""; }; - 98FEABB327F8298C0034EC1F /* CalendarXApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CalendarXApp.swift; sourceTree = ""; }; + 9816601C2B30D7440046558A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; name = Base; path = Base.lproj/CalendarXWidget.intentdefinition; sourceTree = ""; }; + 9816601F2B30D7470046558A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/CalendarXWidget.strings; sourceTree = ""; }; + 981660212B30D7480046558A /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/CalendarXWidget.strings"; sourceTree = ""; }; + 981660252B30DA2B0046558A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; + 981660272B30DA2C0046558A /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; + 98712FA12B2BB15E005163D4 /* CalendarX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CalendarX.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 98712FA82B2BB160005163D4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 98712FAB2B2BB160005163D4 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 98712FAD2B2BB160005163D4 /* CalendarX.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = CalendarX.entitlements; sourceTree = ""; }; + 98712FB92B2BB1B7005163D4 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; + 98712FBB2B2BB1B7005163D4 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; + 98712FD12B2BB29B005163D4 /* CalendarXWidget.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = CalendarXWidget.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 98712FD52B2BB29B005163D4 /* CalendarXWidgetBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarXWidgetBundle.swift; sourceTree = ""; }; + 98712FD92B2BB29C005163D4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 98712FDB2B2BB29C005163D4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 98712FDC2B2BB29C005163D4 /* CalendarXWidget.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = CalendarXWidget.entitlements; sourceTree = ""; }; + 98712FE62B2BB3A6005163D4 /* LargeWidgetProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LargeWidgetProvider.swift; sourceTree = ""; }; + 98712FE82B2BB3BC005163D4 /* LargeWidgetEntry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LargeWidgetEntry.swift; sourceTree = ""; }; + 98712FEA2B2BB54C005163D4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 9886FCAB2B2BC54400AE22DC /* LargeWidgetView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LargeWidgetView.swift; sourceTree = ""; }; + 9886FCBA2B2CE3AC00AE22DC /* MonitorHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MonitorHelper.swift; sourceTree = ""; }; + 9886FCBB2B2CE3AC00AE22DC /* Updater.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Updater.swift; sourceTree = ""; }; + 9886FCBC2B2CE3AC00AE22DC /* LaunchHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LaunchHelper.swift; sourceTree = ""; }; + 9886FCC12B2CE69A00AE22DC /* TitleView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TitleView.swift; sourceTree = ""; }; + 9886FCC22B2CE69A00AE22DC /* ScacleButtonPicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScacleButtonPicker.swift; sourceTree = ""; }; + 9886FCC32B2CE69A00AE22DC /* ScacleButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScacleButton.swift; sourceTree = ""; }; + 9886FCC42B2CE69A00AE22DC /* RowTitleView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowTitleView.swift; sourceTree = ""; }; + 9886FCC52B2CE69A00AE22DC /* RotationArrow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RotationArrow.swift; sourceTree = ""; }; + 9886FCCC2B2CE69E00AE22DC /* CalendarPreference.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CalendarPreference.swift; sourceTree = ""; }; + 9886FCCD2B2CE69E00AE22DC /* MenubarStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenubarStyle.swift; sourceTree = ""; }; + 9886FCCE2B2CE69E00AE22DC /* MenubarPreference.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenubarPreference.swift; sourceTree = ""; }; + 9886FCD42B2CE6A400AE22DC /* AboutView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = ""; }; + 9886FCD52B2CE6A400AE22DC /* SettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; + 9886FCD62B2CE6A400AE22DC /* RecommendationsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecommendationsView.swift; sourceTree = ""; }; + 9886FCD72B2CE6A400AE22DC /* MenubarSettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenubarSettingsView.swift; sourceTree = ""; }; + 9886FCD82B2CE6A400AE22DC /* AppearanceSettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppearanceSettingsView.swift; sourceTree = ""; }; + 9886FCD92B2CE6A400AE22DC /* CalendarSettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CalendarSettingsView.swift; sourceTree = ""; }; + 9886FCDB2B2CE6A400AE22DC /* MenubarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenubarController.swift; sourceTree = ""; }; + 9886FCDC2B2CE6A400AE22DC /* MenubarPopover.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenubarPopover.swift; sourceTree = ""; }; + 9886FCDD2B2CE6A400AE22DC /* MenubarItemController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenubarItemController.swift; sourceTree = ""; }; + 9886FCDF2B2CE6A400AE22DC /* RootView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootView.swift; sourceTree = ""; }; + 9886FCE02B2CE6A400AE22DC /* DateView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateView.swift; sourceTree = ""; }; + 9886FCE12B2CE6A400AE22DC /* AlertView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertView.swift; sourceTree = ""; }; + 9886FCE22B2CE6A400AE22DC /* MainView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; + 9886FCF12B2CE6AA00AE22DC /* AlertAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertAction.swift; sourceTree = ""; }; + 9886FCF22B2CE6AA00AE22DC /* SettingsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewModel.swift; sourceTree = ""; }; + 9886FCF32B2CE6AA00AE22DC /* MenubarViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenubarViewModel.swift; sourceTree = ""; }; + 9886FCF42B2CE6AA00AE22DC /* MainViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainViewModel.swift; sourceTree = ""; }; + 9886FCF52B2CE6AA00AE22DC /* Router.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = ""; }; + 9886FCF62B2CE6AA00AE22DC /* CalendarViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CalendarViewModel.swift; sourceTree = ""; }; + 9886FD012B2D0E8D00AE22DC /* CalendarXApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CalendarXApp.swift; sourceTree = ""; }; + 98FFFC472B2D188F0047B692 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; + 98FFFC4A2B2D18930047B692 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 98FFFC4C2B2D18940047B692 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = ""; }; + 98FFFC4D2B2D18970047B692 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; + 98FFFC532B2F7D460047B692 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 98D573CB27571EB3001C2D8C /* Frameworks */ = { + 98712F9E2B2BB15E005163D4 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9829F17227F2E2D90085F98E /* LaunchAtLogin in Frameworks */, - 98139ECD299D98BC000EEF46 /* Schedule in Frameworks */, - 982DABC927C37977002891A3 /* WrappingHStack in Frameworks */, - 98BE991427A0E08500306061 /* Sparkle in Frameworks */, + 9886FCA82B2BC52700AE22DC /* CalendarXShared in Frameworks */, + 9886FCB52B2CE1B900AE22DC /* Schedule in Frameworks */, + 9886FCB22B2CE19C00AE22DC /* WrappingHStack in Frameworks */, + 9886FCB82B2CE1F700AE22DC /* LaunchAtLogin in Frameworks */, + 9886FCAF2B2CE15600AE22DC /* Sparkle in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 98712FCE2B2BB29B005163D4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9886FCAA2B2BC53000AE22DC /* CalendarXShared in Frameworks */, + 98712FD32B2BB29B005163D4 /* SwiftUI.framework in Frameworks */, + 98712FD22B2BB29B005163D4 /* WidgetKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 982DABCA27C5E33D002891A3 /* Service */ = { + 981660152B2FE9900046558A /* LargeWidget */ = { isa = PBXGroup; children = ( - 98CED55227F4423A00E0F758 /* L10n.swift */, - 98AB002429A5670D006C6FC7 /* Updater.swift */, - 982DABCB27C60713002891A3 /* EventHelper.swift */, - 98FEAB9C27F6D6B10034EC1F /* MonitorHelper.swift */, - 98AB002229A565E8006C6FC7 /* LaunchHelper.swift */, + 98712FE62B2BB3A6005163D4 /* LargeWidgetProvider.swift */, + 98712FE82B2BB3BC005163D4 /* LargeWidgetEntry.swift */, + 9886FCAB2B2BC54400AE22DC /* LargeWidgetView.swift */, ); - path = Service; + path = LargeWidget; sourceTree = ""; }; - 988A82CB279F8674000899B5 /* Calender */ = { + 98712F982B2BB15E005163D4 = { isa = PBXGroup; children = ( - 98BE991527A0F6AB00306061 /* RootView.swift */, - 98BE991727A0F75900306061 /* MainView.swift */, - 98ED365427A288E500AF578A /* DateView.swift */, - 980E46D729B48A0C00036309 /* AlertView.swift */, + 98712FA32B2BB15E005163D4 /* CalendarX */, + 98712FD42B2BB29B005163D4 /* CalendarXWidget */, + 98712FB82B2BB1B7005163D4 /* Frameworks */, + 98712FA22B2BB15E005163D4 /* Products */, ); - path = Calender; sourceTree = ""; }; - 988A82CC279F8B0B000899B5 /* Extension */ = { + 98712FA22B2BB15E005163D4 /* Products */ = { isa = PBXGroup; children = ( - 98ED365627A289EC00AF578A /* View+.swift */, - 988A82CD279F8B1A000899B5 /* AppKit+.swift */, - 98BE991B27A1397500306061 /* Calendar+.swift */, - 982DABC327C332E1002891A3 /* Date+.swift */, - 982DABC527C33343002891A3 /* Bundle+.swift */, - 9885302328168D4800FD98BC /* Color+.swift */, - ); - path = Extension; + 98712FA12B2BB15E005163D4 /* CalendarX.app */, + 98712FD12B2BB29B005163D4 /* CalendarXWidget.appex */, + ); + name = Products; sourceTree = ""; }; - 988A82D3279FEB72000899B5 /* Model */ = { + 98712FA32B2BB15E005163D4 /* CalendarX */ = { isa = PBXGroup; children = ( - 988A82DD279FEC9D000899B5 /* AppInfo.swift */, - 988A82DA279FEC9D000899B5 /* Language.swift */, - 988A82DC279FEC9D000899B5 /* Theme.swift */, - 98ED367327BB468700AF578A /* CalDay.swift */, - 988A82E2279FFB8A000899B5 /* Preference.swift */, - 9829B63B299980BC00C8AB8A /* MenubarPreference.swift */, - 98139ED0299EF504000EEF46 /* MenubarStyle.swift */, - 984E5E5B29B096DE009EBB24 /* CalendarPreference.swift */, + 9886FCF02B2CE6AA00AE22DC /* ViewModel */, + 9886FCD22B2CE6A400AE22DC /* Module */, + 9886FCCB2B2CE69E00AE22DC /* Model */, + 9886FCC02B2CE69A00AE22DC /* Component */, + 9886FCB92B2CE3AC00AE22DC /* Service */, + 98712FEA2B2BB54C005163D4 /* Info.plist */, + 98712FA82B2BB160005163D4 /* Assets.xcassets */, + 98712FAD2B2BB160005163D4 /* CalendarX.entitlements */, + 9886FD012B2D0E8D00AE22DC /* CalendarXApp.swift */, + 98FFFC4B2B2D18930047B692 /* InfoPlist.strings */, + 98FFFC482B2D188F0047B692 /* Localizable.strings */, + 98712FAA2B2BB160005163D4 /* Preview Content */, ); - path = Model; + path = CalendarX; sourceTree = ""; }; - 98C9BD0B29099A2C00F645AD /* Settings */ = { + 98712FAA2B2BB160005163D4 /* Preview Content */ = { isa = PBXGroup; children = ( - 98BE991D27A1415F00306061 /* SettingsView.swift */, - 98C9BD09290999F600F645AD /* MenubarSettingsView.swift */, - 98B5B6CA294289F900114483 /* RecommendationsView.swift */, - 98139ED4299F33D4000EEF46 /* AppearanceSettingsView.swift */, - 984E5E5229AA9417009EBB24 /* CalendarSettingsView.swift */, - 984E5E5429AF6BF0009EBB24 /* AboutView.swift */, + 98712FAB2B2BB160005163D4 /* Preview Assets.xcassets */, ); - path = Settings; + path = "Preview Content"; + sourceTree = ""; + }; + 98712FB82B2BB1B7005163D4 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 98712FB92B2BB1B7005163D4 /* WidgetKit.framework */, + 98712FBB2B2BB1B7005163D4 /* SwiftUI.framework */, + 98FFFC532B2F7D460047B692 /* Intents.framework */, + ); + name = Frameworks; sourceTree = ""; }; - 98CE8BDC27BBABF2009E5674 /* Resource */ = { + 98712FD42B2BB29B005163D4 /* CalendarXWidget */ = { isa = PBXGroup; children = ( - 98B5B6CC2942A6D800114483 /* apps.json */, - 98CE8BE327BDFA12009E5674 /* terms.json */, - 98CE8BDA27BBAA93009E5674 /* tiaoxiu.json */, - 98CE8BDF27BDEF1D009E5674 /* chuxi.json */, - 98CE8BE727BF43EB009E5674 /* solarPF.json */, - 98CE8BED27BF5105009E5674 /* solarAF.json */, - 98CE8BEB27BF44A3009E5674 /* lunarPF.json */, - 987E85C427BFD3E1003CC110 /* weekPF.json */, - 982DABBF27C32FC9002891A3 /* weekSF.json */, - 982DABC127C330EC002891A3 /* weekAF.json */, - ); - path = Resource; + 981660152B2FE9900046558A /* LargeWidget */, + 98712FD52B2BB29B005163D4 /* CalendarXWidgetBundle.swift */, + 98712FD92B2BB29C005163D4 /* Assets.xcassets */, + 98712FDB2B2BB29C005163D4 /* Info.plist */, + 98712FDC2B2BB29C005163D4 /* CalendarXWidget.entitlements */, + 9816601D2B30D7440046558A /* CalendarXWidget.intentdefinition */, + 981660262B30DA2B0046558A /* Localizable.strings */, + ); + path = CalendarXWidget; sourceTree = ""; }; - 98D2478C278414EC00F2B278 /* ViewModel */ = { + 9886FCB92B2CE3AC00AE22DC /* Service */ = { isa = PBXGroup; children = ( - 98F4347827A24AFC009F18CC /* Router.swift */, - 980E46D529B489D500036309 /* AlertAction.swift */, - 98F4347327A23ABE009F18CC /* MainViewModel.swift */, - 9829B63D2999864E00C8AB8A /* MenubarViewModel.swift */, - 98139ED2299EFFD0000EEF46 /* SettingsViewModel.swift */, - 984E5E5929B0969D009EBB24 /* CalendarViewModel.swift */, + 9886FCBA2B2CE3AC00AE22DC /* MonitorHelper.swift */, + 9886FCBB2B2CE3AC00AE22DC /* Updater.swift */, + 9886FCBC2B2CE3AC00AE22DC /* LaunchHelper.swift */, ); - path = ViewModel; + path = Service; sourceTree = ""; }; - 98D2479127842C8C00F2B278 /* Module */ = { + 9886FCC02B2CE69A00AE22DC /* Component */ = { isa = PBXGroup; children = ( - 988A82CB279F8674000899B5 /* Calender */, - 98C9BD0B29099A2C00F645AD /* Settings */, - 98D2479227842CC500F2B278 /* Menubar */, + 9886FCC12B2CE69A00AE22DC /* TitleView.swift */, + 9886FCC22B2CE69A00AE22DC /* ScacleButtonPicker.swift */, + 9886FCC32B2CE69A00AE22DC /* ScacleButton.swift */, + 9886FCC42B2CE69A00AE22DC /* RowTitleView.swift */, + 9886FCC52B2CE69A00AE22DC /* RotationArrow.swift */, ); - path = Module; + path = Component; sourceTree = ""; }; - 98D2479227842CC500F2B278 /* Menubar */ = { + 9886FCCB2B2CE69E00AE22DC /* Model */ = { isa = PBXGroup; children = ( - 9808C700297889FE0062B3B9 /* MenubarItemController.swift */, - 98D2479327842E5A00F2B278 /* MenubarController.swift */, - 98D247952784324700F2B278 /* MenubarPopover.swift */, + 9886FCCC2B2CE69E00AE22DC /* CalendarPreference.swift */, + 9886FCCD2B2CE69E00AE22DC /* MenubarStyle.swift */, + 9886FCCE2B2CE69E00AE22DC /* MenubarPreference.swift */, ); - path = Menubar; + path = Model; sourceTree = ""; }; - 98D573C527571EB3001C2D8C = { + 9886FCD22B2CE6A400AE22DC /* Module */ = { isa = PBXGroup; children = ( - 98D573D027571EB3001C2D8C /* CalendarX */, - 98D573CF27571EB3001C2D8C /* Products */, + 9886FCD32B2CE6A400AE22DC /* Settings */, + 9886FCDA2B2CE6A400AE22DC /* Menubar */, + 9886FCDE2B2CE6A400AE22DC /* Calender */, ); + path = Module; sourceTree = ""; }; - 98D573CF27571EB3001C2D8C /* Products */ = { + 9886FCD32B2CE6A400AE22DC /* Settings */ = { isa = PBXGroup; children = ( - 98D573CE27571EB3001C2D8C /* CalendarX.app */, + 9886FCD42B2CE6A400AE22DC /* AboutView.swift */, + 9886FCD52B2CE6A400AE22DC /* SettingsView.swift */, + 9886FCD62B2CE6A400AE22DC /* RecommendationsView.swift */, + 9886FCD72B2CE6A400AE22DC /* MenubarSettingsView.swift */, + 9886FCD82B2CE6A400AE22DC /* AppearanceSettingsView.swift */, + 9886FCD92B2CE6A400AE22DC /* CalendarSettingsView.swift */, ); - name = Products; + path = Settings; sourceTree = ""; }; - 98D573D027571EB3001C2D8C /* CalendarX */ = { + 9886FCDA2B2CE6A400AE22DC /* Menubar */ = { isa = PBXGroup; children = ( - 982DABCA27C5E33D002891A3 /* Service */, - 98CE8BDC27BBABF2009E5674 /* Resource */, - 98F4347527A2428E009F18CC /* Component */, - 988A82D3279FEB72000899B5 /* Model */, - 988A82CC279F8B0B000899B5 /* Extension */, - 98D2479127842C8C00F2B278 /* Module */, - 98D2478C278414EC00F2B278 /* ViewModel */, - 98D573E327586A8F001C2D8C /* Info.plist */, - 98FEABB327F8298C0034EC1F /* CalendarXApp.swift */, - 98D2479727844D8F00F2B278 /* Constant.swift */, - 98D573D527571EB6001C2D8C /* Assets.xcassets */, - 98D573DA27571EB6001C2D8C /* CalendarX.entitlements */, - 98D573D727571EB6001C2D8C /* Preview Content */, - 988A82D8279FEC4E000899B5 /* Localizable.strings */, - 98CED55027F43CF100E0F758 /* InfoPlist.strings */, + 9886FCDB2B2CE6A400AE22DC /* MenubarController.swift */, + 9886FCDC2B2CE6A400AE22DC /* MenubarPopover.swift */, + 9886FCDD2B2CE6A400AE22DC /* MenubarItemController.swift */, ); - path = CalendarX; + path = Menubar; sourceTree = ""; }; - 98D573D727571EB6001C2D8C /* Preview Content */ = { + 9886FCDE2B2CE6A400AE22DC /* Calender */ = { isa = PBXGroup; children = ( - 98D573D827571EB6001C2D8C /* Preview Assets.xcassets */, + 9886FCDF2B2CE6A400AE22DC /* RootView.swift */, + 9886FCE02B2CE6A400AE22DC /* DateView.swift */, + 9886FCE12B2CE6A400AE22DC /* AlertView.swift */, + 9886FCE22B2CE6A400AE22DC /* MainView.swift */, ); - path = "Preview Content"; + path = Calender; sourceTree = ""; }; - 98F4347527A2428E009F18CC /* Component */ = { + 9886FCF02B2CE6AA00AE22DC /* ViewModel */ = { isa = PBXGroup; children = ( - 98F4347627A24297009F18CC /* ScacleButton.swift */, - 98ED365827A354CC00AF578A /* ScacleButtonPicker.swift */, - 98CED54A27F3057100E0F758 /* RotationArrow.swift */, - 98B5B6C829427A8A00114483 /* TitleView.swift */, - 98139ECE299EC229000EEF46 /* SegmentedPicker.swift */, - 98BC335529A022DF00FC8400 /* RowTitleView.swift */, + 9886FCF12B2CE6AA00AE22DC /* AlertAction.swift */, + 9886FCF22B2CE6AA00AE22DC /* SettingsViewModel.swift */, + 9886FCF32B2CE6AA00AE22DC /* MenubarViewModel.swift */, + 9886FCF42B2CE6AA00AE22DC /* MainViewModel.swift */, + 9886FCF52B2CE6AA00AE22DC /* Router.swift */, + 9886FCF62B2CE6AA00AE22DC /* CalendarViewModel.swift */, ); - path = Component; + path = ViewModel; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 98D573CD27571EB3001C2D8C /* CalendarX */ = { + 98712FA02B2BB15E005163D4 /* CalendarX */ = { isa = PBXNativeTarget; - buildConfigurationList = 98D573DD27571EB6001C2D8C /* Build configuration list for PBXNativeTarget "CalendarX" */; + buildConfigurationList = 98712FB02B2BB160005163D4 /* Build configuration list for PBXNativeTarget "CalendarX" */; buildPhases = ( - 98D573CA27571EB3001C2D8C /* Sources */, - 98D573CB27571EB3001C2D8C /* Frameworks */, - 98D573CC27571EB3001C2D8C /* Resources */, - 9829F17327F2E46F0085F98E /* ShellScript */, - 98CA788C2996EE8C00E41D3B /* Embed Foundation Extensions */, + 98712F9D2B2BB15E005163D4 /* Sources */, + 98712F9E2B2BB15E005163D4 /* Frameworks */, + 98712F9F2B2BB15E005163D4 /* Resources */, + 98712FCC2B2BB1B9005163D4 /* Embed Foundation Extensions */, + 9886FD032B2D11DA00AE22DC /* ShellScript */, ); buildRules = ( ); dependencies = ( + 98712FDE2B2BB29C005163D4 /* PBXTargetDependency */, ); name = CalendarX; packageProductDependencies = ( - 98BE991327A0E08500306061 /* Sparkle */, - 982DABC827C37977002891A3 /* WrappingHStack */, - 9829F17127F2E2D90085F98E /* LaunchAtLogin */, - 98139ECC299D98BC000EEF46 /* Schedule */, + 9886FCA72B2BC52700AE22DC /* CalendarXShared */, + 9886FCAE2B2CE15600AE22DC /* Sparkle */, + 9886FCB12B2CE19C00AE22DC /* WrappingHStack */, + 9886FCB42B2CE1B900AE22DC /* Schedule */, + 9886FCB72B2CE1F700AE22DC /* LaunchAtLogin */, ); productName = CalendarX; - productReference = 98D573CE27571EB3001C2D8C /* CalendarX.app */; + productReference = 98712FA12B2BB15E005163D4 /* CalendarX.app */; productType = "com.apple.product-type.application"; }; + 98712FD02B2BB29B005163D4 /* CalendarXWidget */ = { + isa = PBXNativeTarget; + buildConfigurationList = 98712FE02B2BB29D005163D4 /* Build configuration list for PBXNativeTarget "CalendarXWidget" */; + buildPhases = ( + 98712FCD2B2BB29B005163D4 /* Sources */, + 98712FCE2B2BB29B005163D4 /* Frameworks */, + 98712FCF2B2BB29B005163D4 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = CalendarXWidget; + packageProductDependencies = ( + 9886FCA92B2BC53000AE22DC /* CalendarXShared */, + ); + productName = CalendarXWidgetExtension; + productReference = 98712FD12B2BB29B005163D4 /* CalendarXWidget.appex */; + productType = "com.apple.product-type.app-extension"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ - 98D573C627571EB3001C2D8C /* Project object */ = { + 98712F992B2BB15E005163D4 /* Project object */ = { isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 1420; - LastUpgradeCheck = 1400; + LastSwiftUpdateCheck = 1510; + LastUpgradeCheck = 1510; TargetAttributes = { - 98D573CD27571EB3001C2D8C = { - CreatedOnToolsVersion = 13.1; + 98712FA02B2BB15E005163D4 = { + CreatedOnToolsVersion = 15.1; + }; + 98712FD02B2BB29B005163D4 = { + CreatedOnToolsVersion = 15.1; }; }; }; - buildConfigurationList = 98D573C927571EB3001C2D8C /* Build configuration list for PBXProject "CalendarX" */; - compatibilityVersion = "Xcode 13.0"; + buildConfigurationList = 98712F9C2B2BB15E005163D4 /* Build configuration list for PBXProject "CalendarX" */; + compatibilityVersion = "Xcode 14.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -394,48 +416,49 @@ Base, "zh-Hans", ); - mainGroup = 98D573C527571EB3001C2D8C; + mainGroup = 98712F982B2BB15E005163D4; packageReferences = ( - 98BE991227A0E08500306061 /* XCRemoteSwiftPackageReference "Sparkle" */, - 982DABC727C37977002891A3 /* XCRemoteSwiftPackageReference "WrappingHStack" */, - 9829F17027F2E2D90085F98E /* XCRemoteSwiftPackageReference "LaunchAtLogin" */, - 98139ECB299D98BC000EEF46 /* XCRemoteSwiftPackageReference "Schedule" */, + 9886FCA62B2BC52700AE22DC /* XCLocalSwiftPackageReference "CalendarXShared" */, + 9886FCAD2B2CE15600AE22DC /* XCRemoteSwiftPackageReference "Sparkle" */, + 9886FCB02B2CE19C00AE22DC /* XCRemoteSwiftPackageReference "WrappingHStack" */, + 9886FCB32B2CE1B900AE22DC /* XCRemoteSwiftPackageReference "Schedule" */, + 9886FCB62B2CE1F700AE22DC /* XCRemoteSwiftPackageReference "LaunchAtLogin" */, ); - productRefGroup = 98D573CF27571EB3001C2D8C /* Products */; + productRefGroup = 98712FA22B2BB15E005163D4 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( - 98D573CD27571EB3001C2D8C /* CalendarX */, + 98712FA02B2BB15E005163D4 /* CalendarX */, + 98712FD02B2BB29B005163D4 /* CalendarXWidget */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 98D573CC27571EB3001C2D8C /* Resources */ = { + 98712F9F2B2BB15E005163D4 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 98D573D927571EB6001C2D8C /* Preview Assets.xcassets in Resources */, - 987E85C527BFD3E1003CC110 /* weekPF.json in Resources */, - 98CE8BDB27BBAA93009E5674 /* tiaoxiu.json in Resources */, - 98CED54E27F43CF100E0F758 /* InfoPlist.strings in Resources */, - 98CE8BE827BF43EB009E5674 /* solarPF.json in Resources */, - 98CE8BEE27BF5105009E5674 /* solarAF.json in Resources */, - 98B5B6CD2942A6D800114483 /* apps.json in Resources */, - 982DABC027C32FC9002891A3 /* weekSF.json in Resources */, - 98D573D627571EB6001C2D8C /* Assets.xcassets in Resources */, - 98CE8BE027BDEF1D009E5674 /* chuxi.json in Resources */, - 988A82D6279FEC4E000899B5 /* Localizable.strings in Resources */, - 98CE8BE427BDFA12009E5674 /* terms.json in Resources */, - 982DABC227C330EC002891A3 /* weekAF.json in Resources */, - 98CE8BEC27BF44A3009E5674 /* lunarPF.json in Resources */, + 98712FAC2B2BB160005163D4 /* Preview Assets.xcassets in Resources */, + 98FFFC462B2D188F0047B692 /* Localizable.strings in Resources */, + 98FFFC492B2D18930047B692 /* InfoPlist.strings in Resources */, + 98712FA92B2BB160005163D4 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 98712FCF2B2BB29B005163D4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 981660242B30DA2B0046558A /* Localizable.strings in Resources */, + 98712FDA2B2BB29C005163D4 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 9829F17327F2E46F0085F98E /* ShellScript */ = { + 9886FD032B2D11DA00AE22DC /* ShellScript */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; @@ -456,76 +479,101 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 98D573CA27571EB3001C2D8C /* Sources */ = { + 98712F9D2B2BB15E005163D4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9886FD022B2D0E8D00AE22DC /* CalendarXApp.swift in Sources */, + 9886FCED2B2CE6A400AE22DC /* DateView.swift in Sources */, + 9886FCEB2B2CE6A400AE22DC /* MenubarItemController.swift in Sources */, + 9886FCE92B2CE6A400AE22DC /* MenubarController.swift in Sources */, + 9886FCC72B2CE69A00AE22DC /* ScacleButtonPicker.swift in Sources */, + 9886FCBF2B2CE3AC00AE22DC /* LaunchHelper.swift in Sources */, + 9886FCC92B2CE69A00AE22DC /* RowTitleView.swift in Sources */, + 9886FCF72B2CE6AA00AE22DC /* AlertAction.swift in Sources */, + 9886FCF92B2CE6AA00AE22DC /* MenubarViewModel.swift in Sources */, + 9886FCFB2B2CE6AA00AE22DC /* Router.swift in Sources */, + 9886FCFC2B2CE6AA00AE22DC /* CalendarViewModel.swift in Sources */, + 9886FCE62B2CE6A400AE22DC /* MenubarSettingsView.swift in Sources */, + 9886FCE32B2CE6A400AE22DC /* AboutView.swift in Sources */, + 9886FCEC2B2CE6A400AE22DC /* RootView.swift in Sources */, + 9816601A2B30D7440046558A /* CalendarXWidget.intentdefinition in Sources */, + 9886FCC82B2CE69A00AE22DC /* ScacleButton.swift in Sources */, + 9886FCC62B2CE69A00AE22DC /* TitleView.swift in Sources */, + 9886FCD02B2CE69E00AE22DC /* MenubarStyle.swift in Sources */, + 9886FCE42B2CE6A400AE22DC /* SettingsView.swift in Sources */, + 9886FCF82B2CE6AA00AE22DC /* SettingsViewModel.swift in Sources */, + 9886FCEA2B2CE6A400AE22DC /* MenubarPopover.swift in Sources */, + 9886FCBD2B2CE3AC00AE22DC /* MonitorHelper.swift in Sources */, + 9886FCCF2B2CE69E00AE22DC /* CalendarPreference.swift in Sources */, + 9886FCEF2B2CE6A400AE22DC /* MainView.swift in Sources */, + 9886FCD12B2CE69E00AE22DC /* MenubarPreference.swift in Sources */, + 9886FCE82B2CE6A400AE22DC /* CalendarSettingsView.swift in Sources */, + 9886FCEE2B2CE6A400AE22DC /* AlertView.swift in Sources */, + 9886FCE52B2CE6A400AE22DC /* RecommendationsView.swift in Sources */, + 9886FCE72B2CE6A400AE22DC /* AppearanceSettingsView.swift in Sources */, + 9886FCCA2B2CE69A00AE22DC /* RotationArrow.swift in Sources */, + 9886FCBE2B2CE3AC00AE22DC /* Updater.swift in Sources */, + 9886FCFA2B2CE6AA00AE22DC /* MainViewModel.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 98712FCD2B2BB29B005163D4 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 980E46D629B489D500036309 /* AlertAction.swift in Sources */, - 9829B63E2999864E00C8AB8A /* MenubarViewModel.swift in Sources */, - 98D2479827844D8F00F2B278 /* Constant.swift in Sources */, - 9829B63C299980BC00C8AB8A /* MenubarPreference.swift in Sources */, - 988A82E3279FFB8A000899B5 /* Preference.swift in Sources */, - 98139ED1299EF504000EEF46 /* MenubarStyle.swift in Sources */, - 98139ED3299EFFD0000EEF46 /* SettingsViewModel.swift in Sources */, - 98D2479427842E5A00F2B278 /* MenubarController.swift in Sources */, - 98FEAB9D27F6D6B10034EC1F /* MonitorHelper.swift in Sources */, - 98BC335629A022DF00FC8400 /* RowTitleView.swift in Sources */, - 984E5E5A29B0969D009EBB24 /* CalendarViewModel.swift in Sources */, - 98BE991627A0F6AB00306061 /* RootView.swift in Sources */, - 982DABC627C33343002891A3 /* Bundle+.swift in Sources */, - 98F4347727A24297009F18CC /* ScacleButton.swift in Sources */, - 98B5B6C929427A8A00114483 /* TitleView.swift in Sources */, - 98BE991E27A1415F00306061 /* SettingsView.swift in Sources */, - 98AB002529A5670D006C6FC7 /* Updater.swift in Sources */, - 98C9BD0A290999F600F645AD /* MenubarSettingsView.swift in Sources */, - 982DABC427C332E1002891A3 /* Date+.swift in Sources */, - 98AB002329A565E8006C6FC7 /* LaunchHelper.swift in Sources */, - 98ED367427BB468700AF578A /* CalDay.swift in Sources */, - 984E5E5C29B096DE009EBB24 /* CalendarPreference.swift in Sources */, - 988A82DE279FEC9D000899B5 /* Language.swift in Sources */, - 982DABCC27C60713002891A3 /* EventHelper.swift in Sources */, - 988A82E0279FEC9D000899B5 /* Theme.swift in Sources */, - 98ED365527A288E500AF578A /* DateView.swift in Sources */, - 98CED55327F4423A00E0F758 /* L10n.swift in Sources */, - 988A82E1279FEC9D000899B5 /* AppInfo.swift in Sources */, - 988A82CE279F8B1A000899B5 /* AppKit+.swift in Sources */, - 98F4347927A24AFC009F18CC /* Router.swift in Sources */, - 98ED365727A289EC00AF578A /* View+.swift in Sources */, - 98CED54B27F3057100E0F758 /* RotationArrow.swift in Sources */, - 98ED365927A354CC00AF578A /* ScacleButtonPicker.swift in Sources */, - 98BE991827A0F75900306061 /* MainView.swift in Sources */, - 98BE991C27A1397500306061 /* Calendar+.swift in Sources */, - 984E5E5329AA9417009EBB24 /* CalendarSettingsView.swift in Sources */, - 9885302428168D4800FD98BC /* Color+.swift in Sources */, - 98139ECF299EC229000EEF46 /* SegmentedPicker.swift in Sources */, - 98FEABB427F8298C0034EC1F /* CalendarXApp.swift in Sources */, - 984E5E5529AF6BF0009EBB24 /* AboutView.swift in Sources */, - 98D247962784324700F2B278 /* MenubarPopover.swift in Sources */, - 980E46D829B48A0C00036309 /* AlertView.swift in Sources */, - 9808C701297889FE0062B3B9 /* MenubarItemController.swift in Sources */, - 98139ED5299F33D4000EEF46 /* AppearanceSettingsView.swift in Sources */, - 98F4347427A23ABE009F18CC /* MainViewModel.swift in Sources */, - 98B5B6CB294289F900114483 /* RecommendationsView.swift in Sources */, + 9816601B2B30D7440046558A /* CalendarXWidget.intentdefinition in Sources */, + 98712FE92B2BB3BC005163D4 /* LargeWidgetEntry.swift in Sources */, + 98712FE72B2BB3A6005163D4 /* LargeWidgetProvider.swift in Sources */, + 9886FCAC2B2BC54400AE22DC /* LargeWidgetView.swift in Sources */, + 98712FD62B2BB29B005163D4 /* CalendarXWidgetBundle.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 98712FDE2B2BB29C005163D4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 98712FD02B2BB29B005163D4 /* CalendarXWidget */; + targetProxy = 98712FDD2B2BB29C005163D4 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ - 988A82D8279FEC4E000899B5 /* Localizable.strings */ = { + 9816601D2B30D7440046558A /* CalendarXWidget.intentdefinition */ = { + isa = PBXVariantGroup; + children = ( + 9816601C2B30D7440046558A /* Base */, + 9816601F2B30D7470046558A /* en */, + 981660212B30D7480046558A /* zh-Hans */, + ); + name = CalendarXWidget.intentdefinition; + sourceTree = ""; + }; + 981660262B30DA2B0046558A /* Localizable.strings */ = { isa = PBXVariantGroup; children = ( - 988A82D7279FEC4E000899B5 /* en */, - 988A82D9279FEC4F000899B5 /* zh-Hans */, + 981660252B30DA2B0046558A /* en */, + 981660272B30DA2C0046558A /* zh-Hans */, ); name = Localizable.strings; sourceTree = ""; }; - 98CED55027F43CF100E0F758 /* InfoPlist.strings */ = { + 98FFFC482B2D188F0047B692 /* Localizable.strings */ = { isa = PBXVariantGroup; children = ( - 98CED54F27F43CF100E0F758 /* en */, - 98CED55127F43CF300E0F758 /* zh-Hans */, + 98FFFC472B2D188F0047B692 /* en */, + 98FFFC4D2B2D18970047B692 /* zh-Hans */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 98FFFC4B2B2D18930047B692 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 98FFFC4A2B2D18930047B692 /* en */, + 98FFFC4C2B2D18940047B692 /* zh-Hans */, ); name = InfoPlist.strings; sourceTree = ""; @@ -533,15 +581,14 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ - 98D573DB27571EB6001C2D8C /* Debug */ = { + 98712FAE2B2BB160005163D4 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - CLANG_CXX_LIBRARY = "libc++"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; @@ -568,11 +615,11 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu17; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; @@ -586,25 +633,25 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; - 98D573DC27571EB6001C2D8C /* Release */ = { + 98712FAF2B2BB160005163D4 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - CLANG_CXX_LIBRARY = "libc++"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; @@ -631,11 +678,11 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu17; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; @@ -643,40 +690,39 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; }; name = Release; }; - 98D573DE27571EB6001C2D8C /* Debug */ = { + 98712FB12B2BB160005163D4 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CODE_SIGN_ENTITLEMENTS = CalendarX/CalendarX.entitlements; - CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 2.3.0; - DEAD_CODE_STRIPPING = YES; + CURRENT_PROJECT_VERSION = 2.3.1; DEVELOPMENT_ASSET_PATHS = "\"CalendarX/Preview Content\""; DEVELOPMENT_TEAM = ""; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = CalendarX/Info.plist; - INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.lifestyle"; INFOPLIST_KEY_LSUIElement = YES; - INFOPLIST_KEY_NSCalendarsUsageDescription = "Used to display calendar events"; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2020 ZzzM. All rights reserved."; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 2.3.0; + MACOSX_DEPLOYMENT_TARGET = 11.0; + MARKETING_VERSION = 2.3.1; PRODUCT_BUNDLE_IDENTIFIER = com.alpha.calendarx; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -685,31 +731,30 @@ }; name = Debug; }; - 98D573DF27571EB6001C2D8C /* Release */ = { + 98712FB22B2BB160005163D4 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CODE_SIGN_ENTITLEMENTS = CalendarX/CalendarX.entitlements; - CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 2.3.0; - DEAD_CODE_STRIPPING = YES; + CURRENT_PROJECT_VERSION = 2.3.1; DEVELOPMENT_ASSET_PATHS = "\"CalendarX/Preview Content\""; DEVELOPMENT_TEAM = ""; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = CalendarX/Info.plist; - INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.lifestyle"; INFOPLIST_KEY_LSUIElement = YES; - INFOPLIST_KEY_NSCalendarsUsageDescription = "Used to display calendar events"; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2020 ZzzM. All rights reserved."; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 2.3.0; + MACOSX_DEPLOYMENT_TARGET = 11.0; + MARKETING_VERSION = 2.3.1; PRODUCT_BUNDLE_IDENTIFIER = com.alpha.calendarx; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -718,86 +763,171 @@ }; name = Release; }; + 98712FE12B2BB29D005163D4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CODE_SIGN_ENTITLEMENTS = CalendarXWidget/CalendarXWidget.entitlements; + CODE_SIGN_STYLE = Manual; + CURRENT_PROJECT_VERSION = 2.3.1; + DEVELOPMENT_TEAM = ""; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = CalendarXWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = CalendarXWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@executable_path/../../../../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 11.0; + MARKETING_VERSION = 2.3.1; + PRODUCT_BUNDLE_IDENTIFIER = com.alpha.calendarx.widget; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 98712FE22B2BB29D005163D4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CODE_SIGN_ENTITLEMENTS = CalendarXWidget/CalendarXWidget.entitlements; + CODE_SIGN_STYLE = Manual; + CURRENT_PROJECT_VERSION = 2.3.1; + DEVELOPMENT_TEAM = ""; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = CalendarXWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = CalendarXWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@executable_path/../../../../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 11.0; + MARKETING_VERSION = 2.3.1; + PRODUCT_BUNDLE_IDENTIFIER = com.alpha.calendarx.widget; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 98D573C927571EB3001C2D8C /* Build configuration list for PBXProject "CalendarX" */ = { + 98712F9C2B2BB15E005163D4 /* Build configuration list for PBXProject "CalendarX" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 98712FAE2B2BB160005163D4 /* Debug */, + 98712FAF2B2BB160005163D4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 98712FB02B2BB160005163D4 /* Build configuration list for PBXNativeTarget "CalendarX" */ = { isa = XCConfigurationList; buildConfigurations = ( - 98D573DB27571EB6001C2D8C /* Debug */, - 98D573DC27571EB6001C2D8C /* Release */, + 98712FB12B2BB160005163D4 /* Debug */, + 98712FB22B2BB160005163D4 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 98D573DD27571EB6001C2D8C /* Build configuration list for PBXNativeTarget "CalendarX" */ = { + 98712FE02B2BB29D005163D4 /* Build configuration list for PBXNativeTarget "CalendarXWidget" */ = { isa = XCConfigurationList; buildConfigurations = ( - 98D573DE27571EB6001C2D8C /* Debug */, - 98D573DF27571EB6001C2D8C /* Release */, + 98712FE12B2BB29D005163D4 /* Debug */, + 98712FE22B2BB29D005163D4 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ +/* Begin XCLocalSwiftPackageReference section */ + 9886FCA62B2BC52700AE22DC /* XCLocalSwiftPackageReference "CalendarXShared" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = CalendarXShared; + }; +/* End XCLocalSwiftPackageReference section */ + /* Begin XCRemoteSwiftPackageReference section */ - 98139ECB299D98BC000EEF46 /* XCRemoteSwiftPackageReference "Schedule" */ = { + 9886FCAD2B2CE15600AE22DC /* XCRemoteSwiftPackageReference "Sparkle" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/luoxiu/Schedule"; + repositoryURL = "https://github.com/sparkle-project/Sparkle"; requirement = { kind = exactVersion; - version = 2.1.1; + version = 2.5.1; }; }; - 9829F17027F2E2D90085F98E /* XCRemoteSwiftPackageReference "LaunchAtLogin" */ = { + 9886FCB02B2CE19C00AE22DC /* XCRemoteSwiftPackageReference "WrappingHStack" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/sindresorhus/LaunchAtLogin"; + repositoryURL = "https://github.com/dkk/WrappingHStack"; requirement = { kind = exactVersion; - version = 5.0.0; + version = 2.2.11; }; }; - 982DABC727C37977002891A3 /* XCRemoteSwiftPackageReference "WrappingHStack" */ = { + 9886FCB32B2CE1B900AE22DC /* XCRemoteSwiftPackageReference "Schedule" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/dkk/WrappingHStack"; + repositoryURL = "https://github.com/luoxiu/Schedule"; requirement = { kind = exactVersion; - version = 2.2.9; + version = 2.1.1; }; }; - 98BE991227A0E08500306061 /* XCRemoteSwiftPackageReference "Sparkle" */ = { + 9886FCB62B2CE1F700AE22DC /* XCRemoteSwiftPackageReference "LaunchAtLogin" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/sparkle-project/Sparkle"; + repositoryURL = "https://github.com/sindresorhus/LaunchAtLogin"; requirement = { kind = exactVersion; - version = 2.3.2; + version = 5.0.0; }; }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 98139ECC299D98BC000EEF46 /* Schedule */ = { + 9886FCA72B2BC52700AE22DC /* CalendarXShared */ = { isa = XCSwiftPackageProductDependency; - package = 98139ECB299D98BC000EEF46 /* XCRemoteSwiftPackageReference "Schedule" */; - productName = Schedule; + productName = CalendarXShared; }; - 9829F17127F2E2D90085F98E /* LaunchAtLogin */ = { + 9886FCA92B2BC53000AE22DC /* CalendarXShared */ = { isa = XCSwiftPackageProductDependency; - package = 9829F17027F2E2D90085F98E /* XCRemoteSwiftPackageReference "LaunchAtLogin" */; - productName = LaunchAtLogin; + package = 9886FCA62B2BC52700AE22DC /* XCLocalSwiftPackageReference "CalendarXShared" */; + productName = CalendarXShared; }; - 982DABC827C37977002891A3 /* WrappingHStack */ = { + 9886FCAE2B2CE15600AE22DC /* Sparkle */ = { isa = XCSwiftPackageProductDependency; - package = 982DABC727C37977002891A3 /* XCRemoteSwiftPackageReference "WrappingHStack" */; + package = 9886FCAD2B2CE15600AE22DC /* XCRemoteSwiftPackageReference "Sparkle" */; + productName = Sparkle; + }; + 9886FCB12B2CE19C00AE22DC /* WrappingHStack */ = { + isa = XCSwiftPackageProductDependency; + package = 9886FCB02B2CE19C00AE22DC /* XCRemoteSwiftPackageReference "WrappingHStack" */; productName = WrappingHStack; }; - 98BE991327A0E08500306061 /* Sparkle */ = { + 9886FCB42B2CE1B900AE22DC /* Schedule */ = { isa = XCSwiftPackageProductDependency; - package = 98BE991227A0E08500306061 /* XCRemoteSwiftPackageReference "Sparkle" */; - productName = Sparkle; + package = 9886FCB32B2CE1B900AE22DC /* XCRemoteSwiftPackageReference "Schedule" */; + productName = Schedule; + }; + 9886FCB72B2CE1F700AE22DC /* LaunchAtLogin */ = { + isa = XCSwiftPackageProductDependency; + package = 9886FCB62B2CE1F700AE22DC /* XCRemoteSwiftPackageReference "LaunchAtLogin" */; + productName = LaunchAtLogin; }; /* End XCSwiftPackageProductDependency section */ }; - rootObject = 98D573C627571EB3001C2D8C /* Project object */; + rootObject = 98712F992B2BB15E005163D4 /* Project object */; } diff --git a/CalendarX.xcodeproj/xcshareddata/xcschemes/CalendarX.xcscheme b/CalendarX.xcodeproj/xcshareddata/xcschemes/CalendarX.xcscheme index 64d1c59..88e89bd 100644 --- a/CalendarX.xcodeproj/xcshareddata/xcschemes/CalendarX.xcscheme +++ b/CalendarX.xcodeproj/xcshareddata/xcschemes/CalendarX.xcscheme @@ -1,7 +1,7 @@ + LastUpgradeVersion = "1510" + version = "1.7"> @@ -14,7 +14,7 @@ buildForAnalyzing = "YES"> @@ -26,9 +26,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES"> - - + shouldUseLaunchSchemeArgsEnv = "YES" + shouldAutocreateTestPlan = "YES"> @@ -61,7 +60,7 @@ runnableDebuggingMode = "0"> diff --git a/CalendarX/CalendarX.entitlements b/CalendarX/CalendarX.entitlements index da90437..0c67376 100644 --- a/CalendarX/CalendarX.entitlements +++ b/CalendarX/CalendarX.entitlements @@ -1,10 +1,5 @@ - - com.apple.security.application-groups - - group.com.alpha.calendarx - - + diff --git a/CalendarX/CalendarXApp.swift b/CalendarX/CalendarXApp.swift index 5b38b4c..0a357c9 100644 --- a/CalendarX/CalendarXApp.swift +++ b/CalendarX/CalendarXApp.swift @@ -6,7 +6,7 @@ // import SwiftUI - +import CalendarXShared @main struct CalendarXApp: App { @@ -15,9 +15,11 @@ struct CalendarXApp: App { private var delegate init() { + LaunchHelper.migrateIfNeeded() - EventHelper.start() + CalendarPreference.check() Updater.start() + } var body: some Scene { @@ -32,17 +34,20 @@ class CalendarXDelegate: NSObject & NSApplicationDelegate { lazy var rootView = RootView() lazy var popover = MenubarPopover(rootView) lazy var controller = MenubarController(popover) - + func applicationWillFinishLaunching(_ notification: Notification) { + NSRunningApplication - .runningApplications(withBundleIdentifier: AppInfo.identifier) + .runningApplications(withBundleIdentifier: AppBundle.identifier) .filter { $0.isFinishedLaunching } .forEach { $0.terminate() } + } func applicationDidFinishLaunching(_ notification: Notification) { _ = controller } + } diff --git a/CalendarX/Component/RotationArrow.swift b/CalendarX/Component/RotationArrow.swift index 779a276..a830629 100644 --- a/CalendarX/Component/RotationArrow.swift +++ b/CalendarX/Component/RotationArrow.swift @@ -11,7 +11,8 @@ struct RotationArrow: View { var isPresented: Bool var body: some View { Image.rightArrow - .foregroundColor(.secondary) + .font(.title3) + .appForeground(.appSecondary) .rotationEffect(.degrees(isPresented ? 90 : 0)) .animation(.spring(), value: isPresented) } diff --git a/CalendarX/Component/RowTitleView.swift b/CalendarX/Component/RowTitleView.swift index 220c202..d0c58f2 100644 --- a/CalendarX/Component/RowTitleView.swift +++ b/CalendarX/Component/RowTitleView.swift @@ -15,7 +15,7 @@ struct RowTitleView: View { Text(title) .font(font) .frame(maxWidth: .infinity, alignment: .leading) - .foregroundColor(font != .none ? .primary: .secondary) + .appForeground(font != .none ? .appPrimary: .appSecondary) } } diff --git a/CalendarX/Component/ScacleButton.swift b/CalendarX/Component/ScacleButton.swift index 5fe5da8..4181658 100644 --- a/CalendarX/Component/ScacleButton.swift +++ b/CalendarX/Component/ScacleButton.swift @@ -6,7 +6,7 @@ // import SwiftUI - +import CalendarXShared struct ScacleButton: View { let action: VoidClosure @@ -22,17 +22,16 @@ struct ScacleButton: View { struct ScacleImageButton: View { - private let image: Image, scale: Image.Scale, color: Color, action: VoidClosure - - init(image: Image, scale: Image.Scale = .medium, color: Color = .secondary, action: @escaping VoidClosure) { + private let image: Image, color: Color, action: VoidClosure + + init(image: Image, color: Color = .appSecondary, action: @escaping VoidClosure) { self.image = image - self.scale = scale self.color = color self.action = action } var body: some View { - ScacleButton(action: action, label: { image.imageScale(scale).foregroundColor(color) }) + ScacleButton(action: action, label: { image.font(.title3).appForeground(color) }) } } @@ -44,8 +43,8 @@ struct ScacleTagButton: View { .padding(.horizontal, 5) .padding(.vertical, 5) .background(Color.tagBackground) - .foregroundColor(.accentColor) - .clipShape(Capsule()) + .appForeground(.white) + .clipShape(.capsule) } } } @@ -62,8 +61,8 @@ struct ScacleCapsuleButton: View { .frame(maxWidth: .infinity) .padding(.vertical, 5) .background(backgroundColor) - .foregroundColor(foregroundColor) - .clipShape(Capsule()) + .appForeground(foregroundColor) + .clipShape(.capsule) } } } diff --git a/CalendarX/Component/ScacleButtonPicker.swift b/CalendarX/Component/ScacleButtonPicker.swift index 07d1579..91181df 100644 --- a/CalendarX/Component/ScacleButtonPicker.swift +++ b/CalendarX/Component/ScacleButtonPicker.swift @@ -6,7 +6,6 @@ // import SwiftUI - struct ScacleButtonPicker: View { private let items: [Item] @@ -61,26 +60,26 @@ struct ScacleButtonPicker: View { @ViewBuilder func popoverContent() -> some View { ScrollViewReader { reader in - ScrollView { - LazyVStack { + ScrollView(showsIndicators: false) { + LazyVGrid(columns: [GridItem(.fixed(width))], spacing: 0) { ForEach(items, id: \.self) { item in Button { selection = item isPresented.toggle() } label: { itemLabel(item) - .foregroundColor(item == selection ? tint:.primary) + .appForeground(item == selection ? tint:.primary) .lineLimit(1) - .minimumScaleFactor(0.1) + .minimumScaleFactor(0.75) } .id(item) .buttonStyle(.plain) - .frame(minWidth: width, idealHeight: .popoverRowHeight) + .frame(height: .popoverRowHeight) } } .padding(5) } - .frame(height: min(CGFloat(items.count + 1) * .popoverRowHeight + 10, .popoverHeight)) + .frame(height: min(CGFloat(items.count) * .popoverRowHeight + 10, .popoverHeight)) .onAppear { reader.scrollTo(selection) } } } diff --git a/CalendarX/Component/SegmentedPicker.swift b/CalendarX/Component/SegmentedPicker.swift deleted file mode 100644 index c1c4f55..0000000 --- a/CalendarX/Component/SegmentedPicker.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// SegmentedPicker.swift -// CalendarX -// -// Created by zm on 2023/2/17. -// - -import SwiftUI - -struct SegmentedPicker: View { - - let tabs: [Value] - - @Binding - var selection: Value - - let itemView: (Value) -> Content - - @State - private var offsetX: CGFloat = 0 - - - private let itemWidth: CGFloat = 90, itemHeight: CGFloat = 25 - - var body: some View { - - ZStack { - Color.disable - Capsule() - .foregroundColor(.accentColor) - .frame(width: itemWidth, height: itemHeight) - .position(x: itemWidth / 2 + offsetX, y: itemHeight / 2) - HStack(spacing: .zero) { - ForEach(Array(tabs.enumerated()), id: \.offset) { tab in - Button { - selection = tab.element - withAnimation { - offsetX = CGFloat(tab.offset) * itemWidth - } - } label: { - itemView(tab.element) - .frame(width: itemWidth, height: itemHeight) - .foregroundColor(.white) - .font(.subheadline) - .lineLimit(1) - .minimumScaleFactor(0.1) - } - .buttonStyle(.borderless) - } - } - .onAppear{ - let index = tabs.firstIndex(of: selection) ?? 0 - offsetX = CGFloat(index) * itemWidth - } - } - .frame(width: itemWidth * CGFloat(tabs.count), height: itemHeight) - .clipShape(Capsule(style: .circular)) - - } -} diff --git a/CalendarX/Component/TitleView.swift b/CalendarX/Component/TitleView.swift index fce4a66..ac8e9e3 100644 --- a/CalendarX/Component/TitleView.swift +++ b/CalendarX/Component/TitleView.swift @@ -7,19 +7,29 @@ import SwiftUI -struct TitleView: View { +struct TitleView: View { let title: () -> Title @ViewBuilder - let actions: () -> Content + let leftItems: () -> LeftItems + + @ViewBuilder + let rightItems: () -> RightItems + var body: some View { ZStack { + + HStack(content: leftItems) + .frame(maxWidth: .infinity, alignment: .leading) + title() .font(.title2) - HStack(content: actions) + + HStack(content: rightItems) .frame(maxWidth: .infinity, alignment: .trailing) + } } } diff --git a/CalendarX/Info.plist b/CalendarX/Info.plist index 6d6cd86..c0e227a 100644 --- a/CalendarX/Info.plist +++ b/CalendarX/Info.plist @@ -3,14 +3,18 @@ CommitDate - 2023.03.09 15:04 + 2023.12.19 6:34 CommitHash - 60f115b + 20e65e2 NSAppTransportSecurity NSAllowsArbitraryLoads + NSUserActivityTypes + + WidgetConfigurationIntent + SUEnableAutomaticChecks SUFeedURL diff --git a/CalendarX/Model/AppInfo.swift b/CalendarX/Model/AppInfo.swift deleted file mode 100644 index 9e7eb0b..0000000 --- a/CalendarX/Model/AppInfo.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// AppInfo.swift -// CalendarX -// -// Created by zm on 2021/12/30. -// - -import Foundation - - -enum AppInfoKey: String { - case build = "CFBundleVersion", - version = "CFBundleShortVersionString", - identifier = "CFBundleIdentifier", - name = "CFBundleName", - commitHash = "CommitHash", - commitDate = "CommitDate" -} - -struct AppInfo { - - private static subscript(key: AppInfoKey) -> String { - Bundle.main.infoDictionary?[key.rawValue] as? String ?? "none" - } - static let name = Self[.name] - static let version = Self[.version] - static let identifier = Self[.identifier] - static let commitHash = Self[.commitHash] - static let commitDate = Self[.commitHash] -} diff --git a/CalendarX/Model/CalendarPreference.swift b/CalendarX/Model/CalendarPreference.swift index 05443bd..acec00d 100644 --- a/CalendarX/Model/CalendarPreference.swift +++ b/CalendarX/Model/CalendarPreference.swift @@ -6,13 +6,15 @@ // import SwiftUI +import CalendarXShared +import WidgetKit struct CalendarPreference { static let shared = CalendarPreference() @AppStorage(CalendarStorageKey.weekday, store: .group) - var weekday: CalWeekday = .sunday + var weekday: AppWeekday = .sunday @AppStorage(CalendarStorageKey.showEvents, store: .group) var showEvents: Bool = false @@ -24,3 +26,12 @@ struct CalendarPreference { var showHolidays: Bool = true } + +extension CalendarPreference { + static func check() { + WidgetCenter.shared.reloadAllTimelines() + if EventHelper.isAuthorized { return } + guard shared.showEvents else { return } + shared.showEvents = false + } +} diff --git a/CalendarX/Model/Language.swift b/CalendarX/Model/Language.swift deleted file mode 100644 index 2d52b95..0000000 --- a/CalendarX/Model/Language.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// Language.swift -// CalendarX -// -// Created by zm on 2022/1/18. -// - -import SwiftUI - -enum Language: Int, CaseIterable { - - case system, zh_CN, en_US - - var locale: Locale { - switch self { - case .zh_CN: return .zh - case .en_US: return .en - default: return Locale.current - } - } - - var title: LocalizedStringKey { - switch self { - case .zh_CN: return L10n.Language.zh_CN - case .en_US: return L10n.Language.en_US - default: return L10n.Language.system - } - } - -} - - diff --git a/CalendarX/Model/MenuBarStyle.swift b/CalendarX/Model/MenuBarStyle.swift index 51ba602..92119a2 100644 --- a/CalendarX/Model/MenuBarStyle.swift +++ b/CalendarX/Model/MenuBarStyle.swift @@ -6,6 +6,7 @@ // import SwiftUI +import CalendarXShared enum MenubarStyle: Int, CaseIterable, Decodable { // 2.2.0 or earlier diff --git a/CalendarX/Model/MenubarPreference.swift b/CalendarX/Model/MenubarPreference.swift index 93bda5f..9ae2436 100644 --- a/CalendarX/Model/MenubarPreference.swift +++ b/CalendarX/Model/MenubarPreference.swift @@ -6,22 +6,17 @@ // import SwiftUI +import CalendarXShared //MARK: Menubar Date&Time Style -typealias DTTag = (offset: Int, element: DTType) - -enum DTType: String, Codable { +enum DTType: String, Codable, Hashable { case lm, ld, sm, sd, e, a, t } -struct DTIndex: Decodable { - let isShown: Bool, index: Int -} - struct MenubarPreference { - + static let shared = MenubarPreference() - + @AppStorage(MenubarStorageKey.style, store: .group) var style: MenubarStyle = .default @@ -29,7 +24,7 @@ struct MenubarPreference { // Use a 24-hour clock @AppStorage(MenubarStorageKey.use24h, store: .group) var use24h: Bool = true - + // Display the time with seconds @AppStorage(MenubarStorageKey.showSeconds, store: .group) var showSeconds: Bool = false @@ -39,10 +34,47 @@ struct MenubarPreference { @AppStorage(MenubarStorageKey.hiddenTypes, store: .group) var hiddenTypes: [DTType] = [.lm, .ld, .a] - + // Text Style @AppStorage(MenubarStorageKey.text, store: .group) - var text: String = AppInfo.name - + var text: String = AppBundle.name + } +extension MenubarPreference { + var dateItemTitle: String { + let date = Date() + + return dateTitle(types: shownTypes) { + switch $0 { + case .lm: return L10n.lm(from: date) + case .ld: return L10n.ld(from: date) + case .sm: return L10n.sm(from: date) + case .sd: return L10n.sd(from: date) + case .e: return L10n.e(from: date) + case .a: return L10n.a(from: date) + case .t: return L10n.t(from: date, use24h: use24h, showSeconds: showSeconds) + } + + } + } + + func dateTitle(types: [DTType], map: (DTType) -> String) -> String { + guard let type = types.first else { return AppBundle.name } + var titleArray = [map(type)] + for (index, type) in types.enumerated() { + guard index > 0 else { continue } + var title = map(type) + if L10n.inChinese { + let preIndex = index - 1, preType = types[preIndex] + if (type == .ld && preType == .lm) || + (type == .sd && preType == .sm) { + title = titleArray[preIndex] + title + titleArray[preIndex] = "" + } + } + titleArray.append(title) + } + return titleArray.joined(separator: " ") + } +} diff --git a/CalendarX/Model/Preference.swift b/CalendarX/Model/Preference.swift deleted file mode 100644 index a9f5268..0000000 --- a/CalendarX/Model/Preference.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// Preferences.swift -// Bingpaper -// -// Created by zm on 2021/10/26. -// -import SwiftUI - - -struct Preference { - - static let shared = Preference() - - @AppStorage(AppStorageKey.theme, store: .group) - var theme: Theme = .system - - @AppStorage(AppStorageKey.tint, store: .group) - var tint: String = Appearance.tint - - @AppStorage(AppStorageKey.language, store: .group) - var language: Language = .system - -} - -extension Preference { - var color: Color { Color(hex: tint) } - var colorScheme: ColorScheme? { theme.colorScheme } - var locale: Locale { language.locale } -} - - - diff --git a/CalendarX/Model/Theme.swift b/CalendarX/Model/Theme.swift deleted file mode 100644 index 63ae775..0000000 --- a/CalendarX/Model/Theme.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// Theme.swift -// CalendarX -// -// Created by zm on 2021/10/26. -// -import SwiftUI - -enum Theme: Int, CaseIterable { - - case system, light, dark - - var colorScheme: ColorScheme? { - switch self { - case .light: return .light - case .dark: return .dark - default: return .none - } - } - - var title: LocalizedStringKey { - switch self { - case .light: return L10n.Theme.light - case .dark: return L10n.Theme.dark - default: return L10n.Theme.system - } - } -} diff --git a/CalendarX/Module/Calender/AlertView.swift b/CalendarX/Module/Calender/AlertView.swift index d6bf14f..640e9c7 100644 --- a/CalendarX/Module/Calender/AlertView.swift +++ b/CalendarX/Module/Calender/AlertView.swift @@ -9,31 +9,35 @@ import SwiftUI import Combine struct AlertView: View { - + @ObservedObject var alert: AlertAction - + var body: some View { - - Color.black - .opacity(alert.isPresented ? 0.5: 0) - .onTapGesture(perform: alert.dismiss) - - if alert.isPresented { - VStack { - Text(alert.title).bold().padding(.vertical, 5).foregroundColor(.accentColor) - Text(alert.message).multilineTextAlignment(.center) - HStack { - ScacleCapsuleButton(title: alert.no, foregroundColor: .white, backgroundColor: .secondary, action: alert.dismiss) + + + ZStack(alignment: .bottom) { + + Color.black + .opacity(alert.isPresented ? 0.5: 0) + .onTapGesture(perform: alert.dismiss) + + + if alert.isPresented { + VStack { + + alert.image.font(.largeTitle).appForeground(.accentColor) + Text(alert.message).font(.title3).multilineTextAlignment(.center).padding(.vertical, 5) + ScacleCapsuleButton(title: alert.yes, foregroundColor: .white, backgroundColor: .accentColor, action: alert.action) + ScacleCapsuleButton(title: alert.no, foregroundColor: .white, backgroundColor: .appSecondary, action: alert.dismiss) + } - .font(.caption2) + .padding() + .background(Color.card.clipShape(.rect(cornerRadius: 5))) + .transition(.move(edge: .bottom).combined(with: .opacity)) + .padding() } - .padding() - .frame(width: .mainWidth/2, alignment: .top) - .background(RoundedRectangle(cornerRadius: 5).foregroundColor(.card).shadow(radius: 1, x: 1, y: 1)) - .transition(.move(edge: .bottom ).combined(with: .opacity)) } - } } diff --git a/CalendarX/Module/Calender/DateView.swift b/CalendarX/Module/Calender/DateView.swift index 55e4c1e..3bfd190 100644 --- a/CalendarX/Module/Calender/DateView.swift +++ b/CalendarX/Module/Calender/DateView.swift @@ -7,24 +7,28 @@ import SwiftUI import WrappingHStack - +import CalendarXShared struct DateView: View { - let day: CalDay - + let appDate: AppDate + private var showEvents: Bool { CalendarPreference.shared.showEvents } var body: some View { VStack(spacing: 10) { TitleView { - Text(day.date, style: .date) - } actions: { - ScacleImageButton(image: .close, action: Router.backMain) + Text(appDate.date, style: .date) + } leftItems: { + ScacleImageButton(image: .backward, action: Router.backMain) + } rightItems: { + EmptyView() } - Text(day.lunarDate).font(.footnote).foregroundColor(.accentColor) - FestivalsView(festivals: day.festivals) - EventsView(events: day.events, showEvents: showEvents) + + + Text(appDate.lunarDate).font(.footnote).appForeground(.accentColor) + FestivalsView(festivals: appDate.festivals) + EventsView(events: appDate.events, showEvents: showEvents) } } @@ -41,6 +45,7 @@ struct FestivalsView: View { ScacleTagButton(title: festival.l10nKey) { NSWorkspace.searching(festival) } + .font(.subheadline) } } } @@ -50,8 +55,8 @@ struct FestivalsView: View { struct EventsView: View { - let events: [CalEvent], showEvents: Bool - + let events: [AppEvent], showEvents: Bool + var body: some View { Section { @@ -71,14 +76,14 @@ struct EventsView: View { } @ViewBuilder - func eventView(_ event: CalEvent) -> some View { + func eventView(_ event: AppEvent) -> some View { VStack(alignment: .leading, spacing: 5) { HStack { - Image.clock.foregroundColor(event.color) - + Image.clock.appForeground(event.color) + if event.isAllDay { Text(L10n.Date.allDay) } else { @@ -89,15 +94,15 @@ struct EventsView: View { } .font(.caption2) - .foregroundColor(.secondary) + .appForeground(.appSecondary) .frame(maxWidth: .infinity, alignment: .leading) - Text(event.title).foregroundColor(.primary) + Text(event.title).appForeground(.appPrimary) } .padding(5) .background(Color.card) - .cornerRadius(5) + .clipShape(.rect(cornerRadius: 5)) .shadow(radius: 1, x: 1, y: 1) .padding(.horizontal, 3) diff --git a/CalendarX/Module/Calender/MainView.swift b/CalendarX/Module/Calender/MainView.swift index 70ad731..4c55cd8 100644 --- a/CalendarX/Module/Calender/MainView.swift +++ b/CalendarX/Module/Calender/MainView.swift @@ -6,15 +6,15 @@ // import SwiftUI - +import CalendarXShared struct MainView: View { @ObservedObject var viewModel: MainViewModel - + var body: some View { - + CalendarView(date: viewModel.date, firstWeekday: viewModel.weekday, interval: viewModel.interval, @@ -23,7 +23,7 @@ struct MainView: View { dayView: dayView) .equatable() .frame(height: .mainHeight) - + } private func header() -> some View { @@ -31,7 +31,7 @@ struct MainView: View { HStack { MonthYearPicker(date: $viewModel.date, colorScheme: viewModel.colorScheme, tint: viewModel.tint) Spacer() - ScacleImageButton(image: .leftArrow, action: viewModel.lastMonth) + ScacleImageButton(image: .leftArrow, action: viewModel.lastMonth) .frame(width: .buttonWidth) ScacleImageButton(image: .circle, action: viewModel.reset) .frame(width: .buttonWidth) @@ -39,63 +39,65 @@ struct MainView: View { .frame(width: .buttonWidth) } - } private func weekView(date: Date) -> some View { Text(L10n.shortWeekday(from: date)) - .foregroundColor(date.inWeekend ? .secondary : .primary) + .appForeground(date.inWeekend ? .appSecondary : .appPrimary) .sideLength(30) } @ViewBuilder - private func dayView(inSameMonth: Bool, day: CalDay) -> some View { - - let showHolidays = !day.inNormal && viewModel.showHolidays, - showEvents = day.events.isNotEmpty && viewModel.showEvents, - defaultColor: Color = day.inWeekend ? .secondary : .primary - + private func dayView(appDate: AppDate) -> some View { + + let showHolidays = !appDate.inNormal && viewModel.showHolidays, + showEvents = appDate.events.isNotEmpty && viewModel.showEvents, + showLunar = viewModel.showLunar, + defaultColor: Color = appDate.inWeekend ? .appSecondary : .appPrimary, + inSameMonth = viewModel.date.inSameMonth(as: appDate.date), + txColor: Color = appDate.onHoliday ? .offBackground : .workBackground + ScacleButton { - Router.toDate(day) + Router.toDate(appDate) } label: { ZStack { - - if day.inToday { + + if appDate.inToday { RoundedRectangle(cornerRadius: 4) .stroke(Color.accentColor, lineWidth: 1) } if showHolidays { - (day.onHoliday ? Color.tagBackground : Color.workdayBackground) - .cornerRadius(4) - Text(day.stateDesc) - .font(.system(size: 7).bold().monospacedDigit()) + txColor.clipShape(.rect(cornerRadius: 4)) + Text(appDate.stateDesc) + .font(.system(size: 7, weight: .bold, design: .monospaced)) .offset(x: -14, y: -14) - .foregroundColor(day.onHoliday ? .accentColor: .secondary) + .appForeground(appDate.onHoliday ? .accentColor: .appSecondary) } if showEvents { Circle() .size(width: 5, height: 5) - .foregroundColor(.accentColor) + .appForeground(.accentColor) .offset(x: 32, y: 3) } VStack { - Text(day.title) + Text(appDate.title) .font(.title3.monospacedDigit()) - .foregroundColor(showHolidays ? day.onHoliday ? .accentColor: defaultColor : defaultColor) - if viewModel.showLunar { - Text(day.subtitle) + .appForeground(showHolidays ? appDate.onHoliday ? .accentColor: defaultColor : defaultColor) + if showLunar { + Text(appDate.subtitle) .font(.caption2.weight(.regular)) - .foregroundColor(.secondary) + .appForeground(showHolidays ? appDate.onHoliday ? .accentColor: .appSecondary : .appSecondary) } } } + .opacity(inSameMonth ? 1:0.3) + .sideLength(40) } - .opacity(inSameMonth ? 1:0.3) - .sideLength(40) + } } @@ -120,7 +122,7 @@ struct MonthYearPicker: View { colorScheme: colorScheme, selection: $date.month, isPresented: $isPresentedOfMonth) { - Text(L10n.monthSymbol(from: date.month)).font(.title2).foregroundColor(tint) + Text(L10n.monthSymbol(from: date.month)).font(.title2).appForeground(tint) } itemLabel: { Text(L10n.monthSymbol(from: $0)) } @@ -130,7 +132,7 @@ struct MonthYearPicker: View { colorScheme: colorScheme, selection: $date.year, isPresented: $isPresentedOfYear) { - Text(date.year.description).font(.title2).foregroundColor(tint) + Text(date.year.description).font(.title2).appForeground(tint) } itemLabel: { Text(String($0)) } @@ -140,16 +142,16 @@ struct MonthYearPicker: View { struct CalendarView: View { - private let date: Date, firstWeekday: CalWeekday, interval: TimeInterval - - private let dayView: (Bool, CalDay) -> Day, header: () -> Header, weekView: (Date) -> Week - + private let date: Date, firstWeekday: AppWeekday, interval: TimeInterval + + private let dayView: (AppDate) -> Day, header: () -> Header, weekView: (Date) -> Week + init(date: Date, - firstWeekday: CalWeekday, + firstWeekday: AppWeekday, interval: TimeInterval, @ViewBuilder header: @escaping () -> Header, @ViewBuilder weekView: @escaping (Date) -> Week, - @ViewBuilder dayView: @escaping (Bool, CalDay) -> Day + @ViewBuilder dayView: @escaping (AppDate) -> Day ) { self.date = date self.firstWeekday = firstWeekday @@ -158,37 +160,28 @@ struct CalendarView: View { self.header = header self.weekView = weekView } - - private let columns = Array(repeating: GridItem(), count: Solar.daysInWeek) - + var body: some View { - let days = makeDays() - let spacing: CGFloat? = days.count > Solar.minDates ? 1.7: nil - + let dates = CalendarHelper.makeDates(firstWeekday: firstWeekday, date: date) + let columns = CalendarHelper.columns + let spacing = CalendarHelper.spacing(from: dates.count) + LazyVGrid(columns: columns, spacing: spacing) { - Section(content: { - ForEach(0.. [CalDay] { - var calendar = Calendar.gregorian - calendar.firstWeekday = firstWeekday.rawValue - let dates = calendar.generateDates(for: date) - let events = EventHelper.fetchEvents(with: dates.first!, end: dates.last!) - - return dates.map { date in - CalDay(date, events: events.filter{$0.startDate.isSameDay(as: date)}) - } - } + } extension CalendarView: Equatable { diff --git a/CalendarX/Module/Calender/RootView.swift b/CalendarX/Module/Calender/RootView.swift index 0303d4c..7b1bc69 100644 --- a/CalendarX/Module/Calender/RootView.swift +++ b/CalendarX/Module/Calender/RootView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import CalendarXShared struct RootView: View { @@ -21,20 +22,20 @@ struct RootView: View { @StateObject private var settingsVM = SettingsViewModel() + var body: some View { ZStack { - Color.background.padding(.top, -15) + Color.appBackground.padding(.top, -15) content.padding() AlertView(alert: alert).zIndex(1) } - .foregroundColor(.primary) + .appForeground(.appPrimary) .environment(\.locale, settingsVM.locale) .envTint(settingsVM.color) .envColorScheme(settingsVM.colorScheme) .onChange(of: settingsVM.locale, notification: NSLocale.currentLocaleDidChangeNotification) - - + } @ViewBuilder @@ -42,7 +43,7 @@ struct RootView: View { switch router.path { case .main: MainView(viewModel: mainVM) case .settings: SettingsView(viewModel: settingsVM) - case .date(let day): DateView(day: day).fullScreenCover() + case .date(let appDate): DateView(appDate: appDate).fullScreenCover() case .recommendations: RecommendationsView().fullScreenCover() case .menubarSettings: MenubarSettingsView().fullScreenCover() case .appearanceSettings: AppearanceSettingsView(viewModel: settingsVM).fullScreenCover() @@ -51,7 +52,6 @@ struct RootView: View { } } - -} +} diff --git a/CalendarX/Module/MenuBar/MenuBarController.swift b/CalendarX/Module/MenuBar/MenuBarController.swift index b813a0f..2d34f6e 100644 --- a/CalendarX/Module/MenuBar/MenuBarController.swift +++ b/CalendarX/Module/MenuBar/MenuBarController.swift @@ -7,6 +7,8 @@ import AppKit import Combine +import CalendarXShared +import WidgetKit class MenubarController { @@ -20,8 +22,8 @@ class MenubarController { private lazy var monitor = MonitorHelper { [weak self] _ in guard let self else { return } - guard self.popover.isShown else { return } - self.closePopover() + guard popover.isShown else { return } + closePopover() } private var cancellables: Set = [] @@ -42,8 +44,8 @@ extension MenubarController { .publisher(for: .titleStyleDidChanged) .sink { [weak self] _ in guard let self else { return } - self.itemController.updateItem() - self.itemController.updateTask() + itemController.updateItem() + itemController.updateTask() } .store(in: &cancellables) @@ -51,7 +53,7 @@ extension MenubarController { .publisher(for: .NSCalendarDayChanged) .sink{ [weak self] _ in guard let self else { return } - self.itemController.updateItem() + itemController.updateItem() } .store(in: &cancellables) @@ -59,7 +61,7 @@ extension MenubarController { .publisher(for: NSLocale.currentLocaleDidChangeNotification) .sink{ [weak self] _ in guard let self else { return } - self.itemController.updateItem() + itemController.updateItem() } .store(in: &cancellables) @@ -67,8 +69,15 @@ extension MenubarController { .publisher(for: .NSSystemClockDidChange) .sink{ [weak self] _ in guard let self else { return } - self.itemController.updateItem() - self.itemController.updateTask() + itemController.updateItem() + itemController.updateTask() + } + .store(in: &cancellables) + + NotificationCenter.default + .publisher(for: .EKEventStoreChanged) + .sink { _ in + WidgetCenter.shared.reloadAllTimelines() } .store(in: &cancellables) diff --git a/CalendarX/Module/MenuBar/MenubarItemController.swift b/CalendarX/Module/MenuBar/MenubarItemController.swift index 73bdc57..22cb542 100644 --- a/CalendarX/Module/MenuBar/MenubarItemController.swift +++ b/CalendarX/Module/MenuBar/MenubarItemController.swift @@ -6,13 +6,15 @@ // -import Cocoa import Schedule +import SwiftUI +import CalendarXShared class MenubarItemController { - - typealias Task = Cocoa.Task - + + + typealias Task = SwiftUI.Task + private let item: NSStatusBarButton? private let pref = MenubarPreference.shared @@ -64,7 +66,7 @@ class MenubarItemController { private func resumeTask() { task = plan.do { [weak self] in guard let self else { return } - self.updateItem() + updateItem() } } @@ -95,7 +97,7 @@ extension MenubarItemController { } else if style == .text { title = pref.text } else { - title = L10n.dateItemTitle(pref) + title = pref.dateItemTitle } return NSAttributedString(string: title, attributes: attributes) } diff --git a/CalendarX/Module/Settings/AboutView.swift b/CalendarX/Module/Settings/AboutView.swift index 8de7c21..87d88f6 100644 --- a/CalendarX/Module/Settings/AboutView.swift +++ b/CalendarX/Module/Settings/AboutView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import CalendarXShared struct AboutView: View { @@ -14,19 +15,25 @@ struct AboutView: View { TitleView { Text(L10n.Settings.about) - } actions: { - ScacleImageButton(image: .close, action: Router.backSettings) + } leftItems: { + ScacleImageButton(image: .backward, action: Router.backSettings) + } rightItems: { + EmptyView() } - + + Image(nsImage: NSApp.applicationIconImage) - - Text(AppInfo.name).bold() - + + Text(AppBundle.name).bold() + Group { - ScacleButton(action: { NSWorkspace.open(CalLink.gitHub) }) { - Text("GitHub for \(AppInfo.name)") - .foregroundColor(.accentColor) + + ScacleButton { + NSWorkspace.open(AppLink.gitHub) + } label: { + Text("GitHub for \(AppBundle.name)") + .appForeground(.accentColor) .frame(maxWidth: .infinity) .padding(.vertical, 5) .background(Capsule().stroke(Color.accentColor)) @@ -36,7 +43,7 @@ struct AboutView: View { foregroundColor: .white, backgroundColor: .accentColor, action: Updater.checkForUpdates) - + } .font(.caption2) .frame(width: .mainWidth / 2.5) @@ -46,11 +53,11 @@ struct AboutView: View { Spacer() - Text("Copyright © 2020 ZzzM. All rights reserved.") + Text(AppBundle.copyright) } .font(.footnote) - .foregroundColor(.secondary) - + .appForeground(.appSecondary) + } .frame(height: .mainHeight, alignment: .top) } diff --git a/CalendarX/Module/Settings/AppearanceSettingsView.swift b/CalendarX/Module/Settings/AppearanceSettingsView.swift index e82ada7..2a3854d 100644 --- a/CalendarX/Module/Settings/AppearanceSettingsView.swift +++ b/CalendarX/Module/Settings/AppearanceSettingsView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import CalendarXShared struct AppearanceSettingsView: View { @@ -14,13 +15,15 @@ struct AppearanceSettingsView: View { var body: some View { VStack(spacing: 10) { - + TitleView { Text(L10n.Settings.appearance) - } actions: { - ScacleImageButton(image: .close, action: Router.backSettings) + } leftItems: { + ScacleImageButton(image: .backward, action: Router.backSettings) + } rightItems: { + EmptyView() } - + darkSection accentSection @@ -35,12 +38,12 @@ extension AppearanceSettingsView { private var darkSection: some View { Section { Toggle(isOn: $viewModel.isSystem) { Text(L10n.Theme.system) } - .foregroundColor(.secondary) + .appForeground(.appSecondary) .checkboxStyle() if viewModel.isShown { Toggle(isOn: $viewModel.isDark) { Text(L10n.Theme.dark) } - .foregroundColor(.secondary) + .appForeground(.appSecondary) .checkboxStyle() } @@ -55,7 +58,7 @@ extension AppearanceSettingsView { Section { HStack { Text(L10n.Appearance.hex) - .foregroundColor(.secondary) + .appForeground(.appSecondary) Spacer() if #available(macOS 12.0, *) { @@ -63,18 +66,17 @@ extension AppearanceSettingsView { } else { hexLabel } - } - - ScrollView { + + ScrollView(showsIndicators: false) { LazyVGrid(columns: Array(repeating: .init(spacing: 0), count: 3), spacing: 0) { ForEach(Appearance.palettes, id: \.self) { colorRow($0) } } - .cornerRadius(5) + .clipShape(.rect(cornerRadius: 5)) } - + } header: { RowTitleView(title: L10n.Appearance.tint, font: .title3) } @@ -107,8 +109,8 @@ extension AppearanceSettingsView { .frame(height: 20) .padding(.horizontal, 3) .background(Color.accentColor) - .foregroundColor(.white) - .cornerRadius(5) + .appForeground(.white) + .clipShape(.rect(cornerRadius: 5)) } } diff --git a/CalendarX/Module/Settings/CalendarSettingsView.swift b/CalendarX/Module/Settings/CalendarSettingsView.swift index 55e1a4e..14df8f1 100644 --- a/CalendarX/Module/Settings/CalendarSettingsView.swift +++ b/CalendarX/Module/Settings/CalendarSettingsView.swift @@ -7,6 +7,7 @@ import SwiftUI import Combine +import CalendarXShared struct CalendarSettingsView: View { @@ -15,12 +16,17 @@ struct CalendarSettingsView: View { var body: some View { VStack(spacing: 20) { - + + TitleView { Text(L10n.Settings.calendar) - } actions: { - ScacleImageButton(image: .close, action: Router.backSettings) + } leftItems: { + ScacleImageButton(image: .backward, action: Router.backSettings) + } rightItems: { + EmptyView() } + + Section { weekRow @@ -38,7 +44,7 @@ extension CalendarSettingsView { private var weekRow: some View { SettingsPickerRow(title: L10n.Calendar.startWeekOn, - items: CalWeekday.allCases, + items: AppWeekday.allCases, selection: $viewModel.weekday) { Text($0.description) } } diff --git a/CalendarX/Module/Settings/MenuBarSettingsView.swift b/CalendarX/Module/Settings/MenuBarSettingsView.swift index e9b96d7..829130f 100644 --- a/CalendarX/Module/Settings/MenuBarSettingsView.swift +++ b/CalendarX/Module/Settings/MenuBarSettingsView.swift @@ -7,6 +7,7 @@ import SwiftUI import Combine +import CalendarXShared struct MenubarSettingsView: View { @@ -17,17 +18,26 @@ struct MenubarSettingsView: View { var body: some View { VStack(spacing: 10) { - + TitleView { Text(L10n.Settings.menubarStyle) - } actions: { - ScacleImageButton(image: .close, action: Router.backSettings) + } leftItems: { + ScacleImageButton(image: .backward, action: Router.backSettings) + } rightItems: { + if viewModel.canSave { + ScacleImageButton(image: .save, action: viewModel.save) + } } - - SegmentedPicker(tabs: MenubarStyle.allCases, selection: $viewModel.style) { - Text($0.title) + + Picker(selection: $viewModel.style) { + ForEach(MenubarStyle.allCases, id: \.self) { + Text($0.title) + } + } label: { + EmptyView() } - + .pickerStyle(.segmented) + ZStack { switch viewModel.style { case .default: DefaultStyleView() @@ -37,15 +47,6 @@ struct MenubarSettingsView: View { } .frame(maxHeight: .infinity) - - ScacleCapsuleButton(title: L10n.MenubarStyle.save, - foregroundColor: .white, - backgroundColor: viewModel.disabled ? .disable: .accentColor, - action: viewModel.save) - .frame(width: .mainWidth/2) - .disabled(viewModel.disabled) - - } .focusable(false) @@ -56,8 +57,7 @@ struct MenubarSettingsView: View { struct DefaultStyleView: View { var body: some View { - Image.calendar.sideLength(30) - + Image.calendar.sideLength(40) Text(Date().day.description) .font(.title3) .offset(y: 5) @@ -72,20 +72,22 @@ struct TextStyleView: View { var body: some View { VStack { - - Text(text).font(.title3).frame(height: 30) - - TextField(AppInfo.name, text: $text.max()) + + Text(text) + .font(.title3) + .frame(height: 30) + .padding() + + TextField(AppBundle.name, text: $text.max()) .textFieldStyle(.plain) .multilineTextAlignment(.center) - - + Divider().padding(.horizontal) Text(L10n.MenubarStyle.tips) .font(.footnote) - .foregroundColor(.secondary) - + .appForeground(.appSecondary) + } } } @@ -101,71 +103,68 @@ struct DateStyleView: View { Text(viewModel.dateTitle) .font(.title3) - .padding(.vertical, 5) - + .padding(.vertical) + ScrollView { - gridView(tags: viewModel.shownTags, - background: .tagBackground, + gridView(types: viewModel.shownTypes, + background: Color.tagBackground, onTapGesture: viewModel.shownTagTapped, onDrop: viewModel.onDrop) - gridView(tags: viewModel.hiddenTags, + gridView(types: viewModel.hiddenTypes, background: .disable, onTapGesture: viewModel.hiddenTagTapped) Toggle(isOn: $viewModel.use24h) { Text(L10n.MenubarStyle.use24).font(.title3) } .checkboxStyle() - .padding(.top, 5) - + .padding(.top) + Toggle(isOn: $viewModel.showSeconds) { Text(L10n.MenubarStyle.showSeconds).font(.title3) } .checkboxStyle() } - - + } } - - private func gridView(tags: [DTTag], + private func gridView(types: [DTType], background: Color, - onTapGesture: @escaping (DTTag) -> Void, - onDrop: ((NSItemProvider?, Int) -> Bool)? = .none) -> some View { - + onTapGesture: @escaping (DTType) -> Void, + onDrop: ((NSItemProvider?, DTType) -> Bool)? = .none) -> some View { + LazyVGrid(columns: .init(repeating: .init(), count: 4)) { - ForEach(tags, id: \.element) { tag in - + ForEach(types, id: \.self) { type in if onDrop != nil { - tagView(tag, foregroundColor: .accentColor, background: background, onTapGesture: onTapGesture) - .onDrag { viewModel.onDrag(tag.offset) } - .onDrop(of: [.utf8PlainText], isTargeted: .none) { - onDrop! ($0.first, tag.offset) + tagView(type, foregroundColor: .white, background: background, onTapGesture: onTapGesture) + .onDrag { viewModel.onDrag(type) } + .onDrop(of: [.text], isTargeted: .none) { + onDrop! ($0.first, type) } } else { - tagView(tag, foregroundColor: .white, background: background, onTapGesture: onTapGesture) - .onDrag { viewModel.onDrag(tag.offset) } + tagView(type, foregroundColor: .white, background: background, onTapGesture: onTapGesture) + .onDrag { viewModel.onDrag(type) } } } } } - private func tagView(_ tag: DTTag, + private func tagView(_ type: DTType, foregroundColor: Color, background: Color, - onTapGesture: @escaping (DTTag) -> Void) -> some View { - - Text(viewModel.tagTitle(tag.element)) + onTapGesture: @escaping (DTType) -> Void) -> some View { + + Text(viewModel.tagTitle(type)) .lineLimit(1) .minimumScaleFactor(0.1) .frame(width: 55) .padding(5) .background(background) - .foregroundColor(foregroundColor) - .clipShape(Capsule()) + .appForeground(foregroundColor) + .clipShape(.capsule) .onTapGesture { - onTapGesture(tag) + onTapGesture(type) } } diff --git a/CalendarX/Module/Settings/RecommendationsView.swift b/CalendarX/Module/Settings/RecommendationsView.swift index 1ca76b4..331326b 100644 --- a/CalendarX/Module/Settings/RecommendationsView.swift +++ b/CalendarX/Module/Settings/RecommendationsView.swift @@ -6,20 +6,24 @@ // import SwiftUI +import CalendarXShared struct RecommendationsView: View { - - private let apps: [CalApp] = Bundle.main.json2Object(from: "apps") ?? [] - + + private let apps = Bundle.apps + var body: some View { VStack { TitleView { Text(L10n.Settings.recommendations) - } actions: { - ScacleImageButton(image: .close, action: Router.backSettings) + } leftItems: { + ScacleImageButton(image: .backward, action: Router.backSettings) + } rightItems: { + EmptyView() } + ScrollView { @@ -36,8 +40,8 @@ struct RecommendationsView: View { struct AppView: View { - let app: CalApp - + let app: AppInfo + var body: some View { HStack { Image(app.name).resizable().sideLength(60) @@ -48,15 +52,18 @@ struct AppView: View { ScacleButton { NSWorkspace.open(app.link) } label: { - Image.gitHub.sideLength(15).foregroundColor(.secondary) + Image.gitHub.sideLength(15) + .appForeground(.appSecondary) } + .hoverEffect + } - Text(app.about).font(.caption2).foregroundColor(.secondary).lineLimit(2) + Text(app.about).font(.caption2).appForeground(.appSecondary).lineLimit(2) } } .padding(5) .background(Color.card) - .cornerRadius(5) + .clipShape(.rect(cornerRadius: 5)) .shadow(radius: 1, x: 1, y: 1) .padding(.horizontal, 3) @@ -65,7 +72,3 @@ struct AppView: View { } } -struct CalApp: Decodable, Identifiable { - var id: String { name } - let name: String, about: String, link: String -} diff --git a/CalendarX/Module/Settings/SettingsView.swift b/CalendarX/Module/Settings/SettingsView.swift index 1824d23..4848dc1 100644 --- a/CalendarX/Module/Settings/SettingsView.swift +++ b/CalendarX/Module/Settings/SettingsView.swift @@ -7,6 +7,7 @@ import SwiftUI import Combine +import CalendarXShared struct SettingsView: View { @@ -16,9 +17,15 @@ struct SettingsView: View { var body: some View { VStack(spacing: 15) { - - TitleView { Text( L10n.Settings.title) } actions: { - ScacleImageButton(image: .power, action: viewModel.exit) + + TitleView { + Text( L10n.Settings.title).onTapGesture { + Router.backMain() + } + } leftItems: { + EmptyView() + } rightItems: { + ScacleImageButton(image: .quit, action: viewModel.exit) } Section { @@ -37,7 +44,7 @@ struct SettingsView: View { .frame(height: .mainHeight, alignment: .top) } - + } extension SettingsView { @@ -49,13 +56,13 @@ extension SettingsView { var calendarRow: some View { SettingsRow(title: L10n.Settings.calendar, detail: {}, action: Router.toCalendarSettings) } - + var languageRow: some View { SettingsPickerRow(title: L10n.Settings.language, - items: Language.allCases, width: 60, - selection: $viewModel.language) { Text($0.title) } + items: Language.allCases, width: 70, + selection: $viewModel.language) { Text($0.title) } } - + var memubarRow: some View { SettingsRow(title: L10n.Settings.menubarStyle, detail: {Text(viewModel.menubarStyle.title) }, @@ -63,7 +70,7 @@ extension SettingsView { } var launchRow: some View { - CalToggle { Text(L10n.Settings.launchAtLogin).font(.title3) } + AppToggle { Text(L10n.Settings.launchAtLogin).font(.title3) } .checkboxStyle() } @@ -96,7 +103,7 @@ extension SettingsView { Text(L10n.Settings.version) + Text(Updater.version) } .font(.footnote) - .foregroundColor(.accentColor) + .appForeground(.accentColor) } } @@ -129,14 +136,13 @@ struct SettingsRow: View { Group { detail() if showArrow { - Image.rightArrow + Image.rightArrow.font(.title3) } - } - .foregroundColor(.secondary) - + .appForeground(.appSecondary) + } - .contentShape(Rectangle()) + .contentShape(.rect) .onTapGesture(perform: action) } @@ -183,7 +189,7 @@ struct SettingsPickerRow: View { isPresented: $isPresented, label: { HStack { - itemLabel(selection).foregroundColor(.secondary) + itemLabel(selection).appForeground(.appSecondary) RotationArrow(isPresented: $isPresented) } }, itemLabel: itemLabel) diff --git a/CalendarX/Service/L10n.swift b/CalendarX/Service/L10n.swift deleted file mode 100644 index 42b95a3..0000000 --- a/CalendarX/Service/L10n.swift +++ /dev/null @@ -1,187 +0,0 @@ -// -// L10n.swift -// CalendarX -// -// Created by zm on 2022/3/30. -// - -import Foundation -import SwiftUI - -typealias CalDate = Date - -struct L10n { - - private static let formatter = DateFormatter() - - private static var locale: Locale { Preference.shared.locale } - - static var inChinese: Bool { locale.inChinese } - - enum Settings { - static let title = "settings.title".l10nKey - static let appearance = "settings.appearance".l10nKey - static let calendar = "settings.calendar".l10nKey - static let auto = "settings.auto".l10nKey - static let language = "settings.language".l10nKey - static let recommendations = "settings.recommendations".l10nKey - static let menubarStyle = "settings.menubarStyle".l10nKey - static let launchAtLogin = "settings.launchAtLogin".l10nKey - static let version = "settings.version".l10nKey - static let checkForUpdates = "settings.checkForUpdates".l10nKey - static let about = "settings.about".l10nKey - } - - enum Calendar { - static let showEvents = "calendar.showEvents".l10nKey - static let startWeekOn = "calendar.startWeekOn".l10nKey - static let showLunar = "calendar.showLunar".l10nKey - static let showHolidays = "calendar.showHolidays".l10nKey - } - - enum Appearance { - static let hex = "appearance.hex".l10nKey - static let tint = "appearance.tint".l10nKey - } - - enum Alert { - static let exit = "alert.exit".l10nKey - static let notifications = "alert.notifications".l10nKey - static let calendars = "alert.calendars".l10nKey - - static let exitMessage = "alert.exitMessage".l10nKey - static let notificationsMessage = "alert.notificationsMessage".l10nKey - static let calendarsMessage = "alert.calendarsMessage".l10nKey - - static let ok = "alert.ok".l10nKey - static let yes = "alert.yes".l10nKey - static let no = "alert.no".l10nKey - - } - - enum Theme { - static let system = "theme.system".l10nKey - static let dark = "theme.dark".l10nKey - static let light = "theme.light".l10nKey - } - - enum Language { - static let system = "theme.system".l10nKey - static let en_US = "English".l10nKey - static let zh_CN = "简体中文".l10nKey - } - - enum MenubarStyle { - static let `default` = "menubarStyle.default".l10nKey - static let text = "menubarStyle.text".l10nKey - static let date = "menubarStyle.date".l10nKey - static let tips = "menubarStyle.tips".l10nKey - static let save = "menubarStyle.save".l10nKey - static let use24 = "menubarStyle.use24".l10nKey - static let showSeconds = "menubarStyle.showSeconds".l10nKey - } - - enum Date { - static let allDay = "date.allDay".l10nKey - static let events = "date.events".l10nKey - static let noEvents = "date.noEvents".l10nKey - } - - enum Updater { - static var available: String { "updater.available".localized(bundle) } - static func update(_ version: String) -> String { "updater.update".localized(bundle, args: version) } - } - -} - -extension L10n { - - static func timeline(from date: CalDate) -> String { - formatter.locale = .posix - formatter.dateFormat = "yyyy-MM-dd HH:mm" - return formatter.string(from: date) - } - - static func shortWeekday(from date: CalDate) -> String { - formatter.locale = locale - return inChinese ? formatter.veryShortWeekdaySymbols[date.weekday - 1] : - formatter.shortWeekdaySymbols[date.weekday - 1] - } - - static func monthSymbol(from month: Int) -> String { - formatter.locale = locale - return formatter.shortMonthSymbols[month - 1] - } - - static func weekdaySymbol(from weekday: CalWeekday) -> String { - formatter.locale = locale - return formatter.shortWeekdaySymbols[weekday.rawValue - 1] - } - - - static func dateItemTitle(_ pref: MenubarPreference) -> String { - let date = CalDate(), types = pref.shownTypes, - use24h = pref.use24h, showSeconds = pref.showSeconds - - return dateTitle(types: types) { - switch $0 { - case .lm: return date.lunarMonthString - case .ld: return date.lunarDayString - case .sm: - return monthSymbol(from: date.month) - case .sd: - formatter.locale = locale - formatter.dateFormat = L10n.inChinese ? "d日":"d" - return formatter.string(from: date) - case .e: - formatter.locale = locale - formatter.dateFormat = "E" - return formatter.string(from: date) - case .a: - formatter.locale = locale - formatter.dateFormat = "a" - return formatter.string(from: date) - case .t: - formatter.locale = .posix - formatter.dateFormat = (use24h ? "HH:mm":"h:mm") + (showSeconds ? ":ss":"") - return formatter.string(from: date) - } - } - } - - - static func dateTitle(types: [DTType], map: (DTType) -> String) -> String { - guard let type = types.first else { return AppInfo.name } - var titleArray = [map(type)] - for (index, type) in types.enumerated() { - guard index > 0 else { continue } - var title = map(type) - if inChinese { - let preIndex = index - 1, preType = types[preIndex] - if (type == .ld && preType == .lm) || - (type == .sd && preType == .sm) { - title = titleArray[preIndex] + title - titleArray[preIndex] = "" - } - } - titleArray.append(title) - } - return titleArray.joined(separator: " ") - } - -} - -extension L10n { - static var bundle: Bundle { - let fileName = { - switch locale { - case .zh: return "zh-Hans" - case .en: return "en" - default: return "zh-Hans" - } - } - guard let path = Bundle.main.path(forResource: fileName(), ofType: "lproj") else { return .main } - return Bundle(path: path) ?? .main - } -} - diff --git a/CalendarX/Service/LaunchHelper.swift b/CalendarX/Service/LaunchHelper.swift index a1fc7d0..b69f9c1 100644 --- a/CalendarX/Service/LaunchHelper.swift +++ b/CalendarX/Service/LaunchHelper.swift @@ -6,7 +6,7 @@ // import LaunchAtLogin -typealias CalToggle = LaunchAtLogin.Toggle +typealias AppToggle = LaunchAtLogin.Toggle struct LaunchHelper { static func migrateIfNeeded() { diff --git a/CalendarX/Service/Updater.swift b/CalendarX/Service/Updater.swift index 38b8c05..33e2dba 100644 --- a/CalendarX/Service/Updater.swift +++ b/CalendarX/Service/Updater.swift @@ -8,11 +8,12 @@ import Sparkle import UserNotifications import Cocoa +import CalendarXShared class Updater: NSObject { - static let version = " \(AppInfo.version) ( \(AppInfo.commitHash) ) " - + static let version = " \(AppBundle.version) ( \(AppBundle.commitHash) ) " + private static let UpdateNotificationId = "UpdateNotificationId" private static let shared = Updater() diff --git a/CalendarX/ViewModel/AlertAction.swift b/CalendarX/ViewModel/AlertAction.swift index e356f0b..bff6558 100644 --- a/CalendarX/ViewModel/AlertAction.swift +++ b/CalendarX/ViewModel/AlertAction.swift @@ -6,6 +6,7 @@ // import SwiftUI import Combine +import CalendarXShared class AlertAction: ObservableObject { @@ -16,6 +17,7 @@ class AlertAction: ObservableObject { var title: LocalizedStringKey = "", message: LocalizedStringKey = "", + image: Image = .info, no: LocalizedStringKey = L10n.Alert.no, yes: LocalizedStringKey = L10n.Alert.yes, action: VoidClosure = {} @@ -27,13 +29,13 @@ class AlertAction: ObservableObject { .publisher(for: NSPopover.didCloseNotification) .sink{ [weak self] _ in guard let self else { return } - self.dismiss() + dismiss() } .store(in: &cancellables) } static func exit() { - shared.title = L10n.Alert.exit + shared.image = .info shared.message = L10n.Alert.exitMessage shared.yes = L10n.Alert.yes shared.action = { NSApp.terminate(.none) } @@ -41,7 +43,7 @@ class AlertAction: ObservableObject { } static func enableNotifications() { - shared.title = L10n.Alert.notifications + shared.image = .privacy shared.message = L10n.Alert.notificationsMessage shared.yes = L10n.Alert.ok shared.action = { NSWorkspace.openPreference(Privacy.notifications); shared.dismiss() } @@ -50,7 +52,7 @@ class AlertAction: ObservableObject { } static func enableCalendars() { - shared.title = L10n.Alert.calendars + shared.image = .privacy shared.message = L10n.Alert.calendarsMessage shared.yes = L10n.Alert.ok shared.action = { NSWorkspace.openPreference(Privacy.calendars); shared.dismiss() } @@ -58,14 +60,18 @@ class AlertAction: ObservableObject { } func dismiss() { - withAnimation { - isPresented = false + Task { @MainActor in + withAnimation { + isPresented = false + } } } private func show() { - withAnimation { - isPresented = true + Task { @MainActor in + withAnimation { + isPresented = true + } } } diff --git a/CalendarX/ViewModel/CalendarViewModel.swift b/CalendarX/ViewModel/CalendarViewModel.swift index ce2e1c1..97d5569 100644 --- a/CalendarX/ViewModel/CalendarViewModel.swift +++ b/CalendarX/ViewModel/CalendarViewModel.swift @@ -7,6 +7,7 @@ import SwiftUI import Combine +import CalendarXShared class CalendarViewModel: ObservableObject { diff --git a/CalendarX/ViewModel/MainViewModel.swift b/CalendarX/ViewModel/MainViewModel.swift index bea0caa..78edadd 100644 --- a/CalendarX/ViewModel/MainViewModel.swift +++ b/CalendarX/ViewModel/MainViewModel.swift @@ -6,6 +6,8 @@ // import SwiftUI +import Combine +import CalendarXShared class MainViewModel: ObservableObject { @@ -18,9 +20,9 @@ class MainViewModel: ObservableObject { @Published var date: Date - - var weekday: CalWeekday { calendarPref.weekday } - + + var weekday: AppWeekday { calendarPref.weekday } + var showEvents: Bool { calendarPref.showEvents } var showLunar: Bool { calendarPref.showLunar } @@ -30,7 +32,7 @@ class MainViewModel: ObservableObject { var colorScheme: ColorScheme? { pref.colorScheme } var tint: Color { pref.color } - + init() { date = Date() interval = Date().timeIntervalSince1970 @@ -58,4 +60,5 @@ class MainViewModel: ObservableObject { date = Date() } + } diff --git a/CalendarX/ViewModel/MenubarViewModel.swift b/CalendarX/ViewModel/MenubarViewModel.swift index a02d3a7..90507bb 100644 --- a/CalendarX/ViewModel/MenubarViewModel.swift +++ b/CalendarX/ViewModel/MenubarViewModel.swift @@ -6,51 +6,52 @@ // import SwiftUI +import CalendarXShared class MenubarViewModel: ObservableObject { private let pref = MenubarPreference.shared - + @Published var style = MenubarPreference.shared.style - + // Text Style @Published var text = MenubarPreference.shared.text - + // Date&Time Style - + // Use a 24-hour clock @Published var use24h = MenubarPreference.shared.use24h - + //Display the time with seconds @Published var showSeconds = MenubarPreference.shared.showSeconds - + @Published - private var shownTypes = MenubarPreference.shared.shownTypes - + var shownTypes = MenubarPreference.shared.shownTypes + @Published - private var hiddenTypes = MenubarPreference.shared.hiddenTypes - - var shownTags: [DTTag] { Array(shownTypes.enumerated()) } - - var hiddenTags: [DTTag] { Array(hiddenTypes.enumerated()) } - + var hiddenTypes = MenubarPreference.shared.hiddenTypes + + // var shownTags: [DTTag] { shownTypes.enumerated().map{ .init(offset: $0.offset, element: $0.element) } } + // + // var hiddenTags: [DTTag] { hiddenTypes.enumerated().map{ .init(offset: $0.offset, element: $0.element) } } + var dateTitle: String { - L10n.dateTitle(types: shownTypes) { tagTitle($0) } + pref.dateTitle(types: shownTypes) { tagTitle($0) } } - - var disabled: Bool { + + var canSave: Bool { switch style { - case .text: return text.isEmpty - default: return false + case .text: return !text.isEmpty + default: return true } } - + func save() { - + if style == .date { pref.showSeconds = showSeconds pref.use24h = use24h @@ -60,16 +61,15 @@ class MenubarViewModel: ObservableObject { else if style == .text { pref.text = text } - + pref.style = style - + Router.backSettings() - + NotificationCenter.default.post(name: .titleStyleDidChanged, object: .none) } - - + } //MARK: Date&Time Style @@ -86,56 +86,51 @@ extension MenubarViewModel { case .t: return (use24h ? "20:30":"8:30") + (showSeconds ? ":30":"") //d 24, e sec } } - - func shownTagTapped(_ tag: DTTag) { + + func shownTagTapped(_ type: DTType) { guard shownTypes.count > 1 else { return } Task { @MainActor in - guard shownTypes.indices ~= tag.offset else { return } - withAnimation { - shownTypes.remove(at: tag.offset) - hiddenTypes.append(tag.element) - } + guard let index = shownTypes.firstIndex(of: type) else { return } + shownTypes.remove(at: index) + hiddenTypes.append(type) } } - - func hiddenTagTapped(_ tag: DTTag) { + + func hiddenTagTapped(_ type: DTType) { Task { @MainActor in - guard hiddenTypes.indices ~= tag.offset else { return } - withAnimation { - hiddenTypes.remove(at: tag.offset) - shownTypes.append(tag.element) - } + guard let index = hiddenTypes.firstIndex(of: type) else { return } + hiddenTypes.remove(at: index) + shownTypes.append(type) } } - - func onDrop(provider: NSItemProvider?, to: Int) -> Bool { - - provider?.loadObject(ofClass: NSString.self) { reading, error in - - guard let reading = reading as? String else { return } - guard let obj = reading.toObject(DTIndex.self) else { return } - - Task { @MainActor in - withAnimation(.easeInOut) { - let isShown = obj.isShown, from = obj.index - - if isShown { - self.shownTypes.move(fromOffsets: IndexSet(integer: from), toOffset: to > from ? (to + 1): to) - } else { - let type = self.hiddenTypes[from] - self.shownTypes.insert(type, at: to) - self.hiddenTypes.remove(at: from) - } + + func onDrop(provider: NSItemProvider?, type: DTType) -> Bool { + + provider?.loadObject(ofClass: NSString.self) { [weak self] reading, error in + + guard let typeRawValue = reading as? String else { return } + + Task { @MainActor [weak self] in + + guard let self else { return } + guard let to = shownTypes.firstIndex(of: type) else { return } + + if let from = shownTypes.firstIndex(where: { typeRawValue == $0.rawValue }) { + shownTypes.move(fromOffsets: IndexSet(integer: from), toOffset: to > from ? (to + 1): to) } + else if let from = hiddenTypes.firstIndex(where: { typeRawValue == $0.rawValue }) { + let type = hiddenTypes[from] + shownTypes.insert(type, at: to) + hiddenTypes.remove(at: from) + } + } } - return false } - - func onDrag(_ index: Int) -> NSItemProvider { - NSItemProvider(object: #"{"isShown":true,"index":\#(index)}"# as NSString) + + func onDrag(_ type: DTType) -> NSItemProvider { + return NSItemProvider(object: type.rawValue as NSString) } - } diff --git a/CalendarX/ViewModel/Router.swift b/CalendarX/ViewModel/Router.swift index 9e241b8..9586819 100644 --- a/CalendarX/ViewModel/Router.swift +++ b/CalendarX/ViewModel/Router.swift @@ -6,13 +6,14 @@ // import SwiftUI +import CalendarXShared class Router: ObservableObject { static let shared = Router() enum Path { - case main, date(CalDay), settings, + case main, date(AppDate), settings, recommendations, menubarSettings, appearanceSettings, calendarSettings, about } @@ -37,7 +38,7 @@ extension Router { static func backMain() { to(.main) } - static func toDate(_ day: CalDay) { to(.date(day)) } + static func toDate(_ appDate: AppDate) { to(.date(appDate)) } } extension Router { diff --git a/CalendarX/ViewModel/SettingsViewModel.swift b/CalendarX/ViewModel/SettingsViewModel.swift index 3591664..cd24c7c 100644 --- a/CalendarX/ViewModel/SettingsViewModel.swift +++ b/CalendarX/ViewModel/SettingsViewModel.swift @@ -5,9 +5,9 @@ // Created by zm on 2023/2/17. // -import AppKit import SwiftUI import Combine +import CalendarXShared class SettingsViewModel: ObservableObject { @@ -68,14 +68,17 @@ class SettingsViewModel: ObservableObject { .sink{ [weak self] _ in guard let self else { return } if Updater.isAuthorized { return } - guard self.automaticallyChecksForUpdates else { return } - self.automaticallyChecksForUpdates = false + guard automaticallyChecksForUpdates else { return } + automaticallyChecksForUpdates = false } .store(in: &cancellables) } - func exit() { AlertAction.exit() } + func exit() { + AlertAction.exit() + //NSApp.terminate(.none) + } func openPreference() { } } diff --git a/CalendarX/en.lproj/Localizable.strings b/CalendarX/en.lproj/Localizable.strings index 9890316..c37f9b8 100644 --- a/CalendarX/en.lproj/Localizable.strings +++ b/CalendarX/en.lproj/Localizable.strings @@ -19,10 +19,10 @@ "calendar.showLunar" = "Show lunar calendar"; "calendar.showHolidays" = "Show Chinese statutory holidays"; -"calendar.showEvents" = "Display calendar events"; +"calendar.showEvents" = "Show calendar events"; "calendar.startWeekOn" = "Start week on"; -"appearance.tint" = "Accent color"; +"appearance.tint" = "Tint"; "appearance.hex" = "Color hex code"; "alert.exit" = "Exit"; diff --git a/CalendarX/zh-Hans.lproj/Localizable.strings b/CalendarX/zh-Hans.lproj/Localizable.strings index 7aebe4f..363caa8 100644 --- a/CalendarX/zh-Hans.lproj/Localizable.strings +++ b/CalendarX/zh-Hans.lproj/Localizable.strings @@ -22,7 +22,7 @@ "calendar.showEvents" = "显示日历事件"; "calendar.startWeekOn" = "星期开始于"; -"appearance.tint" = "强调色"; +"appearance.tint" = "色彩"; "appearance.hex" = "颜色十六进制编码"; "alert.exit" = "退出"; diff --git a/CalendarXShared/.gitignore b/CalendarXShared/.gitignore new file mode 100644 index 0000000..0023a53 --- /dev/null +++ b/CalendarXShared/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +/.build +/Packages +xcuserdata/ +DerivedData/ +.swiftpm/configuration/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/CalendarXShared/Package.swift b/CalendarXShared/Package.swift new file mode 100644 index 0000000..6c378ae --- /dev/null +++ b/CalendarXShared/Package.swift @@ -0,0 +1,25 @@ +// swift-tools-version: 5.9 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "CalendarXShared", + platforms: [ + .macOS(.v11) + ], + products: [ + .library( + name: "CalendarXShared", + targets: ["CalendarXShared"]), + ], + targets: [ + .target( + name: "CalendarXShared", + path: "Sources", + resources: [ + .process("Resources") + ] + ) + ] +) diff --git a/CalendarX/Constant.swift b/CalendarXShared/Sources/Constant.swift similarity index 50% rename from CalendarX/Constant.swift rename to CalendarXShared/Sources/Constant.swift index 652cca2..32de0ab 100644 --- a/CalendarX/Constant.swift +++ b/CalendarXShared/Sources/Constant.swift @@ -9,79 +9,92 @@ import AppKit import SwiftUI -typealias VoidClosure = () -> Void -typealias FailureClosure = (Error) -> Void +public typealias VoidClosure = () -> Void +public typealias FailureClosure = (Error) -> Void -extension CGFloat { +public extension CGFloat { static let mainHeight: CGFloat = 300 static let mainWidth: CGFloat = 320 - static let popoverWidth: CGFloat = 35 - static let popoverHeight: CGFloat = 150 - static let popoverRowHeight: CGFloat = 20 + static let popoverWidth: CGFloat = 40 + static let popoverHeight: CGFloat = 210 + static let popoverRowHeight: CGFloat = 25 static let buttonWidth: CGFloat = 35 } -extension UserDefaults { - static let group = UserDefaults(suiteName: "group.\(AppInfo.identifier)") +extension Bundle { + public static let apps: [AppInfo] = module.json2Object(from: "apps") ?? [] + static let tiaoxiu: [String: [String: AppDateState]] = module.json2KeyValue(from: "tiaoxiu") + static let solarAF = module.json2AllFestivals(from: "solarAF") // Contains solarPF + static let weekAF = module.json2AllFestivals(from: "weekAF") + static let weekSF = module.json2Festival(from: "weekSF") + static let solarPF = module.json2Festival(from: "solarPF") + static let weekPF = module.json2Festival(from: "weekPF") + static let lunarPF = module.json2Festival(from: "lunarPF") + static let chuxi = module.json2Festival(from: "chuxi") + static let terms = module.json2AllFestivals(from: "terms") } +public extension UserDefaults { + static let group = UserDefaults(suiteName: "group.\(AppBundle.identifier)") +} enum AppStorageKey { static let theme = generate("theme") static let tint = generate("tint") static let language = generate("language") - private static func generate(_ key: String) -> String { "\(AppInfo.name).app.\(key)" } + private static func generate(_ key: String) -> String { "\(AppBundle.name).app.\(key)" } } -enum MenubarStorageKey { - static let style = generate("style") - static let text = generate("text") - static let use24h = generate("use24h") - static let showSeconds = generate("showSeconds") - static let shownTypes = generate("shownTypes") - static let hiddenTypes = generate("hiddenTypes") - private static func generate(_ key: String) -> String { "\(AppInfo.name).menubar.\(key)" } +public enum MenubarStorageKey { + public static let style = generate("style") + public static let text = generate("text") + public static let use24h = generate("use24h") + public static let showSeconds = generate("showSeconds") + public static let shownTypes = generate("shownTypes") + public static let hiddenTypes = generate("hiddenTypes") + private static func generate(_ key: String) -> String { "\(AppBundle.name).menubar.\(key)" } } -enum CalendarStorageKey { - static let weekday = generate("weekday") - static let showEvents = generate("showEvents") - static let showLunar = generate("showLunar") - static let showHolidays = generate("showHolidays") - private static func generate(_ key: String) -> String { "\(AppInfo.name).calendar.\(key)" } +public enum CalendarStorageKey { + public static let weekday = generate("weekday") + public static let showEvents = generate("showEvents") + public static let showLunar = generate("showLunar") + public static let showHolidays = generate("showHolidays") + private static func generate(_ key: String) -> String { "\(AppBundle.name).calendar.\(key)" } } -extension NSFont { +public extension NSFont { static let statusItem = NSFont.monospacedDigitSystemFont(ofSize: 13, weight: .regular) static let statusIcon = NSFont.monospacedDigitSystemFont(ofSize: 8.5, weight: .regular) } -extension Image { - static let power = Image(systemName: "power") - static let settings = Image(systemName: "gearshape.fill") - static let warning = Image(systemName: "exclamationmark.circle.fill") - static let failure = Image(systemName: "xmark.circle.fill") - static let success = Image(systemName: "checkmark.circle.fill") - static let close = Image(systemName: "xmark") +public extension Image { + + static let quit = Image(systemName: "escape") + static let backward = Image(systemName: "arrow.backward") + static let info = Image(systemName: "text.bubble") + static let privacy = Image(systemName: "exclamationmark.shield") static let clock = Image(systemName: "clock.fill") static let leftArrow = Image(systemName: "chevron.left") static let rightArrow = Image(systemName: "chevron.right") static let circle = Image(systemName: "circle") static let recommend = Image(systemName: "hand.thumbsup.fill") + static let save = Image(systemName: "checkmark") + static let gitHub = Image("GitHub").renderingMode(.template).resizable() static let calendar = Image("Calendar").renderingMode(.template).resizable() } -extension NSImage { +public extension NSImage { static let calendar = NSImage(named: "Calendar")! } -extension Calendar { +public extension Calendar { static let gregorian = Calendar(identifier: .gregorian) static let chinese = Calendar(identifier: .chinese) } -extension Locale { +public extension Locale { static let en = Locale(identifier: "en_US") static let zh = Locale(identifier: "zh_CN") static let posix = Locale(identifier: "en_US_POSIX") @@ -89,46 +102,50 @@ extension Locale { -extension Color { - - static let background = Color(light: "FEF9EF", dark: "323232") +public extension Color { + + static let appBackground = Color(light: "FEF9EF", dark: "323232") + static let appPrimary = Color(light: "555555", dark: "EEEEEE") + static let appSecondary = Color(light: "8f8f8f", dark: "777777") + static let card = Color(light: "F6F6EE", dark: "393939") - static let primary = Color(light: "555555", dark: "EEEEEE") - static let secondary = Color(light: "8f8f8f", dark: "777777") - - static let workdayBackground = Color.secondary.opacity(0.16) - static let tagBackground = Color.accentColor.opacity(0.12) + + static let workBackground = Color.secondary.opacity(0.16) + static let offBackground = Color.accentColor.opacity(0.12) + + static let tagBackground = Color.accentColor.opacity(0.6) static let disable = Color.secondary.opacity(0.6) } -extension NSNotification.Name { +public extension NSNotification.Name { static let titleStyleDidChanged = NSNotification.Name("titleStyleDidChanged") } -struct CalLink { - static let gitHub = "https://github.com/ZzzM/CalendarX" +public struct AppLink { + public static let gitHub = "https://github.com/ZzzM/CalendarX" } -struct Privacy { - static let calendars = "com.apple.preference.security?Privacy_Calendars" - static let notifications = "com.apple.preference.notifications" +public struct Privacy { + public static let calendars = "com.apple.preference.security?Privacy_Calendars" + public static let notifications = "com.apple.preference.notifications" } -struct Appearance { - - static let tint = palettes[0][0] - - static let palettes = [ +public struct Appearance { + + public static let tint = palettes[0][0] + + public static let palettes = [ ["C72C41", "E97777", "EE4540"], ["4C3575", "5B4B8A", "7858A6"], ["205295", "42C2FF", "2C74B3"], ["A1B57D", "519872", "A4B494"], ["AA2B1D", "CC561E", "F07B3F"], ["876445", "CA965C", "847545"], ["F1CA89", "A1CAE2", "B25068"], ["704F4F", "AD8B73", "A77979"], ["00A8CC", "1F8A70", "A61F69"], ["03C988", "007880", "E0C341"], ["4A89DC", "D770AD", "1363DF"], ["CD4DCC", "59CE8F", "6D67E4"] ] + } -struct Lunar { +public struct Lunar { //zi 子 rat //chou 丑 ox @@ -154,30 +171,30 @@ struct Lunar { //Ren //Gui - static let heavenlyStems = [ + public static let heavenlyStems = [ "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸" ] - static let earthlyBranches = [ + public static let earthlyBranches = [ "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥" ] - static let zodiacs = [ + public static let zodiacs = [ "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪" ] - static let months = [ + public static let months = [ "正月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "冬月", "腊月" ] - static let days = [ + public static let days = [ "初一", "初二", "初三", "初四", "初五", "初六", "初七", "初八", "初九", "初十", "十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十", "廿一", "廿二", "廿三", "廿四", "廿五", "廿六", "廿七", "廿八", "廿九", "三十" @@ -185,12 +202,12 @@ struct Lunar { } -struct Solar { +public struct Solar { - static let daysInWeek = 7 - static let minYear = 1900, maxYear = 2100 - static let minMonth = 1, maxMonth = 12 - static let minDates = 35, maxDates = 42 + public static let daysInWeek = 7 + public static let minYear = 1900, maxYear = 2100 + public static let minMonth = 1, maxMonth = 12 + public static let minDates = 35, maxDates = 42 } diff --git a/CalendarX/Extension/AppKit+.swift b/CalendarXShared/Sources/Extension/AppKit+.swift similarity index 93% rename from CalendarX/Extension/AppKit+.swift rename to CalendarXShared/Sources/Extension/AppKit+.swift index 55ab3d5..bafcf71 100644 --- a/CalendarX/Extension/AppKit+.swift +++ b/CalendarXShared/Sources/Extension/AppKit+.swift @@ -34,16 +34,15 @@ extension NSView { } extension NSEvent { - var isRightClicked: Bool { + public var isRightClicked: Bool { type == .rightMouseDown || modifierFlags.contains(.control) } } -extension NSWorkspace { +public extension NSWorkspace { static func searching(_ keyword: String) { let urlString = "https://www.baidu.com/s?wd=" + keyword.urlEncoded open(urlString) - } static func open(_ urlString: String) { guard let url = URL(string: urlString) else { return } @@ -64,7 +63,7 @@ extension NSRunningApplication { } } -extension Array { +public extension Array { var isNotEmpty: Bool { !isEmpty } } @@ -90,7 +89,7 @@ extension Array: RawRepresentable where Element: Codable { } -extension String { +public extension String { var urlEncoded: String { addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? self @@ -110,7 +109,7 @@ extension String { } -extension String { +public extension String { func toObject(_ type: T.Type) -> T? { guard let data = data(using: .utf8) else { return .none } return try? JSONDecoder().decode(type, from: data) @@ -118,7 +117,7 @@ extension String { } -extension Binding where Value == String { +public extension Binding where Value == String { func max(_ limit: Int = 30) -> Self { if self.wrappedValue.count > limit { DispatchQueue.main.async { @@ -129,6 +128,6 @@ extension Binding where Value == String { } } -extension Locale { +public extension Locale { var inChinese: Bool { identifier.contains("zh") } } diff --git a/CalendarX/Extension/Bundle+.swift b/CalendarXShared/Sources/Extension/Bundle+.swift similarity index 97% rename from CalendarX/Extension/Bundle+.swift rename to CalendarXShared/Sources/Extension/Bundle+.swift index 3273428..8665c8a 100644 --- a/CalendarX/Extension/Bundle+.swift +++ b/CalendarXShared/Sources/Extension/Bundle+.swift @@ -7,7 +7,7 @@ import Foundation -extension Bundle { +public extension Bundle { func json2KeyValue(from resource: String) -> [String: T] { guard let url = url(forResource: resource, withExtension: "json"), let data = try? Data(contentsOf: url), diff --git a/CalendarX/Extension/Calendar+.swift b/CalendarXShared/Sources/Extension/Calendar+.swift similarity index 98% rename from CalendarX/Extension/Calendar+.swift rename to CalendarXShared/Sources/Extension/Calendar+.swift index 66483af..08ef993 100644 --- a/CalendarX/Extension/Calendar+.swift +++ b/CalendarXShared/Sources/Extension/Calendar+.swift @@ -7,7 +7,7 @@ import Foundation -extension Calendar { +public extension Calendar { func generateDates(for date: Date) -> [Date] { diff --git a/CalendarX/Extension/Color+.swift b/CalendarXShared/Sources/Extension/Color+.swift similarity index 69% rename from CalendarX/Extension/Color+.swift rename to CalendarXShared/Sources/Extension/Color+.swift index b962981..50690d8 100644 --- a/CalendarX/Extension/Color+.swift +++ b/CalendarXShared/Sources/Extension/Color+.swift @@ -7,7 +7,7 @@ import SwiftUI -extension Color { +public extension Color { init(light: String, lightAlpha: CGFloat = 1, dark: String, darkAlpha: CGFloat = 1) { @@ -19,10 +19,25 @@ extension Color { } init(hex: String, alpha: CGFloat = 1) { - self.init(.init(hex: hex, alpha: alpha)) + self.init(ns: .init(hex: hex, alpha: alpha)) } - + init(ns color: NSColor) { + if #available(macOS 12.0, *) { + self.init(nsColor: color) + } else { + self.init(color) + } + } + + init(cg color: CGColor) { + if #available(macOS 12.0, *) { + self.init(cgColor: color) + } else { + self.init(color) + } + } + } @@ -40,9 +55,9 @@ extension NSColor { convenience init(hex: String, alpha: CGFloat = 1) { var hexString = hex if hex.hasPrefix("0x") { - hexString = String(hex[hex.index(hexString.startIndex, offsetBy: 2)...hex.endIndex]) + hexString = hex[hex.index(hexString.startIndex, offsetBy: 2)...] + "" } else if hex.hasPrefix("#") { - hexString = String(hex[hex.index(hexString.startIndex, offsetBy: 1)...hex.endIndex]) + hexString = hex[hex.index(hexString.startIndex, offsetBy: 1)...] + "" } let pattern = "[a-fA-F0-9]+" diff --git a/CalendarX/Extension/Date+.swift b/CalendarXShared/Sources/Extension/Date+.swift similarity index 93% rename from CalendarX/Extension/Date+.swift rename to CalendarXShared/Sources/Extension/Date+.swift index 97146b2..b7ca72d 100644 --- a/CalendarX/Extension/Date+.swift +++ b/CalendarXShared/Sources/Extension/Date+.swift @@ -7,7 +7,7 @@ import Foundation -extension Date { +public extension Date { var isInvalidNextWeekday: Bool { let components = DateComponents(calendar: .gregorian, year: year, month: month, weekday: weekday, weekdayOrdinal: weekdayOrdinal + 1) @@ -84,6 +84,11 @@ extension Date { added(component: .month, value: 1) } + var startOfTomorrow: Date { + let startOfDay = Calendar.gregorian.startOfDay(for: self) + return Calendar.gregorian.date(byAdding: .day, value: 1, to: startOfDay) ?? self + } + var startOfMonth: Date { let components = Calendar.gregorian.dateComponents([.year, .month], from: self) return Calendar.gregorian.date(from: components) ?? self @@ -114,7 +119,7 @@ extension Date { } -extension Date { +public extension Date { var lunarYear: Int { Calendar.chinese.component(.year, from: self) diff --git a/CalendarX/Extension/View+.swift b/CalendarXShared/Sources/Extension/View+.swift similarity index 73% rename from CalendarX/Extension/View+.swift rename to CalendarXShared/Sources/Extension/View+.swift index 60fd13b..bf5ab08 100644 --- a/CalendarX/Extension/View+.swift +++ b/CalendarXShared/Sources/Extension/View+.swift @@ -7,6 +7,21 @@ import SwiftUI + +public extension View { + + @ViewBuilder + func appForeground(_ color: Color) -> some View { + if #available(macOS 14.0, *) { + foregroundStyle(color) + } else { + foregroundColor(color) + } + } +} + + + struct TintModifier: ViewModifier { let tint: Color @@ -71,10 +86,10 @@ struct CheckboxStyle: ToggleStyle { ZStack { Capsule() .frame(width: 35, height: 20) - .foregroundColor(configuration.isOn ? .accentColor : .disable) + .appForeground(configuration.isOn ? .accentColor : .disable) Circle() - .diameter(10) - .foregroundColor(.white) + .frame(width: 10, height: 10) + .appForeground(.white) .offset(x: configuration.isOn ? offsetX : -offsetX) } @@ -88,7 +103,7 @@ struct CheckboxStyle: ToggleStyle { } -extension View { +public extension View { func checkboxStyle() -> some View { toggleStyle(CheckboxStyle()) } @@ -99,13 +114,19 @@ extension View { } -extension View { +public extension View { func onChange(of value: V, notification name: NSNotification.Name) -> some View { - onChange(of: value) { _ in - NotificationCenter.default.post(name: name, object: .none) - } + if #available(macOS 14.0, *) { + return onChange(of: value) { + NotificationCenter.default.post(name: name, object: .none) + } + } else { + return onChange(of: value) { _ in + NotificationCenter.default.post(name: name, object: .none) + } + } } func envTint(_ tint: Color) -> some View { @@ -117,9 +138,9 @@ extension View { } - func fullScreenCover(_ backgroudColor: Color = .background) -> some View { + func fullScreenCover(_ backgroudColor: Color = .appBackground) -> some View { background(backgroudColor) - .transition(.move(edge: .bottom)) + .transition(.move(edge: .trailing)) .zIndex(1) } @@ -131,18 +152,12 @@ extension View { } - -extension View { +public extension View { func sideLength(_ width: CGFloat) -> some View { frame(width: width, height: width) } } -extension Circle { - func diameter(_ width: CGFloat) -> some View { - frame(width: width, height: width) - } -} diff --git a/CalendarXShared/Sources/Model/AppBundle.swift b/CalendarXShared/Sources/Model/AppBundle.swift new file mode 100644 index 0000000..5a65e12 --- /dev/null +++ b/CalendarXShared/Sources/Model/AppBundle.swift @@ -0,0 +1,24 @@ +import Foundation +enum AppBundleKey: String { + case build = "CFBundleVersion", + version = "CFBundleShortVersionString", + identifier = "CFBundleIdentifier", + name = "CFBundleName", + commitHash = "CommitHash", + commitDate = "CommitDate", + copyright = "NSHumanReadableCopyright" + +} + +public struct AppBundle { + + private static subscript(key: AppBundleKey) -> String { + Bundle.main.infoDictionary?[key.rawValue] as? String ?? "none" + } + public static let name = Self[.name] + public static let version = Self[.version] + public static let identifier = Self[.identifier] + public static let commitHash = Self[.commitHash] + public static let commitDate = Self[.commitHash] + public static let copyright = Self[.copyright] +} diff --git a/CalendarX/Model/CalDay.swift b/CalendarXShared/Sources/Model/AppDate.swift similarity index 62% rename from CalendarX/Model/CalDay.swift rename to CalendarXShared/Sources/Model/AppDate.swift index cb81cd4..16bd168 100644 --- a/CalendarX/Model/CalDay.swift +++ b/CalendarXShared/Sources/Model/AppDate.swift @@ -1,18 +1,15 @@ -// -// CalDay.swift -// CalendarX -// -// Created by zm on 2022/2/15. -// - import SwiftUI +import EventKit + +public typealias AppEvent = EKEvent +public typealias AppWeekday = EKWeekday -extension CalEvent { - var color: Color { Color(calendar.cgColor) } +public extension AppEvent { + var color: Color { .init(cg: calendar.cgColor) } } -extension CalWeekday: CaseIterable, CustomStringConvertible { - +extension AppWeekday: CaseIterable, CustomStringConvertible { + public static var allCases: [Self] { [.sunday, .monday, .tuesday, wednesday, thursday, friday, saturday] } @@ -21,13 +18,12 @@ extension CalWeekday: CaseIterable, CustomStringConvertible { } } -enum CalDayState: Int, Decodable, CustomStringConvertible { - - static let states: [String: [String: CalDayState]] = Bundle.main.json2KeyValue(from: "tiaoxiu") - +enum AppDateState: Int, Decodable, CustomStringConvertible { + + static let tiaoxiu = Bundle.tiaoxiu // 0,1,2 case inNormal, inWorking, onHoliday - + var description: String { switch self { case .inWorking: return "班" @@ -35,43 +31,43 @@ enum CalDayState: Int, Decodable, CustomStringConvertible { default: return "" } } - + static subscript(year: String, key: String) -> Self { - states[year]?[key] ?? .inNormal + tiaoxiu[year]?[key] ?? .inNormal } - + } -struct CalDay: Identifiable { - - let id = UUID() - let date: Date - let title, subtitle, stateDesc: String - let solarTerm, lunarFestival: String? - let inToday, inWeekend, inNormal, onHoliday: Bool - - let events: [CalEvent] - +public struct AppDate: Identifiable { + + public let id = UUID() + public let date: Date + public let title, subtitle, stateDesc: String + public let solarTerm, lunarFestival: String? + public let inToday, inWeekend, inNormal, onHoliday: Bool + + public let events: [AppEvent] + private let sKey, lKey, wKey: String private let isInvalid: Bool - - init(_ date: Date, events: [CalEvent]) { - + + public init(_ date: Date, events: [AppEvent] = []) { + let day = date.day.description, year = date.year.description, lunarMonth = (date.isLeapMonth ? "润": "") + date.lunarMonthString, lunarDay = date.lunarDay == 1 ? lunarMonth : date.lunarDayString - + sKey = String(format: "%02d%02d", date.month, date.day) lKey = String(format: "%02d%02d", date.lunarMonth, date.lunarDay) wKey = String(format: "%02d%d%d", date.month, date.weekdayOrdinal, date.weekday) isInvalid = date.isInvalidNextWeekday - + solarTerm = SolarTerm[year, sKey] lunarFestival = LunarFestival[year, sKey, lKey] - let state = CalDayState[year, sKey], solarFestival = SolarFestival[wKey, sKey] - + let state = AppDateState[year, sKey], solarFestival = SolarFestival[wKey, sKey] + title = day subtitle = lunarFestival ?? solarTerm ?? solarFestival ?? lunarDay inToday = date.inToday @@ -81,30 +77,29 @@ struct CalDay: Identifiable { stateDesc = state.description self.date = date self.events = events - + } - } -extension CalDay { - +public extension AppDate { + var festivals: [String] { [lunarFestival, solarTerm].compactMap{$0} + Festival[wKey, sKey, isInvalid] } var lunarDate: String { - + let lunarYear = date.lunarYear, zodiacs = Lunar.zodiacs, heavenlyStems = Lunar.heavenlyStems, earthlyBranches = Lunar.earthlyBranches - + let zIndex = (lunarYear - 1) % zodiacs.count, hIndex = (lunarYear - 1) % heavenlyStems.count, eIndex = (lunarYear - 1) % earthlyBranches.count - + return heavenlyStems[hIndex] + earthlyBranches[eIndex] + zodiacs[zIndex] + "年 " + @@ -112,23 +107,23 @@ extension CalDay { date.lunarMonthString + date.lunarDayString } - + } struct Festival { - - private static let festivals = Bundle.main.json2AllFestivals(from: "solarAF") // Contains solarPF - private static let weekFestivals = Bundle.main.json2AllFestivals(from: "weekAF") + private static let solarAF = Bundle.solarAF// Contains solarPF - private static let otherFestivals = Bundle.main.json2Festival(from: "weekSF") + private static let weekAF = Bundle.weekAF + + private static let weekSF = Bundle.weekSF static subscript(wKey: String, sKey: String, isInvalid: Bool) -> [String] { - let wFestivals = weekFestivals[wKey] ?? [], - oFestival = isInvalid ? otherFestivals[wKey] : .none, - oFestivals = festivals[sKey] ?? [] - + let wFestivals = weekAF[wKey] ?? [], + oFestival = isInvalid ? weekSF[wKey] : .none, + oFestivals = solarAF[sKey] ?? [] + return wFestivals + [oFestival].compactMap{$0} + oFestivals } @@ -136,32 +131,30 @@ struct Festival { struct SolarFestival { - - private static let festivals = Bundle.main.json2Festival(from: "solarPF") - private static let weekFestivals = Bundle.main.json2Festival(from: "weekPF") + private static let solarPF = Bundle.solarPF + private static let weekPF = Bundle.weekPF static subscript(wKey: String, sKey: String) -> String? { - weekFestivals[wKey] ?? festivals[sKey] + weekPF[wKey] ?? solarPF[sKey] } } struct LunarFestival { - - private static let festivals = Bundle.main.json2Festival(from: "lunarPF") - private static let eves = Bundle.main.json2Festival(from: "chuxi") + private static let lunarPF = Bundle.lunarPF + private static let chuxi = Bundle.chuxi static subscript(year: String, sKey: String, lKey: String) -> String? { - eves[year] != sKey ? festivals[lKey]: festivals["0100"] + chuxi[year] != sKey ? lunarPF[lKey]: lunarPF["0100"] } } struct SolarTerm { - private static let terms = Bundle.main.json2AllFestivals(from: "terms") + private static let terms = Bundle.terms private static let termNames = [ "立春", "雨水", "惊蛰", "春分", "清明", "谷雨", "立夏", "小满", "芒种", "夏至", "小暑", "大暑", diff --git a/CalendarXShared/Sources/Model/AppInfo.swift b/CalendarXShared/Sources/Model/AppInfo.swift new file mode 100644 index 0000000..79ac6c0 --- /dev/null +++ b/CalendarXShared/Sources/Model/AppInfo.swift @@ -0,0 +1,13 @@ +// +// AppInfo.swift +// CalendarX +// +// Created by zm on 2023/12/8. +// + +import Foundation + +public struct AppInfo: Decodable, Identifiable { + public var id: String { name } + public let name: String, about: String, link: String +} diff --git a/CalendarXShared/Sources/Model/Preference.swift b/CalendarXShared/Sources/Model/Preference.swift new file mode 100644 index 0000000..2f33614 --- /dev/null +++ b/CalendarXShared/Sources/Model/Preference.swift @@ -0,0 +1,71 @@ +// +// Preferences.swift +// Bingpaper +// +// Created by zm on 2021/10/26. +// +import SwiftUI + +public struct Preference { + + public static let shared = Preference() + + @AppStorage(AppStorageKey.theme, store: .group) + public var theme: Theme = .system + + @AppStorage(AppStorageKey.tint, store: .group) + public var tint: String = Appearance.tint + + @AppStorage(AppStorageKey.language, store: .group) + public var language: Language = .system + +} + +public extension Preference { + var color: Color { Color(hex: tint) } + var colorScheme: ColorScheme? { theme.colorScheme } + var locale: Locale { language.locale } +} + +public enum Theme: Int, CaseIterable { + + case system, light, dark + + public var colorScheme: ColorScheme? { + switch self { + case .light: return .light + case .dark: return .dark + default: return .none + } + } + + public var title: LocalizedStringKey { + switch self { + case .light: return L10n.Theme.light + case .dark: return L10n.Theme.dark + default: return L10n.Theme.system + } + } +} + +public enum Language: Int, CaseIterable { + + case system, zh_CN, en_US + + public var locale: Locale { + switch self { + case .zh_CN: return .zh + case .en_US: return .en + default: return .current + } + } + + public var title: LocalizedStringKey { + switch self { + case .zh_CN: return L10n.Language.zh_CN + case .en_US: return L10n.Language.en_US + default: return L10n.Language.system + } + } + +} diff --git a/CalendarX/Resource/apps.json b/CalendarXShared/Sources/Resources/apps.json similarity index 100% rename from CalendarX/Resource/apps.json rename to CalendarXShared/Sources/Resources/apps.json diff --git a/CalendarX/Resource/chuxi.json b/CalendarXShared/Sources/Resources/chuxi.json similarity index 100% rename from CalendarX/Resource/chuxi.json rename to CalendarXShared/Sources/Resources/chuxi.json diff --git a/CalendarX/Resource/lunarPF.json b/CalendarXShared/Sources/Resources/lunarPF.json similarity index 100% rename from CalendarX/Resource/lunarPF.json rename to CalendarXShared/Sources/Resources/lunarPF.json diff --git a/CalendarX/Resource/solarAF.json b/CalendarXShared/Sources/Resources/solarAF.json similarity index 100% rename from CalendarX/Resource/solarAF.json rename to CalendarXShared/Sources/Resources/solarAF.json diff --git a/CalendarX/Resource/solarPF.json b/CalendarXShared/Sources/Resources/solarPF.json similarity index 100% rename from CalendarX/Resource/solarPF.json rename to CalendarXShared/Sources/Resources/solarPF.json diff --git a/CalendarX/Resource/terms.json b/CalendarXShared/Sources/Resources/terms.json similarity index 100% rename from CalendarX/Resource/terms.json rename to CalendarXShared/Sources/Resources/terms.json diff --git a/CalendarX/Resource/tiaoxiu.json b/CalendarXShared/Sources/Resources/tiaoxiu.json similarity index 90% rename from CalendarX/Resource/tiaoxiu.json rename to CalendarXShared/Sources/Resources/tiaoxiu.json index 86fe28a..5b7863e 100644 --- a/CalendarX/Resource/tiaoxiu.json +++ b/CalendarXShared/Sources/Resources/tiaoxiu.json @@ -401,6 +401,48 @@ "1005": 2, "1006": 2, "1007": 1, - "1008": 1 + "1008": 1, + "1230": 2, + "1231": 2 + }, + "2024": { + "0101": 2, + "0204": 1, + "0210": 2, + "0211": 2, + "0212": 2, + "0213": 2, + "0214": 2, + "0215": 2, + "0216": 2, + "0217": 2, + "0218": 1, + "0404": 2, + "0405": 2, + "0406": 2, + "0407": 1, + "0428": 1, + "0501": 2, + "0502": 2, + "0503": 2, + "0504": 2, + "0505": 2, + "0511": 1, + "0608": 2, + "0609": 2, + "0610": 2, + "0914": 1, + "0915": 2, + "0916": 2, + "0917": 2, + "0929": 1, + "1001": 2, + "1002": 2, + "1003": 2, + "1004": 2, + "1005": 2, + "1006": 2, + "1007": 2, + "1012": 1 } } diff --git a/CalendarX/Resource/weekAF.json b/CalendarXShared/Sources/Resources/weekAF.json similarity index 100% rename from CalendarX/Resource/weekAF.json rename to CalendarXShared/Sources/Resources/weekAF.json diff --git a/CalendarX/Resource/weekPF.json b/CalendarXShared/Sources/Resources/weekPF.json similarity index 100% rename from CalendarX/Resource/weekPF.json rename to CalendarXShared/Sources/Resources/weekPF.json diff --git a/CalendarX/Resource/weekSF.json b/CalendarXShared/Sources/Resources/weekSF.json similarity index 100% rename from CalendarX/Resource/weekSF.json rename to CalendarXShared/Sources/Resources/weekSF.json diff --git a/CalendarXShared/Sources/Service/CalendarHelper.swift b/CalendarXShared/Sources/Service/CalendarHelper.swift new file mode 100644 index 0000000..dc267aa --- /dev/null +++ b/CalendarXShared/Sources/Service/CalendarHelper.swift @@ -0,0 +1,28 @@ +import Foundation +import SwiftUI + +public struct CalendarHelper { + + public static let columns = Array(repeating: GridItem(), count: Solar.daysInWeek) + + public static func makeDates(firstWeekday: AppWeekday, date: Date) -> [AppDate] { + var calendar = Calendar.gregorian + calendar.firstWeekday = firstWeekday.rawValue + let dates = calendar.generateDates(for: date) + + if EventHelper.isAuthorized { + let events = EventHelper.fetchEvents(with: dates.first!, end: dates.last!) + return dates.map { date in + AppDate(date, events: events.filter{ $0.startDate.isSameDay(as: date) } ) + } + } else { + return dates.map { AppDate($0) } + } + } + + + public static func spacing(from count: Int) -> CGFloat? { + count > Solar.minDates ? 1.7: nil + } + +} diff --git a/CalendarX/Service/EventHelper.swift b/CalendarXShared/Sources/Service/EventHelper.swift similarity index 51% rename from CalendarX/Service/EventHelper.swift rename to CalendarXShared/Sources/Service/EventHelper.swift index b1ba72a..7dffe3b 100644 --- a/CalendarX/Service/EventHelper.swift +++ b/CalendarXShared/Sources/Service/EventHelper.swift @@ -8,53 +8,51 @@ import EventKit -typealias CalEvent = EKEvent -typealias CalWeekday = EKWeekday +public struct EventHelper { -struct EventHelper { + private static var store = EKEventStore() - private static let store = EKEventStore() - - private static var authorizationStatus: EKAuthorizationStatus { EKEventStore.authorizationStatus(for: .event) } - - static var isDenied: Bool { + + public static var isDenied: Bool { authorizationStatus == .denied || authorizationStatus == .restricted } - static var isNotDetermined: Bool { + public static var isNotDetermined: Bool { authorizationStatus == .notDetermined } - static var isAuthorized: Bool { - authorizationStatus == .authorized + public static var isAuthorized: Bool { + if #available(macOS 14.0, *) { + authorizationStatus == .fullAccess + } else { + authorizationStatus == .authorized + } } - static func start() { - if isAuthorized { return } - guard CalendarPreference.shared.showEvents else { return } - CalendarPreference.shared.showEvents = false - } - - static func requestAccess() async -> Bool { + public static func requestAccess() async -> Bool { do { - return try await store.requestAccess(to: .event) + if #available(macOS 14.0, *) { + return try await store.requestFullAccessToEvents() + } else { + return try await store.requestAccess(to: .event) + } } catch { return false } } - static func fetchEvents(with start: Date, end: Date) -> [CalEvent] { + public static func fetchEvents(with start: Date, end: Date) -> [AppEvent] { - guard isAuthorized else { return [] } let calendars = store.calendars(for: .event).filter { "中国大陆节假日" != $0.title } let predicate = store.predicateForEvents(withStart: start.yesterday, end: end.tomorrow, calendars: calendars) return store.events(matching: predicate) + } } diff --git a/CalendarXShared/Sources/Service/L10n.swift b/CalendarXShared/Sources/Service/L10n.swift new file mode 100644 index 0000000..0370a63 --- /dev/null +++ b/CalendarXShared/Sources/Service/L10n.swift @@ -0,0 +1,196 @@ +// +// L10n.swift +// CalendarX +// +// Created by zm on 2022/3/30. +// + +import Foundation +import SwiftUI + +public typealias L10Date = Date + +public struct L10n { + + private static let formatter = DateFormatter() + + private static var locale: Locale { Preference.shared.locale } + + public static var inChinese: Bool { locale.inChinese } + + public enum Settings { + public static let title = "settings.title".l10nKey + public static let appearance = "settings.appearance".l10nKey + public static let calendar = "settings.calendar".l10nKey + public static let auto = "settings.auto".l10nKey + public static let language = "settings.language".l10nKey + public static let recommendations = "settings.recommendations".l10nKey + public static let menubarStyle = "settings.menubarStyle".l10nKey + public static let launchAtLogin = "settings.launchAtLogin".l10nKey + public static let version = "settings.version".l10nKey + public static let checkForUpdates = "settings.checkForUpdates".l10nKey + public static let about = "settings.about".l10nKey + } + + public enum Calendar { + public static let showEvents = "calendar.showEvents".l10nKey + public static let startWeekOn = "calendar.startWeekOn".l10nKey + public static let showLunar = "calendar.showLunar".l10nKey + public static let showHolidays = "calendar.showHolidays".l10nKey + } + + public enum Appearance { + public static let hex = "appearance.hex".l10nKey + public static let tint = "appearance.tint".l10nKey + } + + public enum Alert { + public static let exit = "alert.exit".l10nKey + public static let notifications = "alert.notifications".l10nKey + public static let calendars = "alert.calendars".l10nKey + + public static let exitMessage = "alert.exitMessage".l10nKey + public static let notificationsMessage = "alert.notificationsMessage".l10nKey + public static let calendarsMessage = "alert.calendarsMessage".l10nKey + + public static let ok = "alert.ok".l10nKey + public static let yes = "alert.yes".l10nKey + public static let no = "alert.no".l10nKey + } + + public enum Theme { + public static let system = "theme.system".l10nKey + public static let dark = "theme.dark".l10nKey + public static let light = "theme.light".l10nKey + } + + public enum Language { + public static let system = "theme.system".l10nKey + public static let en_US = "English".l10nKey + public static let zh_CN = "简体中文".l10nKey + } + + public enum MenubarStyle { + public static let `default` = "menubarStyle.default".l10nKey + public static let text = "menubarStyle.text".l10nKey + public static let date = "menubarStyle.date".l10nKey + public static let tips = "menubarStyle.tips".l10nKey + public static let save = "menubarStyle.save".l10nKey + public static let use24 = "menubarStyle.use24".l10nKey + public static let showSeconds = "menubarStyle.showSeconds".l10nKey + } + + public enum Date { + public static let allDay = "date.allDay".l10nKey + public static let events = "date.events".l10nKey + public static let noEvents = "date.noEvents".l10nKey + } + + public enum Updater { + public static var available: String { "updater.available".localized(bundle) } + public static func update(_ version: String) -> String { "updater.update".localized(bundle, args: version) } + } + +} + + + + +@available(macOSApplicationExtension, unavailable) +public extension L10n { + + static func timeline(from date: L10Date) -> String { + formatter.locale = .posix + formatter.dateFormat = "yyyy-MM-dd HH:mm" + return formatter.string(from: date) + } + + static func shortWeekday(from date: L10Date) -> String { + formatter.locale = locale + return inChinese ? formatter.veryShortWeekdaySymbols[date.weekday - 1] : + formatter.shortWeekdaySymbols[date.weekday - 1] + } + + static func monthSymbol(from month: Int) -> String { + formatter.locale = locale + return formatter.shortMonthSymbols[month - 1] + } + + static func weekdaySymbol(from weekday: AppWeekday) -> String { + formatter.locale = locale + return formatter.shortWeekdaySymbols[weekday.rawValue - 1] + } + +} + +//MARK: Widget +public extension L10n { + public enum LargeWidget { + public static let displayName = "largeWidget.displayName".l10nKey + public static let description = "largeWidget.description".l10nKey + } +} + +public extension L10n { + static func widgetShortWeekday(from date: L10Date, locale: Locale) -> String { + formatter.locale = locale + return locale.inChinese ? formatter.veryShortWeekdaySymbols[date.weekday - 1] : + formatter.shortWeekdaySymbols[date.weekday - 1] + } + + static func widgetMonthSymbol(from month: Int, locale: Locale) -> String { + formatter.locale = locale + return formatter.shortMonthSymbols[month - 1] + } + + static func widgetWeekdaySymbol(from weekday: AppWeekday, locale: Locale) -> String { + formatter.locale = locale + return formatter.shortWeekdaySymbols[weekday.rawValue - 1] + } +} + +//MARK: Menubar Date&Time Style +public extension L10n { + static func lm(from date: L10Date) -> String { date.lunarMonthString } + static func ld(from date: L10Date) -> String { date.lunarDayString } + static func sm(from date: L10Date) -> String { monthSymbol(from: date.month) } + + static func sd(from date: L10Date) -> String { + formatter.locale = locale + formatter.dateFormat = L10n.inChinese ? "d日":"d" + return formatter.string(from: date) + } + + static func e(from date: L10Date) -> String { + formatter.locale = locale + formatter.dateFormat = "E" + return formatter.string(from: date) + } + + static func a(from date: L10Date) -> String { + formatter.locale = locale + formatter.dateFormat = "a" + return formatter.string(from: date) + } + + static func t(from date: L10Date, use24h: Bool, showSeconds: Bool) -> String { + formatter.locale = .posix + formatter.dateFormat = (use24h ? "HH:mm":"h:mm") + (showSeconds ? ":ss":"") + return formatter.string(from: date) + } +} + +extension L10n { + static var bundle: Bundle { + let fileName = { + switch locale { + case .zh: return "zh-Hans" + case .en: return "en" + default: return "zh-Hans" + } + } + guard let path = Bundle.main.path(forResource: fileName(), ofType: "lproj") else { return .main } + return Bundle(path: path) ?? .main + } +} + diff --git a/CalendarXWidget/Assets.xcassets/AccentColor.colorset/Contents.json b/CalendarXWidget/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/CalendarXWidget/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/CalendarXWidget/Assets.xcassets/AppIcon.appiconset/Contents.json b/CalendarXWidget/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..3f00db4 --- /dev/null +++ b/CalendarXWidget/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,58 @@ +{ + "images" : [ + { + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/CalendarXWidget/Assets.xcassets/Contents.json b/CalendarXWidget/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/CalendarXWidget/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/CalendarXWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json b/CalendarXWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/CalendarXWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/CalendarXWidget/Base.lproj/CalendarXWidget.intentdefinition b/CalendarXWidget/Base.lproj/CalendarXWidget.intentdefinition new file mode 100644 index 0000000..76ef2f3 --- /dev/null +++ b/CalendarXWidget/Base.lproj/CalendarXWidget.intentdefinition @@ -0,0 +1,729 @@ + + + + + INEnums + + + INEnumDisplayName + Widget Weekday + INEnumDisplayNameID + CJwnoY + INEnumGeneratesHeader + + INEnumName + WidgetWeekday + INEnumType + Regular + INEnumValues + + + INEnumValueDisplayName + unknown + INEnumValueDisplayNameID + u1Cg7S + INEnumValueName + unknown + + + INEnumValueDisplayName + Sunday + INEnumValueDisplayNameID + EjYffU + INEnumValueIndex + 1 + INEnumValueName + sunday + + + INEnumValueDisplayName + Monday + INEnumValueDisplayNameID + 23t8NN + INEnumValueIndex + 2 + INEnumValueName + monday + + + INEnumValueDisplayName + Tuesday + INEnumValueDisplayNameID + RoHUik + INEnumValueIndex + 3 + INEnumValueName + tuesday + + + INEnumValueDisplayName + Wednesday + INEnumValueDisplayNameID + eStozH + INEnumValueIndex + 4 + INEnumValueName + wednesday + + + INEnumValueDisplayName + Thursday + INEnumValueDisplayNameID + JLPDos + INEnumValueIndex + 5 + INEnumValueName + thursday + + + INEnumValueDisplayName + Friday + INEnumValueDisplayNameID + UouvsT + INEnumValueIndex + 6 + INEnumValueName + friday + + + INEnumValueDisplayName + Saturday + INEnumValueDisplayNameID + YcSbEL + INEnumValueIndex + 7 + INEnumValueName + saturday + + + + + INEnumDisplayName + Widget Language + INEnumDisplayNameID + mch2I8 + INEnumGeneratesHeader + + INEnumName + WidgetLanguage + INEnumType + Regular + INEnumValues + + + INEnumValueDisplayName + unknown + INEnumValueDisplayNameID + roJexZ + INEnumValueName + unknown + + + INEnumValueDisplayName + Follow system + INEnumValueDisplayNameID + fxBCVh + INEnumValueIndex + 1 + INEnumValueName + system + + + INEnumValueDisplayName + 简体中文 + INEnumValueDisplayNameID + R74qr4 + INEnumValueIndex + 2 + INEnumValueName + zh_CN + + + INEnumValueDisplayName + English + INEnumValueDisplayNameID + w8fWt0 + INEnumValueIndex + 3 + INEnumValueName + en_US + + + + + INEnumDisplayName + Widget Theme + INEnumDisplayNameID + 4KRsdf + INEnumGeneratesHeader + + INEnumName + WidgetTheme + INEnumType + Regular + INEnumValues + + + INEnumValueDisplayName + unknown + INEnumValueDisplayNameID + lnQMm8 + INEnumValueName + unknown + + + INEnumValueDisplayName + Follow system + INEnumValueDisplayNameID + 8R2rKx + INEnumValueIndex + 1 + INEnumValueName + system + + + INEnumValueDisplayName + Light + INEnumValueDisplayNameID + 3h5WUz + INEnumValueIndex + 2 + INEnumValueName + light + + + INEnumValueDisplayName + Dark + INEnumValueDisplayNameID + ixslPm + INEnumValueIndex + 3 + INEnumValueName + dark + + + + + INEnumDisplayName + Widget Tint + INEnumDisplayNameID + szmpx4 + INEnumGeneratesHeader + + INEnumName + WidgetTint + INEnumType + Regular + INEnumValues + + + INEnumValueDisplayName + unknown + INEnumValueDisplayNameID + BHGO9L + INEnumValueName + unknown + + + INEnumValueDisplayName + 🟥 + INEnumValueDisplayNameID + FtpWg1 + INEnumValueIndex + 1 + INEnumValueName + red + + + INEnumValueDisplayName + 🟧 + INEnumValueDisplayNameID + PwlH5o + INEnumValueIndex + 2 + INEnumValueName + orange + + + INEnumValueDisplayName + 🟨 + INEnumValueDisplayNameID + 0KwTK2 + INEnumValueIndex + 3 + INEnumValueName + yellow + + + INEnumValueDisplayName + 🟩 + INEnumValueDisplayNameID + Cvj4om + INEnumValueIndex + 4 + INEnumValueName + green + + + INEnumValueDisplayName + 🟦 + INEnumValueDisplayNameID + 0x6ok8 + INEnumValueIndex + 5 + INEnumValueName + blue + + + INEnumValueDisplayName + 🟫 + INEnumValueDisplayNameID + iZZDhi + INEnumValueIndex + 6 + INEnumValueName + brown + + + INEnumValueDisplayName + 🟪 + INEnumValueDisplayNameID + emz1ih + INEnumValueIndex + 7 + INEnumValueName + purple + + + + + INIntentDefinitionModelVersion + 1.2 + INIntentDefinitionNamespace + DrmhqH + INIntentDefinitionSystemVersion + 22G436 + INIntentDefinitionToolsBuildVersion + 15C65 + INIntentDefinitionToolsVersion + 15.1 + INIntents + + + INIntentCategory + information + INIntentDescriptionID + qs7owS + INIntentEligibleForWidgets + + INIntentIneligibleForSuggestions + + INIntentLastParameterTag + 18 + INIntentName + WidgetConfiguration + INIntentParameters + + + INIntentParameterConfigurable + + INIntentParameterDisplayName + Tint + INIntentParameterDisplayNameID + wkmfzv + INIntentParameterDisplayPriority + 1 + INIntentParameterEnumType + WidgetTint + INIntentParameterEnumTypeNamespace + DrmhqH + INIntentParameterMetadata + + INIntentParameterMetadataDefaultValue + red + + INIntentParameterName + tint + INIntentParameterPromptDialogs + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Configuration + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Primary + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + There are ${count} options matching ‘${tint}’. + INIntentParameterPromptDialogFormatStringID + PyAT7j + INIntentParameterPromptDialogType + DisambiguationIntroduction + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + Just to confirm, you wanted ‘${tint}’? + INIntentParameterPromptDialogFormatStringID + PHmfP2 + INIntentParameterPromptDialogType + Confirmation + + + INIntentParameterTag + 18 + INIntentParameterType + Integer + + + INIntentParameterConfigurable + + INIntentParameterDisplayName + Theme + INIntentParameterDisplayNameID + 4pjVKH + INIntentParameterDisplayPriority + 2 + INIntentParameterEnumType + WidgetTheme + INIntentParameterEnumTypeNamespace + DrmhqH + INIntentParameterMetadata + + INIntentParameterMetadataDefaultValue + system + + INIntentParameterName + theme + INIntentParameterPromptDialogs + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Configuration + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Primary + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + There are ${count} options matching ‘${theme}’. + INIntentParameterPromptDialogFormatStringID + Ur4lLP + INIntentParameterPromptDialogType + DisambiguationIntroduction + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + Just to confirm, you wanted ‘${theme}’? + INIntentParameterPromptDialogFormatStringID + BxmIDl + INIntentParameterPromptDialogType + Confirmation + + + INIntentParameterTag + 13 + INIntentParameterType + Integer + + + INIntentParameterConfigurable + + INIntentParameterDisplayName + Language + INIntentParameterDisplayNameID + 2ZS03J + INIntentParameterDisplayPriority + 3 + INIntentParameterEnumType + WidgetLanguage + INIntentParameterEnumTypeNamespace + DrmhqH + INIntentParameterMetadata + + INIntentParameterMetadataDefaultValue + system + + INIntentParameterName + language + INIntentParameterPromptDialogs + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Configuration + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Primary + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + There are ${count} options matching ‘${language}’. + INIntentParameterPromptDialogFormatStringID + h7F9C9 + INIntentParameterPromptDialogType + DisambiguationIntroduction + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + Just to confirm, you wanted ‘${language}’? + INIntentParameterPromptDialogFormatStringID + RRB5Nx + INIntentParameterPromptDialogType + Confirmation + + + INIntentParameterTag + 11 + INIntentParameterType + Integer + + + INIntentParameterConfigurable + + INIntentParameterDisplayName + Start week on + INIntentParameterDisplayNameID + j5uOVs + INIntentParameterDisplayPriority + 4 + INIntentParameterEnumType + WidgetWeekday + INIntentParameterEnumTypeNamespace + DrmhqH + INIntentParameterMetadata + + INIntentParameterMetadataDefaultValue + sunday + + INIntentParameterName + startWeekOn + INIntentParameterPromptDialogs + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Configuration + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Primary + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + There are ${count} options matching ‘${startWeekOn}’. + INIntentParameterPromptDialogFormatStringID + Qx5ip1 + INIntentParameterPromptDialogType + DisambiguationIntroduction + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + Just to confirm, you wanted ‘${startWeekOn}’? + INIntentParameterPromptDialogFormatStringID + zNI9vB + INIntentParameterPromptDialogType + Confirmation + + + INIntentParameterTag + 8 + INIntentParameterType + Integer + + + INIntentParameterConfigurable + + INIntentParameterDisplayName + Show calendar events + INIntentParameterDisplayNameID + JMeC7c + INIntentParameterDisplayPriority + 5 + INIntentParameterMetadata + + INIntentParameterMetadataDefaultValue + + INIntentParameterMetadataFalseDisplayName + false + INIntentParameterMetadataFalseDisplayNameID + veSx01 + INIntentParameterMetadataTrueDisplayName + true + INIntentParameterMetadataTrueDisplayNameID + 2jywbx + + INIntentParameterName + showEvents + INIntentParameterPromptDialogs + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Configuration + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Primary + + + INIntentParameterTag + 7 + INIntentParameterType + Boolean + + + INIntentParameterConfigurable + + INIntentParameterDisplayName + Show lunar calendar + INIntentParameterDisplayNameID + 3RKOOn + INIntentParameterDisplayPriority + 6 + INIntentParameterMetadata + + INIntentParameterMetadataDefaultValue + + INIntentParameterMetadataFalseDisplayName + false + INIntentParameterMetadataFalseDisplayNameID + ZdFnbN + INIntentParameterMetadataTrueDisplayName + true + INIntentParameterMetadataTrueDisplayNameID + 69LV8r + + INIntentParameterName + showLunar + INIntentParameterPromptDialogs + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Configuration + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Primary + + + INIntentParameterTag + 2 + INIntentParameterType + Boolean + + + INIntentParameterConfigurable + + INIntentParameterDisplayName + Show Chinese statutory holidays + INIntentParameterDisplayNameID + w5cj3i + INIntentParameterDisplayPriority + 7 + INIntentParameterMetadata + + INIntentParameterMetadataDefaultValue + + INIntentParameterMetadataFalseDisplayName + false + INIntentParameterMetadataFalseDisplayNameID + dWh2UQ + INIntentParameterMetadataTrueDisplayName + true + INIntentParameterMetadataTrueDisplayNameID + pikPQm + + INIntentParameterName + showHolidays + INIntentParameterPromptDialogs + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Configuration + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Primary + + + INIntentParameterTag + 6 + INIntentParameterType + Boolean + + + INIntentResponse + + INIntentResponseCodes + + + INIntentResponseCodeName + success + INIntentResponseCodeSuccess + + + + INIntentResponseCodeName + failure + + + + INIntentTitle + Widget Configuration + INIntentTitleID + 65ppC3 + INIntentType + Custom + INIntentVerb + View + + + INTypes + + + diff --git a/CalendarXWidget/CalendarXWidget.entitlements b/CalendarXWidget/CalendarXWidget.entitlements new file mode 100644 index 0000000..e6a86c4 --- /dev/null +++ b/CalendarXWidget/CalendarXWidget.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.personal-information.calendars + + + diff --git a/CalendarXWidget/CalendarXWidgetBundle.swift b/CalendarXWidget/CalendarXWidgetBundle.swift new file mode 100644 index 0000000..44c7c77 --- /dev/null +++ b/CalendarXWidget/CalendarXWidgetBundle.swift @@ -0,0 +1,38 @@ +// +// CalendarXWidgetBundle.swift +// CalendarXWidget +// +// Created by zm on 2023/12/15. +// +import WidgetKit +import SwiftUI +import CalendarXShared + +@main +struct CalendarXWidgetBundle: WidgetBundle { + + @WidgetBundleBuilder + var body: some Widget { + LargeWidget() + } +} + +struct LargeWidget: Widget { + + private let kind = "CalendarX.LargeWidget" + private let intent = LargeWidgetProvider.Intent.self + private let provider = LargeWidgetProvider() + private let displayName = L10n.LargeWidget.displayName + private let description = L10n.LargeWidget.description + + var body: some WidgetConfiguration { + IntentConfiguration(kind: kind, intent: intent, provider: provider) { entry in + LargeWidgetView(entry) + .envColorScheme(entry.colorScheme) + } + .configurationDisplayName(displayName) + .description(description) + .supportedFamilies([.systemLarge]) + } +} + diff --git a/CalendarXWidget/Info.plist b/CalendarXWidget/Info.plist new file mode 100644 index 0000000..0f118fb --- /dev/null +++ b/CalendarXWidget/Info.plist @@ -0,0 +1,11 @@ + + + + + NSExtension + + NSExtensionPointIdentifier + com.apple.widgetkit-extension + + + diff --git a/CalendarXWidget/LargeWidget/LargeWidgetEntry.swift b/CalendarXWidget/LargeWidget/LargeWidgetEntry.swift new file mode 100644 index 0000000..dcad7d6 --- /dev/null +++ b/CalendarXWidget/LargeWidget/LargeWidgetEntry.swift @@ -0,0 +1,57 @@ +// +// LargeWidgetEntry.swift +// CalendarXWidget +// +// Created by zm on 2023/12/8. +// + +import WidgetKit +import CalendarXShared +import SwiftUI + +struct LargeWidgetEntry: TimelineEntry { + let date: Date, configuration: LargeWidgetProvider.Intent + + init(date: Date = Date(), configuration: LargeWidgetProvider.Intent = .init()) { + self.date = date + self.configuration = configuration + } +} + +extension LargeWidgetEntry { + + private var palettes: [String] { + ["C72C41", "F07B3F", "E0C341", "03C988", "1363DF", "876445", "7858A6"] + } + + var tint: Color { + guard configuration.tint.rawValue > 0 else { return Color(hex: palettes[0], alpha: 1) } + return Color(hex: palettes[configuration.tint.rawValue - 1], alpha: 1) + } + + var colorScheme: ColorScheme? { + Theme(rawValue: configuration.theme.rawValue - 1)?.colorScheme + } + + var locale: Locale { + Language(rawValue: configuration.language.rawValue - 1)?.locale ?? .current + } + + var firstWeekday: AppWeekday { + AppWeekday(rawValue: configuration.startWeekOn.rawValue) ?? .sunday + } +} + +extension LargeWidgetEntry { + var showLunar: Bool { + configuration.showLunar?.boolValue ?? true + } + + var showEvents: Bool { + configuration.showEvents?.boolValue ?? true + } + + var showHolidays: Bool { + configuration.showHolidays?.boolValue ?? true + } +} diff --git a/CalendarXWidget/LargeWidget/LargeWidgetProvider.swift b/CalendarXWidget/LargeWidget/LargeWidgetProvider.swift new file mode 100644 index 0000000..c3ee513 --- /dev/null +++ b/CalendarXWidget/LargeWidget/LargeWidgetProvider.swift @@ -0,0 +1,25 @@ +import WidgetKit +import CalendarXShared + +struct LargeWidgetProvider: IntentTimelineProvider { + + typealias Entry = LargeWidgetEntry + typealias Intent = WidgetConfigurationIntent + + func placeholder(in context: Context) -> Entry { + .init() + } + func getSnapshot(for configuration: Intent, in context: Context, completion: @escaping (Entry) -> Void) { + completion(.init(configuration: configuration)) + } + + func getTimeline(for configuration: Intent, in context: Context, completion: @escaping (Timeline) -> Void) { + + let date = Date(), entry = Entry(date: date, configuration: configuration) + let policy: TimelineReloadPolicy = .after(date.startOfTomorrow) + let timeline = Timeline(entries: [entry], policy: policy) + completion(timeline) + + } + +} diff --git a/CalendarXWidget/LargeWidget/LargeWidgetView.swift b/CalendarXWidget/LargeWidget/LargeWidgetView.swift new file mode 100644 index 0000000..0e01d5e --- /dev/null +++ b/CalendarXWidget/LargeWidget/LargeWidgetView.swift @@ -0,0 +1,114 @@ +// +// LargeView.swift +// CalendarXWidget +// +// Created by zm on 2023/12/8. +// + +import SwiftUI +import CalendarXShared + +struct LargeWidgetView: View { + + let entry: LargeWidgetProvider.Entry + + + private var date: Date { entry.date } + private var locale: Locale { entry.locale } + + private var tint: Color { entry.tint } + private var offBackground: Color { tint.opacity(0.12) } + + init(_ entry: LargeWidgetProvider.Entry) { + self.entry = entry + } + + var body: some View { + let dates = CalendarHelper.makeDates(firstWeekday: entry.firstWeekday, date: date) + let columns = CalendarHelper.columns + let spacing = CalendarHelper.spacing(from: dates.count) + + ZStack{ + Color.appBackground + LazyVGrid(columns: columns, spacing: spacing) { + Section { + ForEach(0.. some View { + Text(L10n.widgetShortWeekday(from: date, locale: locale)) + .appForeground(date.inWeekend ? .appSecondary : .appPrimary) + .sideLength(30) + } + + @ViewBuilder + private func dayView(appDate: AppDate) -> some View { + + let showHolidays = !appDate.inNormal && entry.showHolidays, + showEvents = appDate.events.isNotEmpty && entry.showEvents, + showLunar = entry.showLunar, + defaultColor: Color = appDate.inWeekend ? .appSecondary : .appPrimary, + inSameMonth = date.inSameMonth(as: appDate.date), + txColor: Color = appDate.onHoliday ? offBackground : .workBackground + + ZStack { + + if appDate.inToday { + RoundedRectangle(cornerRadius: 4) + .stroke(tint, lineWidth: 1) + } + + if showHolidays { + txColor.clipShape(.rect(cornerRadius: 4)) + Text(appDate.stateDesc) + .font(.system(size: 7, weight: .bold, design: .monospaced)) + .offset(x: -14, y: -14) + .appForeground(appDate.onHoliday ? tint: .appSecondary) + } + + if showEvents { + Circle() + .size(width: 5, height: 5) + .appForeground(tint) + .offset(x: 32, y: 3) + } + + VStack { + Text(appDate.title) + .font(.title3.monospacedDigit()) + .appForeground(showHolidays ? appDate.onHoliday ? tint: defaultColor : defaultColor) + if showLunar { + Text(appDate.subtitle) + .font(.caption2.weight(.regular)) + .appForeground(showHolidays ? appDate.onHoliday ? tint: .appSecondary : .appSecondary) + } + } + + } + .opacity(inSameMonth ? 1:0.3) + .sideLength(40) + + } + + @ViewBuilder + var header: some View { + HStack { + Text(L10n.widgetMonthSymbol(from: date.month, locale: locale)).font(.title2).appForeground(tint) + Text(date.year.description).font(.title2).appForeground(tint) + } + } +} + diff --git a/CalendarXWidget/en.lproj/CalendarXWidget.strings b/CalendarXWidget/en.lproj/CalendarXWidget.strings new file mode 100644 index 0000000..3a2494e --- /dev/null +++ b/CalendarXWidget/en.lproj/CalendarXWidget.strings @@ -0,0 +1,156 @@ +"0KwTK2" = "🟨"; + +"0x6ok8" = "🟦"; + +"23t8NN" = "Monday"; + +"2ZS03J" = "Language"; + +"2jywbx" = "true"; + +"3RKOOn" = "Show lunar calendar"; + +"3h5WUz" = "Light"; + +"4KRsdf" = "Widget Theme"; + +"4pjVKH" = "Theme"; + +"65ppC3" = "Widget Configuration"; + +"69LV8r" = "true"; + +"8R2rKx" = "Follow system"; + +"BxmIDl-3h5WUz" = "Just to confirm, you wanted ‘Light’?"; + +"BxmIDl-8R2rKx" = "Just to confirm, you wanted ‘Follow system’?"; + +"BxmIDl-ixslPm" = "Just to confirm, you wanted ‘Dark’?"; + +"CJwnoY" = "Widget Weekday"; + +"Cvj4om" = "🟩"; + +"EjYffU" = "Sunday"; + +"FtpWg1" = "🟥"; + +"JLPDos" = "Thursday"; + +"JMeC7c" = "Show calendar events"; + +"PHmfP2-0KwTK2" = "Just to confirm, you wanted ‘🟨’?"; + +"PHmfP2-0x6ok8" = "Just to confirm, you wanted ‘🟦’?"; + +"PHmfP2-Cvj4om" = "Just to confirm, you wanted ‘🟩’?"; + +"PHmfP2-FtpWg1" = "Just to confirm, you wanted ‘🟥’?"; + +"PHmfP2-PwlH5o" = "Just to confirm, you wanted ‘🟧’?"; + +"PHmfP2-emz1ih" = "Just to confirm, you wanted ‘🟪’?"; + +"PHmfP2-iZZDhi" = "Just to confirm, you wanted ‘🟫’?"; + +"PwlH5o" = "🟧"; + +"PyAT7j-0KwTK2" = "There are ${count} options matching ‘🟨’."; + +"PyAT7j-0x6ok8" = "There are ${count} options matching ‘🟦’."; + +"PyAT7j-Cvj4om" = "There are ${count} options matching ‘🟩’."; + +"PyAT7j-FtpWg1" = "There are ${count} options matching ‘🟥’."; + +"PyAT7j-PwlH5o" = "There are ${count} options matching ‘🟧’."; + +"PyAT7j-emz1ih" = "There are ${count} options matching ‘🟪’."; + +"PyAT7j-iZZDhi" = "There are ${count} options matching ‘🟫’."; + +"Qx5ip1-23t8NN" = "There are ${count} options matching ‘Monday’."; + +"Qx5ip1-EjYffU" = "There are ${count} options matching ‘Sunday’."; + +"Qx5ip1-JLPDos" = "There are ${count} options matching ‘Thursday’."; + +"Qx5ip1-RoHUik" = "There are ${count} options matching ‘Tuesday’."; + +"Qx5ip1-UouvsT" = "There are ${count} options matching ‘Friday’."; + +"Qx5ip1-YcSbEL" = "There are ${count} options matching ‘Saturday’."; + +"Qx5ip1-eStozH" = "There are ${count} options matching ‘Wednesday’."; + +"R74qr4" = "简体中文"; + +"RRB5Nx-R74qr4" = "Just to confirm, you wanted ‘简体中文’?"; + +"RRB5Nx-fxBCVh" = "Just to confirm, you wanted ‘Follow system’?"; + +"RRB5Nx-w8fWt0" = "Just to confirm, you wanted ‘English’?"; + +"RoHUik" = "Tuesday"; + +"UouvsT" = "Friday"; + +"Ur4lLP-3h5WUz" = "There are ${count} options matching ‘Light’."; + +"Ur4lLP-8R2rKx" = "There are ${count} options matching ‘Follow system’."; + +"Ur4lLP-ixslPm" = "There are ${count} options matching ‘Dark’."; + +"YcSbEL" = "Saturday"; + +"ZdFnbN" = "false"; + +"dWh2UQ" = "false"; + +"eStozH" = "Wednesday"; + +"emz1ih" = "🟪"; + +"fxBCVh" = "Follow system"; + +"h7F9C9-R74qr4" = "There are ${count} options matching ‘简体中文’."; + +"h7F9C9-fxBCVh" = "There are ${count} options matching ‘Follow system’."; + +"h7F9C9-w8fWt0" = "There are ${count} options matching ‘English’."; + +"iZZDhi" = "🟫"; + +"ixslPm" = "Dark"; + +"j5uOVs" = "Start week on"; + +"mch2I8" = "Widget Language"; + +"pikPQm" = "true"; + +"szmpx4" = "Widget Tint"; + +"veSx01" = "false"; + +"w5cj3i" = "Show Chinese statutory holidays"; + +"w8fWt0" = "English"; + +"wkmfzv" = "Tint"; + +"zNI9vB-23t8NN" = "Just to confirm, you wanted ‘Monday’?"; + +"zNI9vB-EjYffU" = "Just to confirm, you wanted ‘Sunday’?"; + +"zNI9vB-JLPDos" = "Just to confirm, you wanted ‘Thursday’?"; + +"zNI9vB-RoHUik" = "Just to confirm, you wanted ‘Tuesday’?"; + +"zNI9vB-UouvsT" = "Just to confirm, you wanted ‘Friday’?"; + +"zNI9vB-YcSbEL" = "Just to confirm, you wanted ‘Saturday’?"; + +"zNI9vB-eStozH" = "Just to confirm, you wanted ‘Wednesday’?"; + diff --git a/CalendarXWidget/en.lproj/Localizable.strings b/CalendarXWidget/en.lproj/Localizable.strings new file mode 100644 index 0000000..e5b7837 --- /dev/null +++ b/CalendarXWidget/en.lproj/Localizable.strings @@ -0,0 +1,9 @@ +/* + Localizable.strings + CalendarX + + Created by zm on 2023/12/19. + +*/ +"largeWidget.displayName" = "Month"; +"largeWidget.description" = "Track the day of the month."; diff --git a/CalendarXWidget/zh-Hans.lproj/CalendarXWidget.strings b/CalendarXWidget/zh-Hans.lproj/CalendarXWidget.strings new file mode 100644 index 0000000..9f41d23 --- /dev/null +++ b/CalendarXWidget/zh-Hans.lproj/CalendarXWidget.strings @@ -0,0 +1,156 @@ +"0KwTK2" = "🟨"; + +"0x6ok8" = "🟦"; + +"23t8NN" = "周一"; + +"2ZS03J" = "语言"; + +"2jywbx" = "true"; + +"3RKOOn" = "显示阴历"; + +"3h5WUz" = "浅色"; + +"4KRsdf" = "Widget Theme"; + +"4pjVKH" = "主题"; + +"65ppC3" = "Widget Configuration"; + +"69LV8r" = "true"; + +"8R2rKx" = "跟随系统"; + +"BxmIDl-3h5WUz" = "Just to confirm, you wanted ‘Light’?"; + +"BxmIDl-8R2rKx" = "Just to confirm, you wanted ‘Follow system’?"; + +"BxmIDl-ixslPm" = "Just to confirm, you wanted ‘Dark’?"; + +"CJwnoY" = "Widget Weekday"; + +"Cvj4om" = "🟩"; + +"EjYffU" = "周日"; + +"FtpWg1" = "🟥"; + +"JLPDos" = "周四"; + +"JMeC7c" = "显示日历事件"; + +"PHmfP2-0KwTK2" = "Just to confirm, you wanted ‘🟨’?"; + +"PHmfP2-0x6ok8" = "Just to confirm, you wanted ‘🟦’?"; + +"PHmfP2-Cvj4om" = "Just to confirm, you wanted ‘🟩’?"; + +"PHmfP2-FtpWg1" = "Just to confirm, you wanted ‘🟥’?"; + +"PHmfP2-PwlH5o" = "Just to confirm, you wanted ‘🟧’?"; + +"PHmfP2-emz1ih" = "Just to confirm, you wanted ‘🟪’?"; + +"PHmfP2-iZZDhi" = "Just to confirm, you wanted ‘🟫’?"; + +"PwlH5o" = "🟧"; + +"PyAT7j-0KwTK2" = "There are ${count} options matching ‘🟨’."; + +"PyAT7j-0x6ok8" = "There are ${count} options matching ‘🟦’."; + +"PyAT7j-Cvj4om" = "There are ${count} options matching ‘🟩’."; + +"PyAT7j-FtpWg1" = "There are ${count} options matching ‘🟥’."; + +"PyAT7j-PwlH5o" = "There are ${count} options matching ‘🟧’."; + +"PyAT7j-emz1ih" = "There are ${count} options matching ‘🟪’."; + +"PyAT7j-iZZDhi" = "There are ${count} options matching ‘🟫’."; + +"Qx5ip1-23t8NN" = "There are ${count} options matching ‘Monday’."; + +"Qx5ip1-EjYffU" = "There are ${count} options matching ‘Sunday’."; + +"Qx5ip1-JLPDos" = "There are ${count} options matching ‘Thursday’."; + +"Qx5ip1-RoHUik" = "There are ${count} options matching ‘Tuesday’."; + +"Qx5ip1-UouvsT" = "There are ${count} options matching ‘Friday’."; + +"Qx5ip1-YcSbEL" = "There are ${count} options matching ‘Saturday’."; + +"Qx5ip1-eStozH" = "There are ${count} options matching ‘Wednesday’."; + +"R74qr4" = "简体中文"; + +"RRB5Nx-R74qr4" = "Just to confirm, you wanted ‘简体中文’?"; + +"RRB5Nx-fxBCVh" = "Just to confirm, you wanted ‘Follow system’?"; + +"RRB5Nx-w8fWt0" = "Just to confirm, you wanted ‘English’?"; + +"RoHUik" = "周二"; + +"UouvsT" = "周五"; + +"Ur4lLP-3h5WUz" = "There are ${count} options matching ‘Light’."; + +"Ur4lLP-8R2rKx" = "There are ${count} options matching ‘Follow system’."; + +"Ur4lLP-ixslPm" = "There are ${count} options matching ‘Dark’."; + +"YcSbEL" = "周六"; + +"ZdFnbN" = "false"; + +"dWh2UQ" = "false"; + +"eStozH" = "周三"; + +"emz1ih" = "🟪"; + +"fxBCVh" = "跟随系统"; + +"h7F9C9-R74qr4" = "There are ${count} options matching ‘简体中文’."; + +"h7F9C9-fxBCVh" = "There are ${count} options matching ‘Follow system’."; + +"h7F9C9-w8fWt0" = "There are ${count} options matching ‘English’."; + +"iZZDhi" = "🟫"; + +"ixslPm" = "深色"; + +"j5uOVs" = "星期开始于"; + +"mch2I8" = "Widget Language"; + +"pikPQm" = "true"; + +"szmpx4" = "Widget Tint"; + +"veSx01" = "false"; + +"w5cj3i" = "显示中国法定假日"; + +"w8fWt0" = "English"; + +"wkmfzv" = "色彩"; + +"zNI9vB-23t8NN" = "Just to confirm, you wanted ‘Monday’?"; + +"zNI9vB-EjYffU" = "Just to confirm, you wanted ‘Sunday’?"; + +"zNI9vB-JLPDos" = "Just to confirm, you wanted ‘Thursday’?"; + +"zNI9vB-RoHUik" = "Just to confirm, you wanted ‘Tuesday’?"; + +"zNI9vB-UouvsT" = "Just to confirm, you wanted ‘Friday’?"; + +"zNI9vB-YcSbEL" = "Just to confirm, you wanted ‘Saturday’?"; + +"zNI9vB-eStozH" = "Just to confirm, you wanted ‘Wednesday’?"; + diff --git a/CalendarXWidget/zh-Hans.lproj/Localizable.strings b/CalendarXWidget/zh-Hans.lproj/Localizable.strings new file mode 100644 index 0000000..6d48a49 --- /dev/null +++ b/CalendarXWidget/zh-Hans.lproj/Localizable.strings @@ -0,0 +1,9 @@ +/* + Localizable.strings + CalendarX + + Created by zm on 2023/12/19. + +*/ +"largeWidget.displayName" = "月"; +"largeWidget.description" = "追踪当月日期。"; diff --git a/README.md b/README.md index 9fb21c0..f2c242a 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ A lightweight macOS app for displaying calendar and time - [x] Custom menubar styles (default, text, date & time) - [x] Dark mode - [x] Localization (简体中文、English) +- [x] Widget - [x] SwiftUI / Async / Await ## Compatibility @@ -28,23 +29,39 @@ A lightweight macOS app for displaying calendar and time ## Snapshots - Calendar - left click to show - - - + + - Settings - right click to show - + + + - +- Menubar Date&Time Style - drag and drop to edit - + -- Menubar Date&Time Style - drag and drop to edit +- Widget & Edit + + + + +## FAQ + +1. **"CalendarX.dmg" can't be opened.** + + - - +1. **"CalendarX" can't be opened.** + + + **Or open `Terminal` and run** + + ``` shell + sudo xattr -r -d com.apple.quarantine /Applications/CalendarX.app + ``` ## Dependencies - [Sparkle](https://github.com/sparkle-project/Sparkle) diff --git a/assets/001.png b/assets/001.png new file mode 100644 index 0000000..782cc88 Binary files /dev/null and b/assets/001.png differ diff --git a/assets/002.png b/assets/002.png new file mode 100644 index 0000000..ee1c5ba Binary files /dev/null and b/assets/002.png differ diff --git a/assets/003.png b/assets/003.png new file mode 100644 index 0000000..5b9e084 Binary files /dev/null and b/assets/003.png differ diff --git a/assets/004.png b/assets/004.png new file mode 100644 index 0000000..13ca0f8 Binary files /dev/null and b/assets/004.png differ diff --git a/assets/005.png b/assets/005.png new file mode 100644 index 0000000..61fa0cb Binary files /dev/null and b/assets/005.png differ diff --git a/assets/006.png b/assets/006.png new file mode 100644 index 0000000..d31f938 Binary files /dev/null and b/assets/006.png differ diff --git a/assets/007.png b/assets/007.png new file mode 100644 index 0000000..4ab4bf9 Binary files /dev/null and b/assets/007.png differ diff --git a/assets/008.png b/assets/008.png new file mode 100644 index 0000000..9a7c362 Binary files /dev/null and b/assets/008.png differ diff --git a/assets/101.png b/assets/101.png new file mode 100644 index 0000000..6c57fa5 Binary files /dev/null and b/assets/101.png differ diff --git a/assets/102.png b/assets/102.png new file mode 100644 index 0000000..ea42f77 Binary files /dev/null and b/assets/102.png differ diff --git a/assets/cd01.png b/assets/cd01.png deleted file mode 100644 index 9e3197e..0000000 Binary files a/assets/cd01.png and /dev/null differ diff --git a/assets/cd02.png b/assets/cd02.png deleted file mode 100644 index 66f8f61..0000000 Binary files a/assets/cd02.png and /dev/null differ diff --git a/assets/cl01.png b/assets/cl01.png deleted file mode 100644 index baa03f1..0000000 Binary files a/assets/cl01.png and /dev/null differ diff --git a/assets/cl02.png b/assets/cl02.png deleted file mode 100644 index 566a344..0000000 Binary files a/assets/cl02.png and /dev/null differ diff --git a/assets/sd01.png b/assets/sd01.png deleted file mode 100644 index 9bfb06e..0000000 Binary files a/assets/sd01.png and /dev/null differ diff --git a/assets/sd02.png b/assets/sd02.png deleted file mode 100644 index 28dac89..0000000 Binary files a/assets/sd02.png and /dev/null differ diff --git a/assets/sd03.png b/assets/sd03.png deleted file mode 100644 index 6bfcfb9..0000000 Binary files a/assets/sd03.png and /dev/null differ diff --git a/assets/sd04.png b/assets/sd04.png deleted file mode 100644 index 9b5ca44..0000000 Binary files a/assets/sd04.png and /dev/null differ diff --git a/assets/sign_update b/assets/sign_update deleted file mode 100755 index bae93fb..0000000 Binary files a/assets/sign_update and /dev/null differ diff --git a/assets/sl01.png b/assets/sl01.png deleted file mode 100644 index 9b3572e..0000000 Binary files a/assets/sl01.png and /dev/null differ diff --git a/assets/sl02.png b/assets/sl02.png deleted file mode 100644 index f5ea839..0000000 Binary files a/assets/sl02.png and /dev/null differ diff --git a/assets/sl03.png b/assets/sl03.png deleted file mode 100644 index 6b0959f..0000000 Binary files a/assets/sl03.png and /dev/null differ diff --git a/assets/sl04.png b/assets/sl04.png deleted file mode 100644 index 92d1f56..0000000 Binary files a/assets/sl04.png and /dev/null differ diff --git a/bin/sign_update b/bin/sign_update new file mode 100755 index 0000000..90bd66b Binary files /dev/null and b/bin/sign_update differ diff --git a/changelogs/CHANGELOG.md b/changelogs/CHANGELOG.md index 8dc853e..42a9ab5 100644 --- a/changelogs/CHANGELOG.md +++ b/changelogs/CHANGELOG.md @@ -1,3 +1,17 @@ +## 2.3.2 - 2023-12-19 + +### Added +- Calendar Widget +- Chinese statutory holidays in 2024 + +### Fixed +- Menu bar date style drag and drop editing issue + +### Changed +- Transition animations +- Alert View + +--- ## 2.3.1 - 2023-03-09 ### Fixed diff --git a/changelogs/CHANGELOG_SC.md b/changelogs/CHANGELOG_SC.md index 8a84e84..41ce352 100644 --- a/changelogs/CHANGELOG_SC.md +++ b/changelogs/CHANGELOG_SC.md @@ -1,3 +1,18 @@ +## 2.3.2 - 2023-12-19 + +### Added +- 日历小组件 +- 2024 年中国法定节假日 + +### Fixed +- 菜单栏日期样式拖拽编辑问题 + +### Changed +- 过渡动画 +- 提醒窗 + +--- + ## 2.3.1 - 2023-03-09 ### Fixed diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 1f99009..e0ca423 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -2,43 +2,24 @@ default_platform(:mac) platform :mac do - lane :package do - setup(name: ENV["APP_NAME"], version: ENV["APP_VERSION"]) - build - clean + before_all do + ENV["APP_NAME"] = "CalendarX" + ENV["APP_VERSION"] = last_git_tag + ENV["SYS_MIN_VERSION"] = "11.0.0" + ENV["BUILD_PATH"] = "./build" end - lane :test do |options| - setup(name: options[:name], version: options[:version]) + lane :create_dmg do + setup build clean - end - - lane :release do |options| - - name = options[:name] - repo = options[:repo] - tag = options[:tag] - token = options[:token] - - github_release = set_github_release( - repository_name: repo, - api_token: token, - name: tag, - tag_name: tag, - description: (File.read("../TEST.md") rescue "No changelog provided"), - upload_assets: ["#{name}.dmg"]) - end - - lane :show do - msg = File.read("../TEST.md") - UI.message msg + sh "cd .. && zsh ./scripts/create_dmg.sh" end - private_lane :setup do |options| + private_lane :setup do - name = options[:name] - version = options[:version] + name = ENV["APP_NAME"] + version = ENV["APP_VERSION"] commit = last_git_commit date = Time.now.utc.localtime("+08:00").strftime("%Y.%m.%d %k:%M") @@ -52,11 +33,14 @@ platform :mac do end private_lane :build do - - build_app( + + build_mac_app( + scheme: ENV["APP_NAME"], clean: true, silent: true, - export_method: 'mac-application') + export_method: "mac-application", + output_directory: ENV["BUILD_PATH"]) + end private_lane :clean do @@ -64,4 +48,37 @@ platform :mac do end + # TEST + lane :test do |options| + setup + build + clean + sh "cd .. && zsh ./scripts/test.sh" + end + + # lane :release do |options| + + # name = ENV["APP_NAME"] + # tag = ENV["APP_VERSION"] + + # repo = options[:repo] + # token = options[:token] + + # github_release = set_github_release( + # repository_name: repo, + # api_token: token, + # name: tag, + # tag_name: tag, + # description: (File.read("../TEST.md") rescue "No changelog provided"), + # upload_assets: ["#{name}.dmg"]) + + # end + + lane :show do + # msg = File.read("../TEST.md") + UI.message ENV["APP_NAME"] + UI.message ENV["APP_VERSION"] + end + + end diff --git a/fastlane/README.md b/fastlane/README.md index eca4b40..ee67493 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -15,10 +15,10 @@ For _fastlane_ installation instructions, see [Installing _fastlane_](https://do ## Mac -### mac package +### mac create_dmg ```sh -[bundle exec] fastlane mac package +[bundle exec] fastlane mac create_dmg ``` @@ -31,14 +31,6 @@ For _fastlane_ installation instructions, see [Installing _fastlane_](https://do -### mac release - -```sh -[bundle exec] fastlane mac release -``` - - - ### mac show ```sh diff --git a/scripts/create_dmg.sh b/scripts/create_dmg.sh index 61ebc71..19ac7fd 100755 --- a/scripts/create_dmg.sh +++ b/scripts/create_dmg.sh @@ -1,45 +1,41 @@ - - -function transform() { +function __transform() { local changelog=`cat $1` changelog=${changelog%%---*} changelog=${changelog#*###} changelog="###$changelog" - echo "$changelog" +function __sparkle_enclosure() { + local app_path=$BUILD_PATH/$APP_NAME.dmg + echo "APP_PATH=$app_path" >> "$GITHUB_ENV" + local signature=`echo $SPARKLE_KEY | ./bin/sign_update -f - $app_path` + local enclosure="$APP_VERSION + $SYS_MIN_VERSION + " echo $enclosure } -function generate_changlog() { - echo "$(transform changelogs/CHANGELOG.md)" > $BODY_PATH - echo "$(transform changelogs/CHANGELOG_SC.md)" >> $BODY_PATH - echo $(sparkle_enclosure) >> $BODY_PATH -} - - function create_dmg() { + cd $BUILD_PATH + if [ -f "$APP_NAME.app.dSYM.zip" ]; then + python3 -m pip install setuptools npm install --global create-dmg create-dmg $APP_NAME.app mv $APP_NAME*.dmg $APP_NAME.dmg + else + UI.user_error!("💥 $APP_NAME.app does not exist.") + fi + cd .. } -function test() { - - echo "$(transform CHANGELOG.md)" > TEST.md - echo "$(transform CHANGELOG_SC.md)" >> TEST.md - +function generate_changlog() { + local log_path=$BUILD_PATH/TMP.md + echo "LOG_PATH=$log_path" >> "$GITHUB_ENV" + echo "$(__transform changelogs/CHANGELOG.md)" > $log_path + echo "$(__transform changelogs/CHANGELOG_SC.md)" >> $log_path + echo $(__sparkle_enclosure) >> $log_path } -# test -create_dmg -generate_changlog - +create_dmg +generate_changlog \ No newline at end of file