├── CalendarHero.acorn ├── CalendarHero ├── Assets.xcassets │ ├── Contents.json │ ├── AppIcon.appiconset │ │ ├── icon-128.png │ │ ├── icon-16.png │ │ ├── icon-256.png │ │ ├── icon-32.png │ │ ├── icon-512.png │ │ ├── icon-16@2x.png │ │ ├── icon-32@2x.png │ │ ├── icon-128@2x.png │ │ ├── icon-256@2x.png │ │ ├── icon-512@2x.png │ │ └── Contents.json │ └── AccentColor.colorset │ │ └── Contents.json ├── CalendarHero.entitlements ├── AppDelegate.swift ├── Info.plist ├── Window.swift ├── ViewController.swift └── Base.lproj │ └── Main.storyboard ├── Calendar Hero.xcodeproj ├── xcuserdata │ └── thall.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── project.pbxproj └── README.md /CalendarHero.acorn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/CalendarHero/main/CalendarHero.acorn -------------------------------------------------------------------------------- /CalendarHero/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /CalendarHero/Assets.xcassets/AppIcon.appiconset/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/CalendarHero/main/CalendarHero/Assets.xcassets/AppIcon.appiconset/icon-128.png -------------------------------------------------------------------------------- /CalendarHero/Assets.xcassets/AppIcon.appiconset/icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/CalendarHero/main/CalendarHero/Assets.xcassets/AppIcon.appiconset/icon-16.png -------------------------------------------------------------------------------- /CalendarHero/Assets.xcassets/AppIcon.appiconset/icon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/CalendarHero/main/CalendarHero/Assets.xcassets/AppIcon.appiconset/icon-256.png -------------------------------------------------------------------------------- /CalendarHero/Assets.xcassets/AppIcon.appiconset/icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/CalendarHero/main/CalendarHero/Assets.xcassets/AppIcon.appiconset/icon-32.png -------------------------------------------------------------------------------- /CalendarHero/Assets.xcassets/AppIcon.appiconset/icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/CalendarHero/main/CalendarHero/Assets.xcassets/AppIcon.appiconset/icon-512.png -------------------------------------------------------------------------------- /CalendarHero/Assets.xcassets/AppIcon.appiconset/icon-16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/CalendarHero/main/CalendarHero/Assets.xcassets/AppIcon.appiconset/icon-16@2x.png -------------------------------------------------------------------------------- /CalendarHero/Assets.xcassets/AppIcon.appiconset/icon-32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/CalendarHero/main/CalendarHero/Assets.xcassets/AppIcon.appiconset/icon-32@2x.png -------------------------------------------------------------------------------- /CalendarHero/Assets.xcassets/AppIcon.appiconset/icon-128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/CalendarHero/main/CalendarHero/Assets.xcassets/AppIcon.appiconset/icon-128@2x.png -------------------------------------------------------------------------------- /CalendarHero/Assets.xcassets/AppIcon.appiconset/icon-256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/CalendarHero/main/CalendarHero/Assets.xcassets/AppIcon.appiconset/icon-256@2x.png -------------------------------------------------------------------------------- /CalendarHero/Assets.xcassets/AppIcon.appiconset/icon-512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/CalendarHero/main/CalendarHero/Assets.xcassets/AppIcon.appiconset/icon-512@2x.png -------------------------------------------------------------------------------- /CalendarHero/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Calendar Hero.xcodeproj/xcuserdata/thall.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /Calendar Hero.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Calendar Hero.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CalendarHero/CalendarHero.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | com.apple.security.personal-information.calendars 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Calendar Hero.xcodeproj/xcuserdata/thall.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Calendar Hero.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | CalendarHero.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /CalendarHero/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // CalendarHero 4 | // 5 | // Created by Tyler Hall on 2/17/21. 6 | // 7 | 8 | import Cocoa 9 | 10 | @main 11 | class AppDelegate: NSObject, NSApplicationDelegate { 12 | 13 | func applicationDidBecomeActive(_ notification: Notification) { 14 | for window in NSApp.windows { 15 | (window as? Window)?.updateStyle() 16 | } 17 | } 18 | 19 | func applicationDidResignActive(_ notification: Notification) { 20 | for window in NSApp.windows { 21 | (window as? Window)?.updateStyle() 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Calendar Hero 2 | 3 | [https://tyler.io/calendar-hero/](https://tyler.io/calendar-hero/) 4 | 5 | MIT License 6 | 7 | Copyright 2021 Tyler Hall 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | -------------------------------------------------------------------------------- /CalendarHero/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSMainStoryboardFile 26 | Main 27 | NSPrincipalClass 28 | NSApplication 29 | NSCalendarsUsageDescription 30 | Dispaly your calendars. 31 | LSUIElement 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /CalendarHero/Window.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Window.swift 3 | // CalendarHero 4 | // 5 | // Created by Tyler Hall on 2/17/21. 6 | // 7 | 8 | import Cocoa 9 | 10 | class Window: NSWindow { 11 | 12 | func updateStyle() { 13 | standardWindowButton(.miniaturizeButton)?.isHidden = true 14 | standardWindowButton(.zoomButton)?.isHidden = true 15 | standardWindowButton(.closeButton)?.isHidden = true 16 | 17 | collectionBehavior = .stationary 18 | 19 | if NSApp.isActive { 20 | styleMask = [.resizable, .fullSizeContentView, .titled] 21 | ignoresMouseEvents = false 22 | level = .normal 23 | isOpaque = true 24 | backgroundColor = .windowBackgroundColor 25 | } else { 26 | styleMask = [.borderless, .fullSizeContentView] 27 | ignoresMouseEvents = true 28 | orderBack(nil) 29 | level = NSWindow.Level.init(Int(CGWindowLevelForKey(CGWindowLevelKey.desktopWindow))) 30 | isOpaque = false 31 | backgroundColor = .clear 32 | } 33 | } 34 | 35 | override var tabbingMode: NSWindow.TabbingMode { 36 | get { 37 | return .disallowed 38 | } 39 | set { 40 | 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /CalendarHero/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "icon-16.png", 5 | "idiom" : "mac", 6 | "scale" : "1x", 7 | "size" : "16x16" 8 | }, 9 | { 10 | "filename" : "icon-16@2x.png", 11 | "idiom" : "mac", 12 | "scale" : "2x", 13 | "size" : "16x16" 14 | }, 15 | { 16 | "filename" : "icon-32.png", 17 | "idiom" : "mac", 18 | "scale" : "1x", 19 | "size" : "32x32" 20 | }, 21 | { 22 | "filename" : "icon-32@2x.png", 23 | "idiom" : "mac", 24 | "scale" : "2x", 25 | "size" : "32x32" 26 | }, 27 | { 28 | "filename" : "icon-128.png", 29 | "idiom" : "mac", 30 | "scale" : "1x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "filename" : "icon-128@2x.png", 35 | "idiom" : "mac", 36 | "scale" : "2x", 37 | "size" : "128x128" 38 | }, 39 | { 40 | "filename" : "icon-256.png", 41 | "idiom" : "mac", 42 | "scale" : "1x", 43 | "size" : "256x256" 44 | }, 45 | { 46 | "filename" : "icon-256@2x.png", 47 | "idiom" : "mac", 48 | "scale" : "2x", 49 | "size" : "256x256" 50 | }, 51 | { 52 | "filename" : "icon-512.png", 53 | "idiom" : "mac", 54 | "scale" : "1x", 55 | "size" : "512x512" 56 | }, 57 | { 58 | "filename" : "icon-512@2x.png", 59 | "idiom" : "mac", 60 | "scale" : "2x", 61 | "size" : "512x512" 62 | } 63 | ], 64 | "info" : { 65 | "author" : "xcode", 66 | "version" : 1 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /CalendarHero/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // CalendarHero 4 | // 5 | // Created by Tyler Hall on 2/17/21. 6 | // 7 | 8 | import Cocoa 9 | import EventKit 10 | 11 | class ViewController: NSViewController { 12 | 13 | @IBOutlet weak var nextEventCountdownTextField: NSTextField! 14 | @IBOutlet weak var weekStackView: NSStackView! 15 | 16 | let store = EKEventStore() 17 | 18 | let startHour = 0 19 | let endHour = 23 20 | 21 | // This is just a wrapper around the current date, 22 | // so I can test other dates during development. 23 | var theDate: Date { 24 | return Date() // Date(timeIntervalSinceNow: 3600 * 6) 25 | } 26 | 27 | var start: Date { 28 | return Calendar.current.date(from: Calendar.current.dateComponents([.yearForWeekOfYear, .weekOfYear], from: theDate))! 29 | } 30 | 31 | var end: Date { 32 | return Date(timeInterval: 86400 * 7, since: start) 33 | } 34 | 35 | var refreshTimer: Timer? 36 | 37 | override func viewDidLoad() { 38 | super.viewDidLoad() 39 | 40 | nextEventCountdownTextField.stringValue = "" 41 | 42 | setup() 43 | 44 | refreshTimer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true, block: { [weak self] (timer) in 45 | self?.loadCalendars() 46 | }) 47 | } 48 | 49 | @objc func calendarDidChange(_ notification: Notification) { 50 | loadCalendars() 51 | } 52 | 53 | func setup() { 54 | for i in 0..<7 { 55 | let dayStackView = DayStackView(views: []) 56 | dayStackView.orientation = .vertical 57 | dayStackView.distribution = .fillEqually 58 | dayStackView.alignment = .leading 59 | 60 | weekStackView.insertArrangedSubview(dayStackView, at: i) 61 | 62 | var pos = 0 63 | for _ in startHour.. NSStackView? { 132 | guard !event.isAllDay else { return nil } 133 | 134 | var day = 0 135 | while event.startDate > Date(timeInterval: Double((day + 1) * 86400), since: start) { 136 | day += 1 137 | } 138 | 139 | guard (0 <= day) && (day <= 7) else { return nil } 140 | 141 | let hour = Calendar.current.component(.hour, from: event.startDate) 142 | guard (startHour <= hour) && (hour <= endHour) else { return nil } 143 | 144 | let dayStackView = weekStackView.arrangedSubviews[day] as! NSStackView 145 | let hourStackView = dayStackView.arrangedSubviews[hour] as! NSStackView 146 | 147 | return hourStackView 148 | } 149 | 150 | func calculateNextEvent() { 151 | let offsetStart = Date() 152 | let aDayFromNow = Date(timeIntervalSinceNow: 86400 * 3) // Just a random future date. 153 | let predicate = self.store.predicateForEvents(withStart: offsetStart, end: aDayFromNow, calendars: nil) 154 | let events = self.store.events(matching: predicate) 155 | 156 | // I couldn't find where it's guaranteed events come back sorted, 157 | // so let's do that just to be safe. 158 | let sortedEvents = events.sorted { (a, b) -> Bool in 159 | return a.startDate < b.startDate 160 | } 161 | 162 | if let nextEvent = sortedEvents.first(where: { (event) -> Bool in 163 | return !event.isAllDay && (offsetStart < event.startDate) 164 | }) { 165 | let df = RelativeDateTimeFormatter() 166 | nextEventCountdownTextField.stringValue = "Next event " + df.localizedString(fromTimeInterval: nextEvent.startDate.timeIntervalSinceNow) 167 | } else { 168 | nextEventCountdownTextField.stringValue = "" 169 | } 170 | } 171 | } 172 | 173 | class HourStackView: DayStackView { 174 | 175 | } 176 | 177 | class DayStackView: NSStackView { 178 | 179 | var backgroundColor: NSColor? 180 | 181 | override func draw(_ dirtyRect: NSRect) { 182 | if let backgroundColor = backgroundColor { 183 | let path = NSBezierPath(roundedRect: bounds, xRadius: 8, yRadius: 8) 184 | backgroundColor.setFill() 185 | path.fill() 186 | } 187 | super.draw(dirtyRect) 188 | } 189 | } 190 | 191 | class EventBubbleView: NSTextField { 192 | 193 | override var intrinsicContentSize: NSSize { 194 | let size = super.intrinsicContentSize 195 | return NSSize(width: size.width + 32, height: size.height + 16) 196 | } 197 | 198 | override func draw(_ dirtyRect: NSRect) { 199 | let path = NSBezierPath(roundedRect: bounds, xRadius: 8, yRadius: 8) 200 | backgroundColor?.setFill() 201 | path.fill() 202 | super.draw(dirtyRect) 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /Calendar Hero.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C6C7634025DD79C600E466D7 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6C7633F25DD79C600E466D7 /* AppDelegate.swift */; }; 11 | C6C7634225DD79C600E466D7 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6C7634125DD79C600E466D7 /* ViewController.swift */; }; 12 | C6C7634425DD79C800E466D7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C6C7634325DD79C800E466D7 /* Assets.xcassets */; }; 13 | C6C7634725DD79C800E466D7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C6C7634525DD79C800E466D7 /* Main.storyboard */; }; 14 | C6C7635825DD8CE200E466D7 /* Window.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6C7635725DD8CE200E466D7 /* Window.swift */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXFileReference section */ 18 | C6C7633C25DD79C600E466D7 /* Calendar Hero.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Calendar Hero.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 19 | C6C7633F25DD79C600E466D7 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 20 | C6C7634125DD79C600E466D7 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 21 | C6C7634325DD79C800E466D7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 22 | C6C7634625DD79C800E466D7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 23 | C6C7634825DD79C800E466D7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 24 | C6C7634925DD79C800E466D7 /* CalendarHero.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = CalendarHero.entitlements; sourceTree = ""; }; 25 | C6C7635725DD8CE200E466D7 /* Window.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Window.swift; sourceTree = ""; }; 26 | /* End PBXFileReference section */ 27 | 28 | /* Begin PBXFrameworksBuildPhase section */ 29 | C6C7633925DD79C600E466D7 /* Frameworks */ = { 30 | isa = PBXFrameworksBuildPhase; 31 | buildActionMask = 2147483647; 32 | files = ( 33 | ); 34 | runOnlyForDeploymentPostprocessing = 0; 35 | }; 36 | /* End PBXFrameworksBuildPhase section */ 37 | 38 | /* Begin PBXGroup section */ 39 | C6C7633325DD79C600E466D7 = { 40 | isa = PBXGroup; 41 | children = ( 42 | C6C7633E25DD79C600E466D7 /* CalendarHero */, 43 | C6C7633D25DD79C600E466D7 /* Products */, 44 | ); 45 | sourceTree = ""; 46 | }; 47 | C6C7633D25DD79C600E466D7 /* Products */ = { 48 | isa = PBXGroup; 49 | children = ( 50 | C6C7633C25DD79C600E466D7 /* Calendar Hero.app */, 51 | ); 52 | name = Products; 53 | sourceTree = ""; 54 | }; 55 | C6C7633E25DD79C600E466D7 /* CalendarHero */ = { 56 | isa = PBXGroup; 57 | children = ( 58 | C6C7633F25DD79C600E466D7 /* AppDelegate.swift */, 59 | C6C7635725DD8CE200E466D7 /* Window.swift */, 60 | C6C7634125DD79C600E466D7 /* ViewController.swift */, 61 | C6C7634325DD79C800E466D7 /* Assets.xcassets */, 62 | C6C7634525DD79C800E466D7 /* Main.storyboard */, 63 | C6C7634825DD79C800E466D7 /* Info.plist */, 64 | C6C7634925DD79C800E466D7 /* CalendarHero.entitlements */, 65 | ); 66 | path = CalendarHero; 67 | sourceTree = ""; 68 | }; 69 | /* End PBXGroup section */ 70 | 71 | /* Begin PBXNativeTarget section */ 72 | C6C7633B25DD79C600E466D7 /* Calendar Hero */ = { 73 | isa = PBXNativeTarget; 74 | buildConfigurationList = C6C7634C25DD79C800E466D7 /* Build configuration list for PBXNativeTarget "Calendar Hero" */; 75 | buildPhases = ( 76 | C6C7633825DD79C600E466D7 /* Sources */, 77 | C6C7633925DD79C600E466D7 /* Frameworks */, 78 | C6C7633A25DD79C600E466D7 /* Resources */, 79 | ); 80 | buildRules = ( 81 | ); 82 | dependencies = ( 83 | ); 84 | name = "Calendar Hero"; 85 | productName = CalendarHero; 86 | productReference = C6C7633C25DD79C600E466D7 /* Calendar Hero.app */; 87 | productType = "com.apple.product-type.application"; 88 | }; 89 | /* End PBXNativeTarget section */ 90 | 91 | /* Begin PBXProject section */ 92 | C6C7633425DD79C600E466D7 /* Project object */ = { 93 | isa = PBXProject; 94 | attributes = { 95 | LastSwiftUpdateCheck = 1220; 96 | LastUpgradeCheck = 1220; 97 | TargetAttributes = { 98 | C6C7633B25DD79C600E466D7 = { 99 | CreatedOnToolsVersion = 12.2; 100 | }; 101 | }; 102 | }; 103 | buildConfigurationList = C6C7633725DD79C600E466D7 /* Build configuration list for PBXProject "Calendar Hero" */; 104 | compatibilityVersion = "Xcode 9.3"; 105 | developmentRegion = en; 106 | hasScannedForEncodings = 0; 107 | knownRegions = ( 108 | en, 109 | Base, 110 | ); 111 | mainGroup = C6C7633325DD79C600E466D7; 112 | productRefGroup = C6C7633D25DD79C600E466D7 /* Products */; 113 | projectDirPath = ""; 114 | projectRoot = ""; 115 | targets = ( 116 | C6C7633B25DD79C600E466D7 /* Calendar Hero */, 117 | ); 118 | }; 119 | /* End PBXProject section */ 120 | 121 | /* Begin PBXResourcesBuildPhase section */ 122 | C6C7633A25DD79C600E466D7 /* Resources */ = { 123 | isa = PBXResourcesBuildPhase; 124 | buildActionMask = 2147483647; 125 | files = ( 126 | C6C7634425DD79C800E466D7 /* Assets.xcassets in Resources */, 127 | C6C7634725DD79C800E466D7 /* Main.storyboard in Resources */, 128 | ); 129 | runOnlyForDeploymentPostprocessing = 0; 130 | }; 131 | /* End PBXResourcesBuildPhase section */ 132 | 133 | /* Begin PBXSourcesBuildPhase section */ 134 | C6C7633825DD79C600E466D7 /* Sources */ = { 135 | isa = PBXSourcesBuildPhase; 136 | buildActionMask = 2147483647; 137 | files = ( 138 | C6C7634225DD79C600E466D7 /* ViewController.swift in Sources */, 139 | C6C7634025DD79C600E466D7 /* AppDelegate.swift in Sources */, 140 | C6C7635825DD8CE200E466D7 /* Window.swift in Sources */, 141 | ); 142 | runOnlyForDeploymentPostprocessing = 0; 143 | }; 144 | /* End PBXSourcesBuildPhase section */ 145 | 146 | /* Begin PBXVariantGroup section */ 147 | C6C7634525DD79C800E466D7 /* Main.storyboard */ = { 148 | isa = PBXVariantGroup; 149 | children = ( 150 | C6C7634625DD79C800E466D7 /* Base */, 151 | ); 152 | name = Main.storyboard; 153 | sourceTree = ""; 154 | }; 155 | /* End PBXVariantGroup section */ 156 | 157 | /* Begin XCBuildConfiguration section */ 158 | C6C7634A25DD79C800E466D7 /* Debug */ = { 159 | isa = XCBuildConfiguration; 160 | buildSettings = { 161 | ALWAYS_SEARCH_USER_PATHS = NO; 162 | CLANG_ANALYZER_NONNULL = YES; 163 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 164 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 165 | CLANG_CXX_LIBRARY = "libc++"; 166 | CLANG_ENABLE_MODULES = YES; 167 | CLANG_ENABLE_OBJC_ARC = YES; 168 | CLANG_ENABLE_OBJC_WEAK = YES; 169 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 170 | CLANG_WARN_BOOL_CONVERSION = YES; 171 | CLANG_WARN_COMMA = YES; 172 | CLANG_WARN_CONSTANT_CONVERSION = YES; 173 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 174 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 175 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 176 | CLANG_WARN_EMPTY_BODY = YES; 177 | CLANG_WARN_ENUM_CONVERSION = YES; 178 | CLANG_WARN_INFINITE_RECURSION = YES; 179 | CLANG_WARN_INT_CONVERSION = YES; 180 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 181 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 182 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 183 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 184 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 185 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 186 | CLANG_WARN_STRICT_PROTOTYPES = YES; 187 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 188 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 189 | CLANG_WARN_UNREACHABLE_CODE = YES; 190 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 191 | COPY_PHASE_STRIP = NO; 192 | DEBUG_INFORMATION_FORMAT = dwarf; 193 | ENABLE_STRICT_OBJC_MSGSEND = YES; 194 | ENABLE_TESTABILITY = YES; 195 | GCC_C_LANGUAGE_STANDARD = gnu11; 196 | GCC_DYNAMIC_NO_PIC = NO; 197 | GCC_NO_COMMON_BLOCKS = YES; 198 | GCC_OPTIMIZATION_LEVEL = 0; 199 | GCC_PREPROCESSOR_DEFINITIONS = ( 200 | "DEBUG=1", 201 | "$(inherited)", 202 | ); 203 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 204 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 205 | GCC_WARN_UNDECLARED_SELECTOR = YES; 206 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 207 | GCC_WARN_UNUSED_FUNCTION = YES; 208 | GCC_WARN_UNUSED_VARIABLE = YES; 209 | MACOSX_DEPLOYMENT_TARGET = 10.15; 210 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 211 | MTL_FAST_MATH = YES; 212 | ONLY_ACTIVE_ARCH = YES; 213 | SDKROOT = macosx; 214 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 215 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 216 | }; 217 | name = Debug; 218 | }; 219 | C6C7634B25DD79C800E466D7 /* Release */ = { 220 | isa = XCBuildConfiguration; 221 | buildSettings = { 222 | ALWAYS_SEARCH_USER_PATHS = NO; 223 | CLANG_ANALYZER_NONNULL = YES; 224 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 225 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 226 | CLANG_CXX_LIBRARY = "libc++"; 227 | CLANG_ENABLE_MODULES = YES; 228 | CLANG_ENABLE_OBJC_ARC = YES; 229 | CLANG_ENABLE_OBJC_WEAK = YES; 230 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 231 | CLANG_WARN_BOOL_CONVERSION = YES; 232 | CLANG_WARN_COMMA = YES; 233 | CLANG_WARN_CONSTANT_CONVERSION = YES; 234 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 235 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 236 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 237 | CLANG_WARN_EMPTY_BODY = YES; 238 | CLANG_WARN_ENUM_CONVERSION = YES; 239 | CLANG_WARN_INFINITE_RECURSION = YES; 240 | CLANG_WARN_INT_CONVERSION = YES; 241 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 242 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 243 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 244 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 245 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 246 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 247 | CLANG_WARN_STRICT_PROTOTYPES = YES; 248 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 249 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 250 | CLANG_WARN_UNREACHABLE_CODE = YES; 251 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 252 | COPY_PHASE_STRIP = NO; 253 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 254 | ENABLE_NS_ASSERTIONS = NO; 255 | ENABLE_STRICT_OBJC_MSGSEND = YES; 256 | GCC_C_LANGUAGE_STANDARD = gnu11; 257 | GCC_NO_COMMON_BLOCKS = YES; 258 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 259 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 260 | GCC_WARN_UNDECLARED_SELECTOR = YES; 261 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 262 | GCC_WARN_UNUSED_FUNCTION = YES; 263 | GCC_WARN_UNUSED_VARIABLE = YES; 264 | MACOSX_DEPLOYMENT_TARGET = 10.15; 265 | MTL_ENABLE_DEBUG_INFO = NO; 266 | MTL_FAST_MATH = YES; 267 | SDKROOT = macosx; 268 | SWIFT_COMPILATION_MODE = wholemodule; 269 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 270 | }; 271 | name = Release; 272 | }; 273 | C6C7634D25DD79C800E466D7 /* Debug */ = { 274 | isa = XCBuildConfiguration; 275 | buildSettings = { 276 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 277 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 278 | CODE_SIGN_ENTITLEMENTS = CalendarHero/CalendarHero.entitlements; 279 | CODE_SIGN_STYLE = Automatic; 280 | COMBINE_HIDPI_IMAGES = YES; 281 | DEVELOPMENT_TEAM = 3A6K89K388; 282 | ENABLE_HARDENED_RUNTIME = YES; 283 | INFOPLIST_FILE = CalendarHero/Info.plist; 284 | LD_RUNPATH_SEARCH_PATHS = ( 285 | "$(inherited)", 286 | "@executable_path/../Frameworks", 287 | ); 288 | PRODUCT_BUNDLE_IDENTIFIER = io.tyler.CalendarHero; 289 | PRODUCT_NAME = "$(TARGET_NAME)"; 290 | SWIFT_VERSION = 5.0; 291 | }; 292 | name = Debug; 293 | }; 294 | C6C7634E25DD79C800E466D7 /* Release */ = { 295 | isa = XCBuildConfiguration; 296 | buildSettings = { 297 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 298 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 299 | CODE_SIGN_ENTITLEMENTS = CalendarHero/CalendarHero.entitlements; 300 | CODE_SIGN_STYLE = Automatic; 301 | COMBINE_HIDPI_IMAGES = YES; 302 | DEVELOPMENT_TEAM = 3A6K89K388; 303 | ENABLE_HARDENED_RUNTIME = YES; 304 | INFOPLIST_FILE = CalendarHero/Info.plist; 305 | LD_RUNPATH_SEARCH_PATHS = ( 306 | "$(inherited)", 307 | "@executable_path/../Frameworks", 308 | ); 309 | PRODUCT_BUNDLE_IDENTIFIER = io.tyler.CalendarHero; 310 | PRODUCT_NAME = "$(TARGET_NAME)"; 311 | SWIFT_VERSION = 5.0; 312 | }; 313 | name = Release; 314 | }; 315 | /* End XCBuildConfiguration section */ 316 | 317 | /* Begin XCConfigurationList section */ 318 | C6C7633725DD79C600E466D7 /* Build configuration list for PBXProject "Calendar Hero" */ = { 319 | isa = XCConfigurationList; 320 | buildConfigurations = ( 321 | C6C7634A25DD79C800E466D7 /* Debug */, 322 | C6C7634B25DD79C800E466D7 /* Release */, 323 | ); 324 | defaultConfigurationIsVisible = 0; 325 | defaultConfigurationName = Release; 326 | }; 327 | C6C7634C25DD79C800E466D7 /* Build configuration list for PBXNativeTarget "Calendar Hero" */ = { 328 | isa = XCConfigurationList; 329 | buildConfigurations = ( 330 | C6C7634D25DD79C800E466D7 /* Debug */, 331 | C6C7634E25DD79C800E466D7 /* Release */, 332 | ); 333 | defaultConfigurationIsVisible = 0; 334 | defaultConfigurationName = Release; 335 | }; 336 | /* End XCConfigurationList section */ 337 | }; 338 | rootObject = C6C7633425DD79C600E466D7 /* Project object */; 339 | } 340 | -------------------------------------------------------------------------------- /CalendarHero/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | Default 530 | 531 | 532 | 533 | 534 | 535 | 536 | Left to Right 537 | 538 | 539 | 540 | 541 | 542 | 543 | Right to Left 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | Default 555 | 556 | 557 | 558 | 559 | 560 | 561 | Left to Right 562 | 563 | 564 | 565 | 566 | 567 | 568 | Right to Left 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | --------------------------------------------------------------------------------