diff --git a/Aerial.xcodeproj/project.pbxproj b/Aerial.xcodeproj/project.pbxproj index 38854f1b..0e367f76 100644 --- a/Aerial.xcodeproj/project.pbxproj +++ b/Aerial.xcodeproj/project.pbxproj @@ -23,6 +23,8 @@ 03510C6F21834F38008F74F2 /* IOBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 03510C6E21834F38008F74F2 /* IOBridge.m */; }; 03510C7021834FC3008F74F2 /* Aerial-Bridging-Header.h in Headers */ = {isa = PBXBuildFile; fileRef = 03510C6D21834F38008F74F2 /* Aerial-Bridging-Header.h */; }; 03510C7121834FC7008F74F2 /* IOBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 03510C6E21834F38008F74F2 /* IOBridge.m */; }; + 03510C732185EF76008F74F2 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03510C722185EF76008F74F2 /* CoreLocation.framework */; }; + 03510C772185EF8F008F74F2 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03510C722185EF76008F74F2 /* CoreLocation.framework */; }; 03893CB3217749F0008E7125 /* ErrorLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03893CB2217749F0008E7125 /* ErrorLog.swift */; }; 03893CB4217753AC008E7125 /* ErrorLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03893CB2217749F0008E7125 /* ErrorLog.swift */; }; 0393857A2175D4B80040B850 /* AVPlayerViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039385792175D4B80040B850 /* AVPlayerViewExtension.swift */; }; @@ -96,6 +98,7 @@ 03510C6A21834EB2008F74F2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; 03510C6D21834F38008F74F2 /* Aerial-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Aerial-Bridging-Header.h"; sourceTree = ""; }; 03510C6E21834F38008F74F2 /* IOBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IOBridge.m; sourceTree = ""; }; + 03510C722185EF76008F74F2 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; }; 03893CB2217749F0008E7125 /* ErrorLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorLog.swift; sourceTree = ""; }; 039385792175D4B80040B850 /* AVPlayerViewExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVPlayerViewExtension.swift; sourceTree = ""; }; 03958348217F4416008E8F9C /* Solar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Solar.swift; sourceTree = ""; }; @@ -138,6 +141,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 03510C772185EF8F008F74F2 /* CoreLocation.framework in Frameworks */, 03510C6B21834EB2008F74F2 /* IOKit.framework in Frameworks */, FA143CE61BDA3EEF0041A82B /* AVKit.framework in Frameworks */, ); @@ -154,6 +158,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 03510C732185EF76008F74F2 /* CoreLocation.framework in Frameworks */, 03510C6C21834EFF008F74F2 /* IOKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -192,6 +197,7 @@ FA2D7AA01BDD849E009EA54C /* Frameworks */ = { isa = PBXGroup; children = ( + 03510C722185EF76008F74F2 /* CoreLocation.framework */, 03510C6A21834EB2008F74F2 /* IOKit.framework */, FA143CE51BDA3EEF0041A82B /* AVKit.framework */, ); @@ -240,8 +246,7 @@ 0395835121807D1F008E8F9C /* thumbnail@2x.png */, FAC36F3A1BE1756D007F2A20 /* PreferencesWindow.xib */, ); - name = Resources; - path = Aerial/Resources; + path = Resources; sourceTree = ""; }; FAC36F3C1BE1756D007F2A20 /* Source */ = { @@ -783,7 +788,7 @@ CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; - INFOPLIST_FILE = Aerial/Resources/Info.plist; + INFOPLIST_FILE = "$(SRCROOT)/Resources/Info.plist"; INSTALL_PATH = "$(HOME)/Library/Screen Savers"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.johncoates.Aerial; @@ -802,7 +807,7 @@ CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; - INFOPLIST_FILE = Aerial/Resources/Info.plist; + INFOPLIST_FILE = "$(SRCROOT)/Resources/Info.plist"; INSTALL_PATH = "$(HOME)/Library/Screen Savers"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.johncoates.Aerial; diff --git a/Aerial/App/Resources/Info.plist b/Aerial/App/Resources/Info.plist index d3a997bd..335391bc 100644 --- a/Aerial/App/Resources/Info.plist +++ b/Aerial/App/Resources/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.4.4test2 + 1.4.4beta4 CFBundleSignature ???? CFBundleVersion @@ -31,6 +31,10 @@ NSHumanReadableCopyright Copyright © 2015 John Coates. All rights reserved. + NSLocationAlwaysUsageDescription + Aerial uses location services to calculate Sunset and Sunrise times from your position + NSLocationWhenInUseUsageDescription + Aerial uses location services to calculate Sunset and Sunrise times from your position NSMainNibFile MainMenu NSPrincipalClass diff --git a/Aerial/Source/Controllers/PreferencesWindowController.swift b/Aerial/Source/Controllers/PreferencesWindowController.swift index 734d4d7f..2d74ad7b 100644 --- a/Aerial/Source/Controllers/PreferencesWindowController.swift +++ b/Aerial/Source/Controllers/PreferencesWindowController.swift @@ -11,7 +11,7 @@ import AVKit import AVFoundation import ScreenSaver import VideoToolbox - +import CoreLocation class TimeOfDay { let title: String var videos: [AerialVideo] = [AerialVideo]() @@ -95,6 +95,7 @@ NSOutlineViewDelegate { @IBOutlet var latitudeTextField: NSTextField! @IBOutlet var longitudeTextField: NSTextField! + @IBOutlet var findCoordinatesButton: NSButton! @IBOutlet var calculateCoordinatesLabel: NSTextField! @@ -171,6 +172,8 @@ NSOutlineViewDelegate { var savedBrightness: Float? + var locationManager: CLLocationManager? + // MARK: - Init required init?(coder decoder: NSCoder) { self.fontManager = NSFontManager.shared @@ -208,6 +211,7 @@ NSOutlineViewDelegate { longitudeFormatter.maximumSignificantDigits = 10 + // This used to grab the preview player and put it in our own video preview thing. // While kinda cool, it showed a random video that wasn't selected, and with new lifecycle, it was paused /*if let previewPlayer = AerialView.previewPlayer { @@ -233,6 +237,7 @@ NSOutlineViewDelegate { iconTime1.image = NSImage(named: NSImage.touchBarHistoryTemplateName) iconTime2.image = NSImage(named: NSImage.touchBarComposeTemplateName) iconTime3.image = NSImage(named: NSImage.touchBarOpenInBrowserTemplateName) + findCoordinatesButton.image = NSImage(named: NSImage.touchBarOpenInBrowserTemplateName) } // Help popover, GVA detection requires 10.13 @@ -952,6 +957,7 @@ NSOutlineViewDelegate { } @IBAction func longitudeChange(_ sender: NSTextField) { + debugLog("longitudechange") preferences.longitude = sender.stringValue updateLatitudeLongitude() } @@ -977,6 +983,56 @@ NSOutlineViewDelegate { let url = URL(string: "https://en.wikipedia.org/wiki/Twilight")! workspace.open(url) } + + @IBAction func findCoordinatesButtonClick(_ sender: NSButton) { + debugLog("UI findCoordinatesButton") + /*let tm = TimeManagement.sharedInstance + + tm.startLocationDetection()*/ + + locationManager = CLLocationManager() + locationManager!.delegate = self + locationManager!.desiredAccuracy = kCLLocationAccuracyBest + locationManager!.distanceFilter = 100 + locationManager!.purpose = "Aerial uses your location to calculate sunrise and sunset times" + + if CLLocationManager.locationServicesEnabled() { + debugLog("Location services enabled") + //print(locationManager.location) + + _ = CLLocationManager.authorizationStatus() + /*if status == .restricted || status == .denied { + print("Location Denied") + } + else if status == .notDetermined { + print("Show ask for location") + } + else if status == .authorized { + print("This should work?") + }*/ + locationManager!.startUpdatingLocation() + } else { + errorLog("Location services are disabled, please check your macOS settings!") + return + } + /* + if #available(OSX 10.14, *) { + locationManager.requestLocation() + } else { + // Fallback on earlier versions + locationManager.startUpdatingLocation() + }*/ + } + + func pushCoordinates(_ coordinates: CLLocationCoordinate2D) + { + latitudeTextField.stringValue = String(coordinates.latitude) + longitudeTextField.stringValue = String(coordinates.longitude) + + preferences.latitude = String(coordinates.latitude) + preferences.longitude = String(coordinates.longitude) + updateLatitudeLongitude() + } // MARK: - Brightness panel @IBAction func dimBrightnessClick(_ button: NSButton) { @@ -1645,6 +1701,24 @@ NSOutlineViewDelegate { }*/ } +// MARK: - Core Location Delegates +extension PreferencesWindowController : CLLocationManagerDelegate { + func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { + debugLog("LM Coordinates") + let currentLocation = locations[locations.count - 1] + pushCoordinates(currentLocation.coordinate) + locationManager!.stopUpdatingLocation() // We only want them once + } + + func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { + debugLog("LMauth status change : \(status.rawValue)") + } + + /*func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { + errorLog("Location Manager error : \(error)") + }*/ +} + // MARK: - Font Panel Delegates diff --git a/Aerial/Source/Models/Time/TimeManagement.swift b/Aerial/Source/Models/Time/TimeManagement.swift index 9435cfdd..04e0cdae 100644 --- a/Aerial/Source/Models/Time/TimeManagement.swift +++ b/Aerial/Source/Models/Time/TimeManagement.swift @@ -10,7 +10,7 @@ import Foundation import Cocoa import CoreLocation -class TimeManagement { +class TimeManagement : NSObject { static let sharedInstance = TimeManagement() // Night shift @@ -21,7 +21,8 @@ class TimeManagement { var solar:Solar? // MARK: - Lifecycle - init() { + override init() { + super.init() debugLog("Time Management initialized") _ = calculateFromCoordinates() } @@ -172,10 +173,14 @@ class TimeManagement { default: sunriseString = dateFormatter.string(from: (solar?.astronomicalSunrise)!) sunsetString = dateFormatter.string(from: (solar?.astronomicalSunset)!) + } + if preferences.solarMode == Preferences.SolarMode.official.rawValue || + preferences.solarMode == Preferences.SolarMode.strict.rawValue { + return(true, "Today’s sunrise: " + sunriseString + " Today’s sunset: " + sunsetString) + } else { + return(true, "Today’s dawn: " + sunriseString + " Today’s dusk: " + sunsetString) } - - return(true, "Today's Sunrise: " + sunriseString + " Today's Sunset: " + sunsetString) } } @@ -218,7 +223,7 @@ class TimeManagement { let sunriseString = dateFormatter.string(from: sunriseDate!) let sunsetString = dateFormatter.string(from: sunsetDate!) - return (true,"Today's Sunrise: " + sunriseString + " Today's Sunset: " + sunsetString) + return (true,"Today’s sunrise: " + sunriseString + " Today’s sunset: " + sunsetString) } else { isNightShiftDataCached = true @@ -381,4 +386,62 @@ class TimeManagement { } } + // MARK: - Location detection + func startLocationDetection() + { + let locationManager = CLLocationManager() + locationManager.delegate = self + + if CLLocationManager.locationServicesEnabled() { + debugLog("Location services enabled") + locationManager.startUpdatingLocation() + } else { + errorLog("Location services are disabled, please check your macOS settings!") + } + + /*let status = CLLocationManager.authorizationStatus() + if status == .restricted || status == .denied { + + print("Location Denied") + + return + } + else if status == .notDetermined { + + print("Show ask for location") + + return + } + else if status == .authorized { + print("This should work?") + + return + }*/ + + if #available(OSX 10.14, *) { + print("reqloc") + locationManager.requestLocation() + } else { + // Fallback on earlier versions + } + } + +} + +// MARK: - Core Location Delegates +extension TimeManagement : CLLocationManagerDelegate { +/* func locationManager(_ manager: CLLocationManager, didUpdateTo newLocation: CLLocation, from oldLocation: CLLocation) { + + print("\(newLocation) \(oldLocation)") + + }*/ + + func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { + let currentLocation = locations[locations.count - 1] + print("\(currentLocation)") + } + + func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { + errorLog("Location Manager error : \(error)") + } } diff --git a/Aerial/Source/Views/AerialView.swift b/Aerial/Source/Views/AerialView.swift index 430df5c4..88beb843 100644 --- a/Aerial/Source/Views/AerialView.swift +++ b/Aerial/Source/Views/AerialView.swift @@ -720,6 +720,17 @@ class AerialView: ScreenSaverView { fontSize = 12 } + // We get the horizontal margin + var mx = CGFloat(preferences.marginX!) + + if !preferences.overrideMargins { + mx = 50 + } + if isPreview { + mx = 10 + } + let boundingRect = CGSize(width: layer!.visibleRect.size.width-2*mx, height: layer!.visibleRect.size.height) + // Get font with a fallback in case var font = NSFont(name: "Helvetica Neue Medium", size: 28) if let tryFont = NSFont(name: preferences.fontName!,size: fontSize) { @@ -735,13 +746,13 @@ class AerialView: ScreenSaverView { // Calculate bounding box let s = NSAttributedString(string: string, attributes: attributes) - var rect = s.boundingRect(with: layer!.visibleRect.size, options: [.truncatesLastVisibleLine, .usesLineFragmentOrigin]) + var rect = s.boundingRect(with: boundingRect, options: [.truncatesLastVisibleLine, .usesLineFragmentOrigin]) // Last line won't appear if we don't adjust rect = CGRect(x: rect.origin.x, y: rect.origin.y, width: rect.width, height: rect.height+10) // Rebind frame self.textLayer.frame = rect - + // At the position the user wants if preferences.descriptionCorner == Preferences.DescriptionCorner.random.rawValue { // Randomish, we still want something different @@ -1026,15 +1037,19 @@ class AerialView: ScreenSaverView { if (position == Preferences.DescriptionCorner.topLeft.rawValue) { self.textLayer.anchorPoint = CGPoint(x: 0, y: 1) self.textLayer.position = CGPoint(x: mx, y: layer!.bounds.height-my) + self.textLayer.alignmentMode = .left } else if (position == Preferences.DescriptionCorner.bottomLeft.rawValue) { self.textLayer.anchorPoint = CGPoint(x: 0, y: 0) self.textLayer.position = CGPoint(x: mx, y: my) + self.textLayer.alignmentMode = .left } else if (position == Preferences.DescriptionCorner.topRight.rawValue) { self.textLayer.anchorPoint = CGPoint(x: 1, y: 1) self.textLayer.position = CGPoint(x: layer!.bounds.width-mx, y: layer!.bounds.height-my) + self.textLayer.alignmentMode = .right } else if (position == Preferences.DescriptionCorner.bottomRight.rawValue) { self.textLayer.anchorPoint = CGPoint(x: 1, y: 0) self.textLayer.position = CGPoint(x: layer!.bounds.width-mx, y: my) + self.textLayer.alignmentMode = .right } } @@ -1044,10 +1059,10 @@ class AerialView: ScreenSaverView { fadeAnimation.values = [0, 0, 1, 1, 0] as [NSNumber] fadeAnimation.keyTimes = [0, Double( 1/duration ), Double( (1+AerialView.textFadeDuration)/duration ), Double( 1-AerialView.textFadeDuration/duration ), 1] as [NSNumber] fadeAnimation.duration = duration - return fadeAnimation } - + + // Create a move animation func createMoveAnimation(layer : CALayer, to: CGPoint, duration: Double) -> CABasicAnimation { let moveAnimation = CABasicAnimation(keyPath: "position") moveAnimation.fromValue = layer.position diff --git a/Aerial/Resources/Community/en.json b/Resources/Community/en.json similarity index 100% rename from Aerial/Resources/Community/en.json rename to Resources/Community/en.json diff --git a/Aerial/Resources/Info.plist b/Resources/Info.plist similarity index 68% rename from Aerial/Resources/Info.plist rename to Resources/Info.plist index ff44c225..afecd3c2 100644 --- a/Aerial/Resources/Info.plist +++ b/Resources/Info.plist @@ -15,11 +15,13 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.4.4beta2 + 1.4.4beta4 CFBundleSignature ???? CFBundleVersion - 1.4.4beta2 + 1.4.4beta4 + LSApplicationCategoryType + LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} NSAppTransportSecurity @@ -27,6 +29,10 @@ NSAllowsArbitraryLoads + NSLocationAlwaysUsageDescription + Aerial uses location services to calculate Sunset and Sunrise times from your position + NSLocationWhenInUseUsageDescription + Aerial uses location services to calculate Sunset and Sunrise times from your position NSPrincipalClass AerialView diff --git a/Aerial/Resources/PreferencesWindow.xib b/Resources/PreferencesWindow.xib similarity index 96% rename from Aerial/Resources/PreferencesWindow.xib rename to Resources/PreferencesWindow.xib index 72c333c0..94b8dc1b 100644 --- a/Aerial/Resources/PreferencesWindow.xib +++ b/Resources/PreferencesWindow.xib @@ -40,6 +40,7 @@ + @@ -98,39 +99,39 @@ - + - + - + - + - + - + - + - + - + @@ -277,7 +278,7 @@ - + @@ -295,7 +296,7 @@ - + @@ -326,7 +327,7 @@ - + @@ -382,7 +383,7 @@ is disabled - + @@ -400,7 +401,7 @@ is disabled - + @@ -420,7 +421,7 @@ is disabled - + @@ -444,12 +445,12 @@ is disabled - - + + - + @@ -474,7 +475,7 @@ should appear - + @@ -505,7 +506,7 @@ should appear - + @@ -536,7 +537,7 @@ should appear - + @@ -545,11 +546,11 @@ should appear - + - + @@ -558,7 +559,7 @@ should appear - + @@ -598,7 +599,7 @@ should appear - + @@ -629,7 +630,7 @@ should appear - + @@ -641,7 +642,7 @@ should appear - + @@ -662,7 +663,7 @@ should appear - + @@ -679,7 +680,7 @@ should appear - + @@ -699,7 +700,7 @@ should appear - + @@ -856,7 +844,7 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - - - - - - - - - - + @@ -892,7 +871,7 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - + @@ -901,7 +880,7 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - + @@ -917,7 +896,7 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - + @@ -926,22 +905,22 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - + - + - + - + @@ -949,13 +928,8 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - - - - - - + @@ -979,21 +953,21 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - + - + - + - + @@ -1017,7 +991,7 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - + @@ -1040,6 +1014,44 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) + + + + + + + + + + + + + + + + @@ -1437,7 +1449,7 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - + @@ -1547,7 +1559,7 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - + @@ -1668,56 +1680,58 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - + - - + + - There are multiple ways to calculate the sunset and sunrise time, depending on how you define it. Aerial lets you pick from multiple options : + There are two ways to calculate the sunset and sunrise time: -- Strict (0°): Calculate when the Sun crosses the horizon +- Strict (0°): Calculate when the center of the Sun crosses the horizon - Official (0.83°) : Calculate when the Sun completely crosses the horizon -- Civil (6°) : Calculate when the natural sunlight starts/stops requiring artificial light compensation +Or instead of sunrise and sunset, you can pick from three options for the time of dawn and dusk: -- Nautical (12°) : Calculate when stars start/stop being seen +- Civil (6°) : Calculate when the natural sunlight stops/starts requiring artificial light compensation -- Astronomical (18°) : Calculate the point when the sun no longer interfers with astronomical observations +- Nautical (12°) : Calculate when stars stop/start being seen - +- Astronomical (18°) : Calculate the point when the sun no longer interferes with astronomical observations - - - + + Coordinates are expressed in degrees, e.g.: - Latitude : 48.85837 -- Longitude : 2.294483 +- Longitude : 2.294483 + +You can either enter those manually or try to use Location Services on your Mac by clicking the icon next to the longitude button. You may be asked for permission. + - + diff --git a/Aerial/Resources/icon-day-dark.pdf b/Resources/icon-day-dark.pdf similarity index 100% rename from Aerial/Resources/icon-day-dark.pdf rename to Resources/icon-day-dark.pdf diff --git a/Aerial/Resources/icon-day.pdf b/Resources/icon-day.pdf similarity index 100% rename from Aerial/Resources/icon-day.pdf rename to Resources/icon-day.pdf diff --git a/Aerial/Resources/icon-night-dark.pdf b/Resources/icon-night-dark.pdf similarity index 100% rename from Aerial/Resources/icon-night-dark.pdf rename to Resources/icon-night-dark.pdf diff --git a/Aerial/Resources/icon-night.pdf b/Resources/icon-night.pdf similarity index 100% rename from Aerial/Resources/icon-night.pdf rename to Resources/icon-night.pdf diff --git a/Aerial/Resources/thumbnail.png b/Resources/thumbnail.png similarity index 100% rename from Aerial/Resources/thumbnail.png rename to Resources/thumbnail.png diff --git a/Aerial/Resources/thumbnail@2x.png b/Resources/thumbnail@2x.png similarity index 100% rename from Aerial/Resources/thumbnail@2x.png rename to Resources/thumbnail@2x.png