From e0b89a5195c221d75a3e9879ce688077bf3e235c Mon Sep 17 00:00:00 2001 From: Alan Tai Date: Thu, 27 Feb 2020 15:02:50 +0800 Subject: [PATCH] Add options to disable background and animation; remove Unsplash API key --- DevExcuses.xcodeproj/project.pbxproj | 16 +- DevExcuses/Sources/Config/ConfigSheet.xib | 230 +++++++++--------- .../Config/ConfigSheetController.swift | 75 ++++-- DevExcuses/Sources/Config/Configs.swift | 52 ++-- DevExcuses/Sources/Constants.swift | 88 +++++++ DevExcuses/Sources/DevExcusesView.swift | 151 +++--------- DevExcuses/Sources/KenBurnsView.swift | 73 +++--- DevExcuses/Sources/UnsplashClient.swift | 9 +- .../SecurityCamera.xcodeproj/project.pbxproj | 4 +- 9 files changed, 390 insertions(+), 308 deletions(-) create mode 100644 DevExcuses/Sources/Constants.swift diff --git a/DevExcuses.xcodeproj/project.pbxproj b/DevExcuses.xcodeproj/project.pbxproj index 04ba294..d3846c2 100644 --- a/DevExcuses.xcodeproj/project.pbxproj +++ b/DevExcuses.xcodeproj/project.pbxproj @@ -3,11 +3,12 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ 241F01FA0BFC50E2D06A6568 /* libPods-devexcuses-DevexcusesTest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7239B59036FBDC9BED38B3E8 /* libPods-devexcuses-DevexcusesTest.a */; }; + 2D5C42A02407952800A01D6D /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D5C429F2407952800A01D6D /* Constants.swift */; }; 7B480B52223254C00019EB07 /* UnsplashClientTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B480B51223254C00019EB07 /* UnsplashClientTest.swift */; }; 7B480B67223264530019EB07 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = E71262FB2080FF78006D94DA /* User.swift */; }; 7B480B68223264530019EB07 /* UserLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = E71262FD20810014006D94DA /* UserLinks.swift */; }; @@ -32,6 +33,7 @@ /* Begin PBXFileReference section */ 27C93E4E9697D42766097BFE /* Pods-devexcuses.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-devexcuses.release.xcconfig"; path = "Pods/Target Support Files/Pods-devexcuses/Pods-devexcuses.release.xcconfig"; sourceTree = ""; }; + 2D5C429F2407952800A01D6D /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; 3E863DF3A0B23534EF450EF5 /* Pods-DevexcusesTest.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DevexcusesTest.release.xcconfig"; path = "Pods/Target Support Files/Pods-DevexcusesTest/Pods-DevexcusesTest.release.xcconfig"; sourceTree = ""; }; 539D1BC2C6EE6F55F52398E0 /* Pods-devexcuses-DevexcusesTest.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-devexcuses-DevexcusesTest.release.xcconfig"; path = "Pods/Target Support Files/Pods-devexcuses-DevexcusesTest/Pods-devexcuses-DevexcusesTest.release.xcconfig"; sourceTree = ""; }; 7239B59036FBDC9BED38B3E8 /* libPods-devexcuses-DevexcusesTest.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-devexcuses-DevexcusesTest.a"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -128,10 +130,11 @@ children = ( E744BD01209AF690001B8597 /* Config */, E71262FA2080FF59006D94DA /* Models */, + 2D5C429F2407952800A01D6D /* Constants.swift */, E7CDCC792080F56100A553DF /* DevExcusesView.swift */, - E712630320810241006D94DA /* UnsplashClient.swift */, - E73C70152099B72D0086AADC /* KenBurnsView.swift */, E70963302081BDD8006B381C /* Extensions.swift */, + E73C70152099B72D0086AADC /* KenBurnsView.swift */, + E712630320810241006D94DA /* UnsplashClient.swift */, ); path = Sources; sourceTree = ""; @@ -249,7 +252,7 @@ }; }; buildConfigurationList = E7CDCC662080F42200A553DF /* Build configuration list for PBXProject "DevExcuses" */; - compatibilityVersion = "Xcode 9.3"; + compatibilityVersion = "Xcode 11.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -366,6 +369,7 @@ E7CDCC7A2080F56100A553DF /* DevExcusesView.swift in Sources */, E71263022081016D006D94DA /* Photo.swift in Sources */, E744BD03209AF6BA001B8597 /* ConfigSheetController.swift in Sources */, + 2D5C42A02407952800A01D6D /* Constants.swift in Sources */, E712630420810241006D94DA /* UnsplashClient.swift in Sources */, E7126300208100F3006D94DA /* PhotoUrls.swift in Sources */, E7C981DB209B3D9700459F44 /* Configs.swift in Sources */, @@ -549,7 +553,7 @@ "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.14; + MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = com.github.ayltai.devexcuses; PRODUCT_NAME = "Developers Excuses"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -573,7 +577,7 @@ "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.14; + MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = com.github.ayltai.devexcuses; PRODUCT_NAME = "Developers Excuses"; SWIFT_VERSION = 5.0; diff --git a/DevExcuses/Sources/Config/ConfigSheet.xib b/DevExcuses/Sources/Config/ConfigSheet.xib index 8032a7a..45c4512 100644 --- a/DevExcuses/Sources/Config/ConfigSheet.xib +++ b/DevExcuses/Sources/Config/ConfigSheet.xib @@ -1,21 +1,22 @@ - + - + + - + @@ -25,109 +26,98 @@ - + - + - + - + - - + + - - - - - - - - - - - - - NSAllRomanInputSourcesLocaleIdentifier - - + - + - + - + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -146,100 +136,90 @@ - - - - - + - + - + - + + + + - + - - - - + - + - + - + + + + - + - + - + - + - + - + - + @@ -253,7 +233,7 @@ - + @@ -261,7 +241,7 @@ - + Gw @@ -274,7 +254,7 @@ Gw - + DQ @@ -283,10 +263,45 @@ DQ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + @@ -294,63 +309,60 @@ DQ - + + + - + - - - - + - - - - + + + - - - + + - - + - + - + + + - - - + + + - + - - + diff --git a/DevExcuses/Sources/Config/ConfigSheetController.swift b/DevExcuses/Sources/Config/ConfigSheetController.swift index f91723e..0bbf689 100644 --- a/DevExcuses/Sources/Config/ConfigSheetController.swift +++ b/DevExcuses/Sources/Config/ConfigSheetController.swift @@ -1,18 +1,20 @@ import AppKit +@available(OSX 10.15, *) final class ConfigSheetController: NSWindowController { private let configs = Configs() - @IBOutlet weak var apiKey : NSTextField? - @IBOutlet weak var darken : NSSlider? - @IBOutlet weak var maxZoom : NSSlider? - @IBOutlet weak var duration : NSPopUpButton? - @IBOutlet weak var videoEnabled : NSButton? - @IBOutlet weak var cameraAppPicker: NSButton? - @IBOutlet weak var cameraAppPath : NSTextField? - @IBOutlet weak var videoSavePicker: NSButton? - @IBOutlet weak var videoSavePath : NSTextField? - @IBOutlet weak var imageTopics : NSTextView? + @IBOutlet weak var backgroundEnabled: NSSwitch? + @IBOutlet weak var animationEnabled : NSSwitch? + @IBOutlet weak var darken : NSSlider? + @IBOutlet weak var maxZoom : NSSlider? + @IBOutlet weak var duration : NSPopUpButton? + @IBOutlet weak var videoEnabled : NSSwitch? + @IBOutlet weak var cameraAppPicker : NSButton? + @IBOutlet weak var cameraAppPath : NSTextField? + @IBOutlet weak var videoSavePicker : NSButton? + @IBOutlet weak var videoSavePath : NSTextField? + @IBOutlet weak var imageTopics : NSTextView? override var windowNibName: NSNib.Name! { return "ConfigSheet" @@ -21,8 +23,16 @@ final class ConfigSheetController: NSWindowController { override func windowDidLoad() { super.windowDidLoad() - if let apiKey = self.apiKey { - apiKey.stringValue = self.configs.apiKey + if let backgroundEnabled = self.backgroundEnabled { + backgroundEnabled.state = self.configs.backgroundEnabled ? .on : .off + + self.toggleBackgroundConfigs(sender: backgroundEnabled) + } + + if let animationEnabled = self.animationEnabled { + animationEnabled.state = self.configs.animationEnabled ? .on : .off + + self.toggleAnimationConfigs(sender: animationEnabled) } if let darken = self.darken { @@ -70,6 +80,39 @@ final class ConfigSheetController: NSWindowController { } } + @IBAction func toggleBackgroundConfigs(sender: Any?) { + if + let backgroundEnabled = self.backgroundEnabled, + let animationEnabled = self.animationEnabled, + let darken = self.darken, + let maxZoom = self.maxZoom, + let imageTopics = self.imageTopics { + if backgroundEnabled.state == .on { + animationEnabled.isEnabled = true + darken.isEnabled = true + maxZoom.isEnabled = true + imageTopics.isEditable = true + } else if backgroundEnabled.state == .off { + animationEnabled.isEnabled = false + darken.isEnabled = false + maxZoom.isEnabled = false + imageTopics.isEditable = false + } + } + } + + @IBAction func toggleAnimationConfigs(sender: Any?) { + if + let animationEnabled = self.animationEnabled, + let maxZoom = self.maxZoom { + if animationEnabled.state == .on { + maxZoom.isEnabled = true + } else if animationEnabled.state == .off { + maxZoom.isEnabled = false + } + } + } + @IBAction func toggleVideoConfigs(sender: Any?) { if let videoEnabled = self.videoEnabled, @@ -136,8 +179,12 @@ final class ConfigSheetController: NSWindowController { } @IBAction func ok(sender: Any?) { - if let apiKey = self.apiKey { - self.configs.apiKey = apiKey.stringValue + if let backgroundEnabled = self.backgroundEnabled { + self.configs.backgroundEnabled = backgroundEnabled.state == .on + } + + if let animationEnabled = self.animationEnabled { + self.configs.animationEnabled = animationEnabled.state == .on } if let darken = self.darken { diff --git a/DevExcuses/Sources/Config/Configs.swift b/DevExcuses/Sources/Config/Configs.swift index 19b5128..3cd157d 100644 --- a/DevExcuses/Sources/Config/Configs.swift +++ b/DevExcuses/Sources/Config/Configs.swift @@ -3,14 +3,15 @@ import ScreenSaver final class Configs: NSObject { public static let videoSavePathSuffix = "/SecurityCamera-%timestamp%.mov" - private static let apiKey = "api" - private static let darkenKey = "darken" - private static let maxZoomKey = "maxZoom" - private static let durationKey = "duration" - private static let videoEnabledKey = "videoEnabled" - private static let cameraAppPathKey = "cameraAppPath" - private static let videoSavePathKey = "videoSavePath" - private static let imageTopicsKey = "imageTopics" + private static let backgroundEnabledKey = "backgroundEnabled" + private static let animationEnabledKey = "animationEnabled" + private static let darkenKey = "darken" + private static let maxZoomKey = "maxZoom" + private static let durationKey = "duration" + private static let videoEnabledKey = "videoEnabled" + private static let cameraAppPathKey = "cameraAppPath" + private static let videoSavePathKey = "videoSavePath" + private static let imageTopicsKey = "imageTopics" private let defaults: ScreenSaverDefaults = Configs.defaults() @@ -20,17 +21,23 @@ final class Configs: NSObject { self.register() } - var apiKey: String { + var backgroundEnabled: Bool { get { - guard let value = self.defaults.string(forKey: Configs.apiKey) else { - return "" - } + return self.defaults.bool(forKey: Configs.backgroundEnabledKey) + } - return value + set { + self.set(newValue, forKey: Configs.backgroundEnabledKey) + } + } + + var animationEnabled: Bool { + get { + return self.defaults.bool(forKey: Configs.animationEnabledKey) } set { - self.set(newValue, forKey: Configs.apiKey) + self.set(newValue, forKey: Configs.animationEnabledKey) } } @@ -118,14 +125,15 @@ final class Configs: NSObject { func register() { let defaults: [String: Any] = [ - Configs.apiKey : "", - Configs.darkenKey : 15, - Configs.maxZoomKey : 175, - Configs.durationKey : 15, - Configs.videoEnabledKey : true, - Configs.cameraAppPathKey: "SecurityCamera", - Configs.videoSavePathKey: "~/Movies", - Configs.imageTopicsKey : [ + Configs.backgroundEnabledKey: true, + Configs.animationEnabledKey : true, + Configs.darkenKey : 15, + Configs.maxZoomKey : 175, + Configs.durationKey : 15, + Configs.videoEnabledKey : true, + Configs.cameraAppPathKey : "SecurityCamera", + Configs.videoSavePathKey : "~/Movies", + Configs.imageTopicsKey : [ "nature", "landscape", "water", diff --git a/DevExcuses/Sources/Constants.swift b/DevExcuses/Sources/Constants.swift new file mode 100644 index 0000000..11b28e9 --- /dev/null +++ b/DevExcuses/Sources/Constants.swift @@ -0,0 +1,88 @@ +import Cocoa + +final class Constants: NSObject { + public static let excuses = [ + "I thought you signed off on that.", + "That feature was slated for phase two.", + "That feature would be outside the scope.", + "It must be a hardware problem.", + "It's never shown unexpected behavior like this before.", + "There must be something strange in your data.", + "Well, that's a first.", + "I haven't touched that code in weeks.", + "Oh, you said you DIDN'T want that to happen?", + "That's already fixed. It just hasn't taken effect yet.", + "I couldn't find any library that can even do that.", + "I usually get a notification when that happens.", + "Oh, that was just a temporary fix.", + "It's never done that before.", + "It's a compatibility issue.", + "Everything looks fine on my end.", + "That error means it was successful.", + "I forgot to commit the code that fixes that.", + "You must have done something wrong.", + "That wasn't in the original specification.", + "I haven't had any experience with that before.", + "That's the fault of the graphic designer.", + "I'll have to fix that at a later date.", + "I told you yesterday it would be done by the end of today.", + "I haven't been able to reproduce that.", + "It's just some unlucky coincidence.", + "I thought you signed off on that.", + "That wouldn't be economically feasible.", + "I didn't create that part of the program.", + "It probably won't happen again.", + "Actually, that's a feature.", + "I have too many other high priority things to do right now.", + "Our internet connection must not be working.", + "It's always been like that.", + "What did you type in wrong to get it to crash?", + "I thought I finished that.", + "The request must have dropped some packets.", + "It is working on my computer.", + "It was working yesterday.", + "You are working with the wrong version.", + "The third party application is causing the problem.", + "Right now I am doing the analysis, so I haven't started the work yet.", + "Please raise a defect, I will check it.", + "Try restarting your machine.", + "I don't think there's fault with my code.", + "Someone must have changed my code.", + "I had too many projects so I had to rush that feature.", + "I'm still working on that.", + "That's a character encoding issue.", + "There must have been a miscommunication on the requirements.", + "We weren't given enough time to write unit tests.", + "Our code quality is up to industry standards.", + "That is a known bug with the framework.", + "That feature is a nice to have.", + "Have you cleared your cache?", + "That's been fixed, but the code still has to be released.", + "That's been fixed on another branch.", + "The developer who coded that doesn't work here anymore.", + "That is part of the old system.", + "It was probably a race condition.", + "That is how we were asked to build it.", + "There must be a problem with the virtual machine.", + "We have to do it that way for security reasons.", + "I just need one more day to work on that.", + "That code was written by the last guy.", + "It was such a simple change I didn't think it needed testing.", + "The file must have corrupted.", + "There is nothing in my error logs.", + "That's an industry best practice.", + "It must be an issue with the firewall.", + "It's just a warning, not an error.", + "There's only a one in a million chance of that error occurring.", + "That software should have been updated ages ago.", + "Are you sure you want it to work that way?", + "I'm pretty sure that works most of the time.", + "I was busy fixing more important issues.", + "I'm not familiar with it so I didn't fix it in case I made it worse", + "How is that possible", + "The third party documentation is wrong", + "The project manager told me to do it that way", + "My time was split in a way that meant I couldn't do either project properly", + "The existing design makes it difficult to do the right thing", + ] +} diff --git a/DevExcuses/Sources/DevExcusesView.swift b/DevExcuses/Sources/DevExcusesView.swift index 538e0d4..ccf5dbb 100644 --- a/DevExcuses/Sources/DevExcusesView.swift +++ b/DevExcuses/Sources/DevExcusesView.swift @@ -6,93 +6,7 @@ class DevExcusesView: ScreenSaverView { private static let userNamePrefix = "Unsplash > " private static let profileUrlSuffix = "?utm_source=Developers%20Excuses&utm_medium=referral" - private static let excuses = [ - "I thought you signed off on that.", - "That feature was slated for phase two.", - "That feature would be outside the scope.", - "It must be a hardware problem.", - "It's never shown unexpected behavior like this before.", - "There must be something strange in your data.", - "Well, that's a first.", - "I haven't touched that code in weeks.", - "Oh, you said you DIDN'T want that to happen?", - "That's already fixed. It just hasn't taken effect yet.", - "I couldn't find any library that can even do that.", - "I usually get a notification when that happens.", - "Oh, that was just a temporary fix.", - "It's never done that before.", - "It's a compatibility issue.", - "Everything looks fine on my end.", - "That error means it was successful.", - "I forgot to commit the code that fixes that.", - "You must have done something wrong.", - "That wasn't in the original specification.", - "I haven't had any experience with that before.", - "That's the fault of the graphic designer.", - "I'll have to fix that at a later date.", - "I told you yesterday it would be done by the end of today.", - "I haven't been able to reproduce that.", - "It's just some unlucky coincidence.", - "I thought you signed off on that.", - "That wouldn't be economically feasible.", - "I didn't create that part of the program.", - "It probably won't happen again.", - "Actually, that's a feature.", - "I have too many other high priority things to do right now.", - "Our internet connection must not be working.", - "It's always been like that.", - "What did you type in wrong to get it to crash?", - "I thought I finished that.", - "The request must have dropped some packets.", - "It is working on my computer.", - "It was working yesterday.", - "You are working with the wrong version.", - "The third party application is causing the problem.", - "Right now I am doing the analysis, so I haven't started the work yet.", - "Please raise a defect, I will check it.", - "Try restarting your machine.", - "I don't think there's fault with my code.", - "Someone must have changed my code.", - "I had too many projects so I had to rush that feature.", - "I'm still working on that.", - "That's a character encoding issue.", - "There must have been a miscommunication on the requirements.", - "We weren't given enough time to write unit tests.", - "Our code quality is up to industry standards.", - "That is a known bug with the framework.", - "That feature is a nice to have.", - "Have you cleared your cache?", - "That's been fixed, but the code still has to be released.", - "That's been fixed on another branch.", - "The developer who coded that doesn't work here anymore.", - "That is part of the old system.", - "It was probably a race condition.", - "That is how we were asked to build it.", - "There must be a problem with the virtual machine.", - "We have to do it that way for security reasons.", - "I just need one more day to work on that.", - "That code was written by the last guy.", - "It was such a simple change I didn't think it needed testing.", - "The file must have corrupted.", - "There is nothing in my error logs.", - "That's an industry best practice.", - "It must be an issue with the firewall.", - "It's just a warning, not an error.", - "There's only a one in a million chance of that error occurring.", - "That software should have been updated ages ago.", - "Are you sure you want it to work that way?", - "I'm pretty sure that works most of the time.", - "I was busy fixing more important issues.", - "I'm not familiar with it so I didn't fix it in case I made it worse", - "How is that possible", - "The third party documentation is wrong", - "The project manager told me to do it that way", - "My time was split in a way that meant I couldn't do either project properly", - "The existing design makes it difficult to do the right thing", - ] - - private static let duration : TimeInterval = 15 - private static let textMargin: Int = 8 + private static let textMargin: Int = 8 private lazy var configSheetController: ConfigSheetController = { return ConfigSheetController() @@ -149,7 +63,7 @@ class DevExcusesView: ScreenSaverView { self.creditShadow.shadowColor = NSColor.black self.creditShadow.shadowBlurRadius = self.bounds.width / 512 - self.client = UnsplashClient(apiKey: self.configs.apiKey) + self.client = UnsplashClient() self.animationTimeInterval = Double(self.configs.duration) if self.configs.videoEnabled && !isPreview { @@ -194,23 +108,24 @@ class DevExcusesView: ScreenSaverView { } override func animateOneFrame() { - guard let client = self.client else { - return - } + if self.configs.backgroundEnabled { + guard let client = self.client else { + return + } - client.random(size: self.frame.size, query: self.configs.imageTopics) - .subscribe { event in - if let error = event.error { - self.update( - excuse : error.localizedDescription, - background: nil, - userName : nil, - profileUrl: nil - ) - - self.setNeedsDisplay(self.frame) - } else if let photo = event.element { - photo.download() + client.random(size: self.frame.size, query: self.configs.imageTopics) + .subscribe { event in + if let error = event.error { + self.update( + excuse : error.localizedDescription, + background: nil, + userName : nil, + profileUrl: nil + ) + + self.setNeedsDisplay(self.frame) + } else if let photo = event.element { + photo.download() .observeOn(MainScheduler.instance) .subscribeOn(CurrentThreadScheduler.instance) .subscribe { event in @@ -228,18 +143,27 @@ class DevExcusesView: ScreenSaverView { let links = user.links, let profileUrl = links.html { self.update( - excuse : DevExcusesView.excuses[DevExcusesView.excuses.count.random()], + excuse : Constants.excuses[Constants.excuses.count.random()], background: data, userName : userName, - profileUrl: profileUrl) + profileUrl: profileUrl + ) } self.setNeedsDisplay(self.frame) } .disposed(by: self.disposeBag) + } } - } - .disposed(by: self.disposeBag) + .disposed(by: self.disposeBag) + } else { + self.update( + excuse : Constants.excuses[Constants.excuses.count.random()], + background: nil, + userName : nil, + profileUrl: nil + ) + } } private func update( @@ -247,8 +171,10 @@ class DevExcusesView: ScreenSaverView { background: Data?, userName : String?, profileUrl: String?) { - if let background = background { - self.updateImageView(data: background) + if self.configs.backgroundEnabled { + if let background = background { + self.updateImageView(data: background) + } } if @@ -320,9 +246,8 @@ class DevExcusesView: ScreenSaverView { self.addSubview(imageView) imageView.animate( - image : NSImage(data: data), - alpha : CGFloat(1 - Float(self.configs.darken) / 100), - duration: self.isPreview ? DevExcusesView.duration : Double(self.configs.duration)) + image: NSImage(data: data), + alpha: CGFloat(1 - Float(self.configs.darken) / 100)) if let oldImageView = self.imageView { oldImageView.removeFromSuperview() diff --git a/DevExcuses/Sources/KenBurnsView.swift b/DevExcuses/Sources/KenBurnsView.swift index ae71808..512d34d 100644 --- a/DevExcuses/Sources/KenBurnsView.swift +++ b/DevExcuses/Sources/KenBurnsView.swift @@ -3,12 +3,9 @@ import Cocoa final class KenBurnsView: NSImageView { private let configs = Configs() - private var duration: TimeInterval = 15 - - func animate(image: NSImage?, alpha: CGFloat, duration: TimeInterval) { + func animate(image: NSImage?, alpha: CGFloat) { self.image = image self.alphaValue = alpha - self.duration = duration } override var wantsUpdateLayer: Bool { @@ -16,37 +13,43 @@ final class KenBurnsView: NSImageView { } override func makeBackingLayer() -> CALayer { - let width = Double(self.frame.size.width) - let height = Double(self.frame.size.height) - let maxScale = Double(self.configs.maxZoom) / 100 - let fromScale = Double.random(min: 1, max: maxScale) - let toScale = Double.random(min: 1, max: maxScale) - let minTranslation = -(maxScale - 1) - - let scaleAnimation = CABasicAnimation(keyPath: "transform.scale") - scaleAnimation.autoreverses = true - scaleAnimation.duration = duration - scaleAnimation.fromValue = fromScale - scaleAnimation.toValue = toScale - - let xAnimation = CABasicAnimation(keyPath: "transform.translation.x") - xAnimation.autoreverses = true - xAnimation.duration = duration - xAnimation.fromValue = KenBurnsView.randomTranslation(min: minTranslation, max: width, scale: fromScale) - xAnimation.toValue = KenBurnsView.randomTranslation(min: minTranslation, max: width, scale: toScale) - - let yAnimation = CABasicAnimation(keyPath: "transform.translation.y") - yAnimation.autoreverses = true - yAnimation.duration = duration - yAnimation.fromValue = KenBurnsView.randomTranslation(min: minTranslation, max: height, scale: fromScale) - yAnimation.toValue = KenBurnsView.randomTranslation(min: minTranslation, max: height, scale: toScale) - - let layer = CALayer() - layer.add(scaleAnimation, forKey: scaleAnimation.keyPath) - layer.add(xAnimation, forKey: xAnimation.keyPath) - layer.add(yAnimation, forKey: yAnimation.keyPath) - - return layer + let duration = Double(self.configs.duration) + + if self.configs.animationEnabled { + let width = Double(self.frame.size.width) + let height = Double(self.frame.size.height) + let maxScale = Double(self.configs.maxZoom) / 100 + let fromScale = Double.random(min: 1, max: maxScale) + let toScale = Double.random(min: 1, max: maxScale) + let minTranslation = 1 - maxScale + + let scaleAnimation = CABasicAnimation(keyPath: "transform.scale") + scaleAnimation.autoreverses = true + scaleAnimation.duration = duration + scaleAnimation.fromValue = fromScale + scaleAnimation.toValue = toScale + + let xAnimation = CABasicAnimation(keyPath: "transform.translation.x") + xAnimation.autoreverses = true + xAnimation.duration = duration + xAnimation.fromValue = KenBurnsView.randomTranslation(min: minTranslation, max: width, scale: fromScale) + xAnimation.toValue = KenBurnsView.randomTranslation(min: minTranslation, max: width, scale: toScale) + + let yAnimation = CABasicAnimation(keyPath: "transform.translation.y") + yAnimation.autoreverses = true + yAnimation.duration = duration + yAnimation.fromValue = KenBurnsView.randomTranslation(min: minTranslation, max: height, scale: fromScale) + yAnimation.toValue = KenBurnsView.randomTranslation(min: minTranslation, max: height, scale: toScale) + + let layer = CALayer() + layer.add(scaleAnimation, forKey: scaleAnimation.keyPath) + layer.add(xAnimation, forKey: xAnimation.keyPath) + layer.add(yAnimation, forKey: yAnimation.keyPath) + + return layer + } + + return CALayer() } private static func randomTranslation(min: Double, max: Double, scale: Double) -> Double { diff --git a/DevExcuses/Sources/UnsplashClient.swift b/DevExcuses/Sources/UnsplashClient.swift index 3b1c555..06caee3 100644 --- a/DevExcuses/Sources/UnsplashClient.swift +++ b/DevExcuses/Sources/UnsplashClient.swift @@ -1,18 +1,11 @@ import RxSwift final class UnsplashClient { - private static let endPoint = "https://api.unsplash.com/" - - private let apiKey: String - - init(apiKey: String) { - self.apiKey = apiKey - } + private static let endPoint = "https://unsplash-api-proxy.appspot.com/" func random(size: CGSize, query: [String]?) -> Observable { return Observable.create { observer in var queryItems: [URLQueryItem] = [ - URLQueryItem(name: "client_id", value: self.apiKey), URLQueryItem(name: "w", value: String(Int(size.width))), URLQueryItem(name: "h", value: String(Int(size.height))) ] diff --git a/SecurityCamera/SecurityCamera.xcodeproj/project.pbxproj b/SecurityCamera/SecurityCamera.xcodeproj/project.pbxproj index 1941f2b..d29d8c8 100644 --- a/SecurityCamera/SecurityCamera.xcodeproj/project.pbxproj +++ b/SecurityCamera/SecurityCamera.xcodeproj/project.pbxproj @@ -92,7 +92,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0930; - LastUpgradeCheck = 0930; + LastUpgradeCheck = 1130; ORGANIZATIONNAME = "Alan Tai"; TargetAttributes = { E7A751AA20915CBD00DBF96E = { @@ -248,6 +248,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 4.0; @@ -258,6 +259,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 4.0;