diff --git a/Aerial.xcodeproj/project.pbxproj b/Aerial.xcodeproj/project.pbxproj index cef687a8..ca8548dd 100644 --- a/Aerial.xcodeproj/project.pbxproj +++ b/Aerial.xcodeproj/project.pbxproj @@ -109,7 +109,7 @@ 03E8730E216501ED002B469B /* AsynchronousOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsynchronousOperation.swift; sourceTree = ""; }; 03E8731221675FE0002B469B /* TimeManagement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeManagement.swift; sourceTree = ""; }; AA7E2E5D1FC62E8B00E5F320 /* AerialPlayerItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AerialPlayerItem.swift; sourceTree = ""; }; - FA143CD61BDA3E880041A82B /* AerialApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AerialApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; + FA143CD61BDA3E880041A82B /* AerialConfig.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AerialConfig.app; sourceTree = BUILT_PRODUCTS_DIR; }; FA143CE51BDA3EEF0041A82B /* AVKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVKit.framework; path = System/Library/Frameworks/AVKit.framework; sourceTree = SDKROOT; }; FA36BD3E1BE57F8E00D5E03B /* VideoDownload.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = VideoDownload.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; FA6F81DB1D939455007975FE /* Preferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = ""; }; @@ -331,7 +331,7 @@ isa = PBXGroup; children = ( FACAF1A51BD9FC6000E539DC /* Aerial.saver */, - FA143CD61BDA3E880041A82B /* AerialApp.app */, + FA143CD61BDA3E880041A82B /* AerialConfig.app */, FA71996E1D94EC5A00FBC99B /* Aerial Tests.xctest */, ); name = Products; @@ -351,9 +351,9 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ - FA143CD51BDA3E880041A82B /* AerialApp */ = { + FA143CD51BDA3E880041A82B /* AerialConfig */ = { isa = PBXNativeTarget; - buildConfigurationList = FA143CE01BDA3E880041A82B /* Build configuration list for PBXNativeTarget "AerialApp" */; + buildConfigurationList = FA143CE01BDA3E880041A82B /* Build configuration list for PBXNativeTarget "AerialConfig" */; buildPhases = ( FA74B8481D94DCE0004FE056 /* Run Script - Swiftlint */, FA143CD21BDA3E880041A82B /* Sources */, @@ -364,9 +364,9 @@ ); dependencies = ( ); - name = AerialApp; + name = AerialConfig; productName = "Aerial Test"; - productReference = FA143CD61BDA3E880041A82B /* AerialApp.app */; + productReference = FA143CD61BDA3E880041A82B /* AerialConfig.app */; productType = "com.apple.product-type.application"; }; FA71996D1D94EC5A00FBC99B /* Aerial Tests */ = { @@ -413,7 +413,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0800; - LastUpgradeCheck = 1000; + LastUpgradeCheck = 1010; ORGANIZATIONNAME = "John Coates"; TargetAttributes = { FA143CD51BDA3E880041A82B = { @@ -446,7 +446,7 @@ projectRoot = ""; targets = ( FACAF1A41BD9FC6000E539DC /* Aerial */, - FA143CD51BDA3E880041A82B /* AerialApp */, + FA143CD51BDA3E880041A82B /* AerialConfig */, FA71996D1D94EC5A00FBC99B /* Aerial Tests */, ); }; @@ -599,7 +599,7 @@ /* Begin PBXTargetDependency section */ FA7199741D94EC5A00FBC99B /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = FA143CD51BDA3E880041A82B /* AerialApp */; + target = FA143CD51BDA3E880041A82B /* AerialConfig */; targetProxy = FA7199731D94EC5A00FBC99B /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -646,7 +646,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.9; PRODUCT_BUNDLE_IDENTIFIER = "com.johncoates.Aerial-Test"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_COMPILATION_MODE = singlefile; + SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OBJC_BRIDGING_HEADER = "Aerial/Source/Models/Time/Aerial-Bridging-Header.h"; SWIFT_SWIFT3_OBJC_INFERENCE = On; }; @@ -831,7 +831,7 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - FA143CE01BDA3E880041A82B /* Build configuration list for PBXNativeTarget "AerialApp" */ = { + FA143CE01BDA3E880041A82B /* Build configuration list for PBXNativeTarget "AerialConfig" */ = { isa = XCConfigurationList; buildConfigurations = ( FA143CE11BDA3E880041A82B /* Debug */, diff --git a/Aerial.xcodeproj/xcshareddata/xcschemes/Aerial.xcscheme b/Aerial.xcodeproj/xcshareddata/xcschemes/Aerial.xcscheme index 32087883..f94b9ebb 100644 --- a/Aerial.xcodeproj/xcshareddata/xcschemes/Aerial.xcscheme +++ b/Aerial.xcodeproj/xcshareddata/xcschemes/Aerial.xcscheme @@ -1,6 +1,6 @@ @@ -44,8 +44,8 @@ @@ -67,8 +67,8 @@ @@ -93,8 +93,8 @@ diff --git a/Aerial/App/AppDelegate.swift b/Aerial/App/AppDelegate.swift index d567e640..4cb65f6c 100644 --- a/Aerial/App/AppDelegate.swift +++ b/Aerial/App/AppDelegate.swift @@ -16,7 +16,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ notification: Notification) { let objects = objectsFromNib(loadNibNamed: "PreferencesWindow") - + preferencesWindowController.appMode = true // We need to find the correct window in our nib let object = objects.first { object in if let window = object as? NSWindow, window.identifier?.rawValue == "preferencesWindow" { diff --git a/Aerial/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json b/Aerial/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json index 2db2b1c7..307be1e9 100644 --- a/Aerial/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Aerial/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -46,8 +46,9 @@ "scale" : "1x" }, { - "idiom" : "mac", "size" : "512x512", + "idiom" : "mac", + "filename" : "icon-1024.png", "scale" : "2x" } ], diff --git a/Aerial/App/Resources/Assets.xcassets/AppIcon.appiconset/icon-1024.png b/Aerial/App/Resources/Assets.xcassets/AppIcon.appiconset/icon-1024.png new file mode 100644 index 00000000..78a3a1be Binary files /dev/null and b/Aerial/App/Resources/Assets.xcassets/AppIcon.appiconset/icon-1024.png differ diff --git a/Aerial/App/Resources/Base.lproj/MainMenu.xib b/Aerial/App/Resources/Base.lproj/MainMenu.xib index a7bfad80..e3fbb97a 100644 --- a/Aerial/App/Resources/Base.lproj/MainMenu.xib +++ b/Aerial/App/Resources/Base.lproj/MainMenu.xib @@ -1,8 +1,9 @@ - + - + + @@ -12,7 +13,7 @@ - + @@ -20,11 +21,11 @@ - + - + - + @@ -38,7 +39,7 @@ - + @@ -56,7 +57,7 @@ - + @@ -64,570 +65,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -657,7 +94,7 @@ - + @@ -666,23 +103,24 @@ + - - + + - + - + - + - + diff --git a/Aerial/App/Resources/Info.plist b/Aerial/App/Resources/Info.plist index 335391bc..e8db4759 100644 --- a/Aerial/App/Resources/Info.plist +++ b/Aerial/App/Resources/Info.plist @@ -17,11 +17,13 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.4.4beta4 + 1.4.5beta2 CFBundleSignature ???? CFBundleVersion 1 + LSApplicationCategoryType + public.app-category.utilities LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSAppTransportSecurity diff --git a/Aerial/Source/Controllers/Preferences.swift b/Aerial/Source/Controllers/Preferences.swift index b6ff81a0..20a2a53b 100644 --- a/Aerial/Source/Controllers/Preferences.swift +++ b/Aerial/Source/Controllers/Preferences.swift @@ -60,6 +60,12 @@ class Preferences { case overrideMargins = "overrideMargins" case marginX = "marginX" case marginY = "marginY" + + case alternateVideoFormat = "alternateVideoFormat" + case overrideOnBattery = "overrideOnBattery" + case powerSavingOnLowBattery = "powerSavingOnLowBattery" + + case darkModeNightOverride = "darkModeNightOverride" } enum SolarMode: Int { @@ -95,6 +101,10 @@ class Preferences { case v1080pH264, v1080pHEVC, v4KHEVC } + enum AlternateVideoFormat: Int { + case powerSaving, v1080pH264, v1080pHEVC, v4KHEVC + } + enum DescriptionMode: Int { case fade10seconds, always } @@ -161,6 +171,10 @@ class Preferences { defaultValues[.overrideMargins] = false defaultValues[.marginX] = 50 defaultValues[.marginY] = 50 + defaultValues[.overrideOnBattery] = false + defaultValues[.powerSavingOnLowBattery] = false + defaultValues[.alternateVideoFormat] = AlternateVideoFormat.powerSaving + defaultValues[.darkModeNightOverride] = false let defaults = defaultValues.reduce([String: Any]()) { (result, pair:(key: Identifiers, value: Any)) -> [String: Any] in var mutable = result @@ -172,6 +186,41 @@ class Preferences { } // MARK: - Variables + var alternateVideoFormat: Int? { + get { + return optionalValue(forIdentifier: .alternateVideoFormat) + } + set { + setValue(forIdentifier: .alternateVideoFormat, value: newValue) + } + } + + var darkModeNightOverride: Bool { + get { + return value(forIdentifier: .darkModeNightOverride) + } + set { + setValue(forIdentifier: .darkModeNightOverride, value: newValue) + } + } + + var overrideOnBattery: Bool { + get { + return value(forIdentifier: .overrideOnBattery) + } + set { + setValue(forIdentifier: .overrideOnBattery, value: newValue) + } + } + + var powerSavingOnLowBattery: Bool { + get { + return value(forIdentifier: .powerSavingOnLowBattery) + } + set { + setValue(forIdentifier: .powerSavingOnLowBattery, value: newValue) + } + } var useCommunityDescriptions: Bool { get { diff --git a/Aerial/Source/Controllers/PreferencesWindowController.swift b/Aerial/Source/Controllers/PreferencesWindowController.swift index dc2bee8f..3f1bb4c2 100644 --- a/Aerial/Source/Controllers/PreferencesWindowController.swift +++ b/Aerial/Source/Controllers/PreferencesWindowController.swift @@ -63,10 +63,16 @@ class PreferencesWindowController: NSWindowController, NSOutlineViewDataSource, @IBOutlet var neverStreamVideosCheckbox: NSButton! @IBOutlet var neverStreamPreviewsCheckbox: NSButton! @IBOutlet weak var downloadNowButton: NSButton! + @IBOutlet var overrideOnBatteryCheckbox: NSButton! + @IBOutlet var powerSavingOnLowBatteryCheckbox: NSButton! + + @IBOutlet var overrideNightOnDarkMode: NSButton! @IBOutlet var multiMonitorModePopup: NSPopUpButton! @IBOutlet var popupVideoFormat: NSPopUpButton! + @IBOutlet var alternatePopupVideoFormat: NSPopUpButton! @IBOutlet var descriptionModePopup: NSPopUpButton! + @IBOutlet var fadeInOutModePopup: NSPopUpButton! @IBOutlet weak var fadeInOutTextModePopup: NSPopUpButton! @@ -75,8 +81,9 @@ class PreferencesWindowController: NSWindowController, NSOutlineViewDataSource, @IBOutlet var versionLabel: NSTextField! @IBOutlet var popover: NSPopover! - @IBOutlet var popoverTime: NSPopover! + @IBOutlet var popoverPower: NSPopover! + @IBOutlet var linkTimeWikipediaButton: NSButton! @IBOutlet var popoverH264Indicator: NSButton! @@ -174,6 +181,8 @@ class PreferencesWindowController: NSWindowController, NSOutlineViewDataSource, var locationManager: CLLocationManager? + public var appMode: Bool = false + // MARK: - Init required init?(coder decoder: NSCoder) { self.fontManager = NSFontManager.shared @@ -282,7 +291,7 @@ class PreferencesWindowController: NSWindowController, NSOutlineViewDataSource, // Grab preferred language as proper string let printOutputLocale: NSLocale = NSLocale(localeIdentifier: Locale.preferredLanguages[0]) if let deviceLanguageName: String = printOutputLocale.displayName(forKey: NSLocale.Key.identifier, value: Locale.preferredLanguages[0]) { - currentLocaleLabel.stringValue = "Preferred language : \(deviceLanguageName)" + currentLocaleLabel.stringValue = "Preferred language: \(deviceLanguageName)" } else { currentLocaleLabel.stringValue = "" } @@ -305,11 +314,21 @@ class PreferencesWindowController: NSWindowController, NSOutlineViewDataSource, showClockCheckbox.isEnabled = false } + // Videos panel + if preferences.overrideOnBattery { + overrideOnBatteryCheckbox.state = .on + changeBatteryOverrideState(to: true) + } else { + changeBatteryOverrideState(to: false) + } + if preferences.powerSavingOnLowBattery { + powerSavingOnLowBatteryCheckbox.state = .on + } + // Aerial panel if preferences.debugMode { debugModeCheckbox.state = .on } - if preferences.logToDisk { logToDiskCheckbox.state = .on } @@ -319,27 +338,22 @@ class PreferencesWindowController: NSWindowController, NSOutlineViewDataSource, showClockCheckbox.state = .on withSecondsCheckbox.isEnabled = true } - if preferences.withSeconds { withSecondsCheckbox.state = .on } - if preferences.showMessage { showExtraMessage.state = .on extraMessageTextField.isEnabled = true } - if preferences.showDescriptions { showDescriptionsCheckbox.state = .on changeTextState(to: true) } else { changeTextState(to: false) } - if preferences.localizeDescriptions { localizeForTvOS12Checkbox.state = .on } - if preferences.overrideMargins { changeCornerMargins.state = .on marginHorizontalTextfield.isEnabled = true @@ -350,15 +364,12 @@ class PreferencesWindowController: NSWindowController, NSOutlineViewDataSource, if preferences.neverStreamVideos { neverStreamVideosCheckbox.state = .on } - if preferences.neverStreamPreviews { neverStreamPreviewsCheckbox.state = .on } - if !preferences.useCommunityDescriptions { useCommunityCheckbox.state = .off } - if !preferences.cacheAerials { cacheAerialsAsTheyPlayCheckbox.state = .off } @@ -390,6 +401,14 @@ class PreferencesWindowController: NSWindowController, NSOutlineViewDataSource, dimFadeInMinutes.stringValue = String(preferences.dimInMinutes!) // Time mode + if #available(OSX 10.14, *) { + if preferences.darkModeNightOverride { + overrideNightOnDarkMode.state = .on + } + } else { + overrideNightOnDarkMode.isEnabled = false + } + let timeManagement = TimeManagement.sharedInstance // Light/Dark mode only available on Mojave+ let (isLDMCapable, reason: LDMReason) = timeManagement.isLightDarkModeAvailable() @@ -456,6 +475,7 @@ class PreferencesWindowController: NSWindowController, NSOutlineViewDataSource, multiMonitorModePopup.selectItem(at: preferences.multiMonitorMode!) popupVideoFormat.selectItem(at: preferences.videoFormat!) + alternatePopupVideoFormat.selectItem(at: preferences.alternateVideoFormat!) descriptionModePopup.selectItem(at: preferences.showDescriptionsMode!) @@ -479,7 +499,7 @@ class PreferencesWindowController: NSWindowController, NSOutlineViewDataSource, } else { sleepAfterLabel.stringValue = "Unable to determine your Mac sleep settings" } - + debugLog("appMode : \(appMode)") } override func windowDidLoad() { @@ -492,7 +512,11 @@ class PreferencesWindowController: NSWindowController, NSOutlineViewDataSource, @IBAction func close(_ sender: AnyObject?) { logPanel.close() - window?.sheetParent?.endSheet(window!) + if appMode { + NSApplication.shared.terminate(nil) + } else { + window?.sheetParent?.endSheet(window!) + } } // MARK: Video playback @@ -538,12 +562,38 @@ class PreferencesWindowController: NSWindowController, NSOutlineViewDataSource, } // MARK: - Video panel + @IBAction func overrideOnBatteryClick(_ sender: NSButton) { + let onState = (sender.state == NSControl.StateValue.on) + preferences.overrideOnBattery = onState + changeBatteryOverrideState(to: onState) + debugLog("UI overrideOnBattery \(onState)") + } + + @IBAction func powerSavingOnLowClick(_ sender: NSButton) { + let onState = (sender.state == NSControl.StateValue.on) + preferences.powerSavingOnLowBattery = onState + debugLog("UI powerSavingOnLow \(onState)") + } + + @IBAction func alternateVideoFormatChange(_ sender: NSPopUpButton) { + debugLog("UI alternatePopupVideoFormat: \(sender.indexOfSelectedItem)") + preferences.alternateVideoFormat = sender.indexOfSelectedItem + changeBatteryOverrideState(to: true) + } + + func changeBatteryOverrideState(to: Bool) { + alternatePopupVideoFormat.isEnabled = to + if !to || (to && preferences.alternateVideoFormat != Preferences.AlternateVideoFormat.powerSaving.rawValue) { + powerSavingOnLowBatteryCheckbox.isEnabled = to + } else { + powerSavingOnLowBatteryCheckbox.isEnabled = false + } + } @IBAction func popupVideoFormatChange(_ sender: NSPopUpButton) { debugLog("UI popupVideoFormat: \(sender.indexOfSelectedItem)") preferences.videoFormat = sender.indexOfSelectedItem preferences.synchronize() - outlineView.reloadData() } @@ -551,6 +601,10 @@ class PreferencesWindowController: NSWindowController, NSOutlineViewDataSource, popover.show(relativeTo: button.preparedContentRect, of: button, preferredEdge: .maxY) } + @IBAction func helpPowerButtonClick(_ button: NSButton!) { + popoverPower.show(relativeTo: button.preparedContentRect, of: button, preferredEdge: .maxY) + } + @IBAction func multiMonitorModePopupChange(_ sender: NSPopUpButton) { debugLog("UI multiMonitorMode: \(sender.indexOfSelectedItem)") preferences.multiMonitorMode = sender.indexOfSelectedItem @@ -577,6 +631,7 @@ class PreferencesWindowController: NSWindowController, NSOutlineViewDataSource, downloadProgressIndicator.maxValue = Double(total) } } + @IBAction func cancelDownloadsClick(_ sender: Any) { debugLog("UI cancelDownloadsClick") let videoManager = VideoManager.sharedInstance @@ -850,7 +905,7 @@ class PreferencesWindowController: NSWindowController, NSOutlineViewDataSource, byteCountFormatter.countStyle = .file let sizeToDisplay = byteCountFormatter.string(for: folderSize) ?? "" debugLog("Cache size : \(sizeToDisplay)") - cacheSizeTextField.stringValue = "Cache all videos (current cache size \(sizeToDisplay))" + cacheSizeTextField.stringValue = "Cache all videos (Current cache size \(sizeToDisplay))" } } @@ -1083,7 +1138,7 @@ class PreferencesWindowController: NSWindowController, NSOutlineViewDataSource, } if event.type != .leftMouseUp && event.type != .leftMouseDown && event.type != .leftMouseDragged { - warnLog("Unexepected event type \(event.type)") + //warnLog("Unexepected event type \(event.type)") } if event.type == .leftMouseUp { diff --git a/Aerial/Source/Models/AerialVideo.swift b/Aerial/Source/Models/AerialVideo.swift index 300c8c3c..b3c7f4e4 100644 --- a/Aerial/Source/Models/AerialVideo.swift +++ b/Aerial/Source/Models/AerialVideo.swift @@ -75,8 +75,14 @@ class AerialVideo: CustomStringConvertible, Equatable { var url: URL { let preferences = Preferences.sharedInstance + let timeManagement = TimeManagement.sharedInstance + // We may override on battery + if preferences.overrideOnBattery && timeManagement.isOnBattery() { + return getClosestAvailable(wanted: preferences.alternateVideoFormat!-1) // Slightly dirty + } - // We need to return the closest available format, not pretty + return getClosestAvailable(wanted: preferences.videoFormat!) +/* // We need to return the closest available format, not pretty if preferences.videoFormat == Preferences.VideoFormat.v4KHEVC.rawValue { if url4KHEVC != "" { return URL(string: self.url4KHEVC)! @@ -102,9 +108,37 @@ class AerialVideo: CustomStringConvertible, Equatable { } else { return URL(string: self.url4KHEVC)! } - } + }*/ } + func getClosestAvailable(wanted: Int) -> URL { + if wanted == Preferences.VideoFormat.v4KHEVC.rawValue { + if url4KHEVC != "" { + return URL(string: self.url4KHEVC)! + } else if url1080pHEVC != "" { + return URL(string: self.url1080pHEVC)! + } else { + return URL(string: self.url1080pH264)! + } + } else if wanted == Preferences.VideoFormat.v1080pHEVC.rawValue { + if url1080pHEVC != "" { + return URL(string: self.url1080pHEVC)! + } else if url1080pH264 != "" { + return URL(string: self.url1080pH264)! + } else { + return URL(string: self.url4KHEVC)! + } + } else { + if url1080pH264 != "" { + return URL(string: self.url1080pH264)! + } else if url1080pHEVC != "" { + // With the latest versions, we should always have a H.264 fallback so this is just for future proofing + return URL(string: self.url1080pHEVC)! + } else { + return URL(string: self.url4KHEVC)! + } + } + } init(id: String, name: String, secondaryName: String, diff --git a/Aerial/Source/Models/Time/TimeManagement.swift b/Aerial/Source/Models/Time/TimeManagement.swift index a0d77664..388cdef3 100644 --- a/Aerial/Source/Models/Time/TimeManagement.swift +++ b/Aerial/Source/Models/Time/TimeManagement.swift @@ -32,6 +32,12 @@ class TimeManagement: NSObject { // swiftlint:disable:next cyclomatic_complexity func shouldRestrictPlaybackToDayNightVideo() -> (Bool, String) { let preferences = Preferences.sharedInstance + // We can override everything on dark mode if we need to + if preferences.darkModeNightOverride && isDarkModeEnabled() { + return (true, "night") + } + + // If not we check the modes if preferences.timeMode == Preferences.TimeMode.lightDarkMode.rawValue { if isDarkModeEnabled() { return (true, "night") @@ -379,6 +385,11 @@ class TimeManagement: NSObject { } } + func isBatteryLow() -> Bool { + let level = IOPSGetBatteryWarningLevel() + return (level == kIOPSLowBatteryWarningEarly || level == kIOPSLowBatteryWarningFinal) + } + // MARK: - Location detection func startLocationDetection() { let locationManager = CLLocationManager() diff --git a/Aerial/Source/Views/AerialView.swift b/Aerial/Source/Views/AerialView.swift index 09a9aa88..f3162f99 100644 --- a/Aerial/Source/Views/AerialView.swift +++ b/Aerial/Source/Views/AerialView.swift @@ -171,12 +171,21 @@ class AerialView: ScreenSaverView { func setup() { debugLog("\(self.description) AerialView setup init") let preferences = Preferences.sharedInstance + let timeManagement = TimeManagement.sharedInstance + + if preferences.overrideOnBattery && timeManagement.isOnBattery() && !isPreview { + if preferences.alternateVideoFormat == Preferences.AlternateVideoFormat.powerSaving.rawValue || + (preferences.powerSavingOnLowBattery && timeManagement.isBatteryLow()) { + isDisabled = true + timeManagement.setBrightness(level: 0.0) + return + } + } // Ugly, we make sure we should dim, we're not a preview, we haven't dimmed yet (multi monitor) // and ensure we properly apply the night/battery restrictions ! if preferences.dimBrightness { if !isPreview && brightnessToRestore == nil { - let timeManagement = TimeManagement.sharedInstance let (should, to) = timeManagement.shouldRestrictPlaybackToDayNightVideo() if !preferences.dimOnlyAtNight || (preferences.dimOnlyAtNight && should && to == "night") { @@ -334,7 +343,7 @@ class AerialView: ScreenSaverView { // Add a bit of shadow to give an outline and better readability clockLayer.shadowRadius = 10 clockLayer.shadowOpacity = 1.0 - textLayer.shadowColor = CGColor.black + clockLayer.shadowColor = CGColor.black //clockLayer.contentsScale = 1.0 // NSScreen.main?.backingScaleFactor ?? 1.0 layer.addSublayer(clockLayer) @@ -344,9 +353,32 @@ class AerialView: ScreenSaverView { // Add a bit of shadow to give an outline and better readability messageLayer.shadowRadius = 10 messageLayer.shadowOpacity = 1.0 - textLayer.shadowColor = CGColor.black + messageLayer.shadowColor = CGColor.black //messageLayer.contentsScale = 1.0 // NSScreen.main?.backingScaleFactor ?? 1.0 layer.addSublayer(messageLayer) + + if #available(OSX 10.14, *) { + } else { + debugLog("Using dot workaround for video driver corruption") + // Tentative fix for high sierra issues + let highSierraLayer = CATextLayer() + highSierraLayer.frame = self.bounds + highSierraLayer.opacity = 0.5 + highSierraLayer.font = NSFont(name: "Helvetica Neue Medium", size: 4) + highSierraLayer.fontSize = 4 + highSierraLayer.string = "." + + let attributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.font: highSierraLayer.font as Any] + + // Calculate bounding box + let attrString = NSAttributedString(string: highSierraLayer.string as! String, attributes: attributes) + let rect = attrString.boundingRect(with: layer.visibleRect.size, options: NSString.DrawingOptions.usesLineFragmentOrigin) + + highSierraLayer.frame = rect + highSierraLayer.position = CGPoint(x: 2, y: 2) + highSierraLayer.anchorPoint = CGPoint(x: 0, y: 0) + layer.addSublayer(highSierraLayer) + } } // MARK: - Lifecycle stuff diff --git a/Resources/Community/en.json b/Resources/Community/en.json index 1433731d..a31ad50f 100644 --- a/Resources/Community/en.json +++ b/Resources/Community/en.json @@ -57,9 +57,11 @@ }, { "id" : "2F11E857-4F77-4476-8033-4A1E4610AFCC", - "name" : "Sheikh Zayed Road" + "name" : "Sheikh Zayed Road", + "pointsOfInterest" : { + "0" : "Traveling along Sheikh Zayed Road in Dubai, United Arab Emirates" + } }, - { "id" : "E4ED0B22-EB81-4D4F-A29E-7E1EA6B6D980", "name" : "Nuussuaq Peninsula" diff --git a/Resources/Info.plist b/Resources/Info.plist index afecd3c2..2f247828 100644 --- a/Resources/Info.plist +++ b/Resources/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.4.4beta4 + 1.4.5beta2 CFBundleSignature ???? CFBundleVersion - 1.4.4beta4 + 1.4.5beta2 LSApplicationCategoryType LSMinimumSystemVersion diff --git a/Resources/PreferencesWindow.xib b/Resources/PreferencesWindow.xib index 94b8dc1b..767991b7 100644 --- a/Resources/PreferencesWindow.xib +++ b/Resources/PreferencesWindow.xib @@ -1,14 +1,15 @@ - + - - + + + @@ -64,14 +65,18 @@ + + + + @@ -99,39 +104,39 @@ - + - + - + - + - - + + - + - + - + - + @@ -278,7 +283,7 @@ - + @@ -296,7 +301,7 @@ - + @@ -327,7 +332,7 @@ - + @@ -383,7 +388,7 @@ is disabled - + @@ -401,7 +406,7 @@ is disabled - + @@ -421,7 +426,7 @@ is disabled - + @@ -441,16 +446,70 @@ is disabled + + + + + + + + + + + + + + + + + + + + + + + + - + - + @@ -475,7 +534,7 @@ should appear - + @@ -506,7 +565,7 @@ should appear - + @@ -537,7 +596,7 @@ should appear - + @@ -546,11 +605,11 @@ should appear - + - + @@ -559,7 +618,7 @@ should appear - + @@ -599,7 +658,7 @@ should appear - + @@ -630,7 +689,7 @@ should appear - + @@ -642,7 +701,7 @@ should appear - + @@ -663,7 +722,7 @@ should appear - + @@ -680,7 +739,7 @@ should appear - + @@ -700,7 +759,7 @@ should appear - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + @@ -844,7 +903,7 @@ should appear - + @@ -871,7 +930,7 @@ should appear - + @@ -880,7 +939,7 @@ should appear - + @@ -896,7 +955,7 @@ should appear - + @@ -905,22 +964,22 @@ should appear - + - + - + - + @@ -929,7 +988,7 @@ should appear - + @@ -953,7 +1012,7 @@ should appear - + @@ -962,12 +1021,12 @@ should appear - + - + @@ -991,7 +1050,7 @@ should appear - + @@ -1015,7 +1074,7 @@ should appear - + @@ -1048,139 +1107,28 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + @@ -1189,16 +1137,16 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - + - + - + @@ -1218,7 +1166,7 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - + @@ -1227,7 +1175,7 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - + @@ -1235,7 +1183,7 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - + @@ -1244,7 +1192,7 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - + @@ -1253,7 +1201,7 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + @@ -1362,7 +1429,7 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - + @@ -1371,7 +1438,7 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - + - + @@ -1449,7 +1516,7 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - + @@ -1559,7 +1626,7 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - + @@ -1692,15 +1759,15 @@ Shift, but macOS 10.12.4 or above and a compatible Mac are required) - Strict (0°): Calculate when the center of the Sun crosses the horizon -- Official (0.83°) : Calculate when the Sun completely crosses the horizon +- Official (0.83°): Calculate when the Sun completely crosses the horizon Or instead of sunrise and sunset, you can pick from three options for the time of dawn and dusk: -- Civil (6°) : Calculate when the natural sunlight stops/starts requiring artificial light compensation +- Civil (6°): Calculate when the natural sunlight stops/starts requiring artificial light compensation -- Nautical (12°) : Calculate when stars stop/start being seen +- Nautical (12°): Calculate when stars stop/start being seen -- Astronomical (18°) : Calculate the point when the sun no longer interferes with astronomical observations +- Astronomical (18°): Calculate the point when the sun no longer interferes with astronomical observations @@ -1731,7 +1798,7 @@ You can either enter those manually or try to use Location Services on your Mac - + @@ -1744,6 +1811,36 @@ You can either enter those manually or try to use Location Services on your Mac + + + + + + + + + + On Power Saving mode, Aerial will no longer play videos. It will show a black screen instead and lower your screen brightness to the minimum. + +You can enable it when on battery, or only when your battery reach 20%. + + + + + + + + + + + + + + + + + +