Skip to content

Commit

Permalink
Merge pull request #67 from karbassi/feature/dark-mode
Browse files Browse the repository at this point in the history
Dark Mode
  • Loading branch information
karbassi authored Apr 11, 2020
2 parents a6cca9f + af7ac45 commit 3f02077
Show file tree
Hide file tree
Showing 13 changed files with 195 additions and 78 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# A simple Timer app for Mac

<img src="/screenshots/timer.png?raw=true" width="262" align="right">
<img src="/screenshots/light-mode.png?raw=true" width="262" align="right">

<img src="/screenshots/dark-mode.png?raw=true" width="262" align="right">

[Download here](https://github.com/michaelvillar/timer-app/releases)

Expand Down
8 changes: 4 additions & 4 deletions Timer.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,7 @@
TargetAttributes = {
4C30BBF71CA7C56500C45EBF = {
CreatedOnToolsVersion = 7.3;
DevelopmentTeam = H9MWYLG8FW;
LastSwiftMigration = 0940;
LastSwiftMigration = 1140;
};
};
};
Expand All @@ -127,6 +126,7 @@
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
Base,
);
Expand Down Expand Up @@ -300,7 +300,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.michaelvillar.Timer;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
Expand All @@ -317,7 +317,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.michaelvillar.Timer;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 5.0;
};
name = Release;
};
Expand Down
2 changes: 1 addition & 1 deletion Timer/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
if let window = notification.object as? NSWindow,
let controller = window.windowController as? MVTimerController,
controller != currentlyInDock,
let index = controllers.index(of: controller) {
let index = controllers.firstIndex(of: controller) {
controllers.remove(at: index)
}
}
Expand Down
63 changes: 32 additions & 31 deletions Timer/Assets.xcassets/AppIcon.appiconset/Contents.json
Original file line number Diff line number Diff line change
@@ -1,67 +1,68 @@
{
"images" : [
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "app-icon_16.png",
"scale" : "1x"
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "app-icon_32.png",
"scale" : "2x"
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "app-icon_32.png",
"scale" : "1x"
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "app-icon_64.png",
"scale" : "2x"
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "app-icon_128.png",
"scale" : "1x"
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "app-icon_256.png",
"scale" : "2x"
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "app-icon_256.png",
"scale" : "1x"
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "app-icon_512.png",
"scale" : "2x"
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "app-icon_512.png",
"scale" : "1x"
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"filename" : "app-icon_1024.png",
"idiom" : "mac",
"size" : "512x512",
"scale" : "2x"
"scale" : "2x",
"size" : "512x512"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xD6",
"green" : "0xD4",
"red" : "0xD6"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x12",
"green" : "0x12",
"red" : "0x12"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
38 changes: 38 additions & 0 deletions Timer/Assets.xcassets/background-top-color.colorset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xF2",
"green" : "0xF1",
"red" : "0xF2"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x27",
"green" : "0x27",
"red" : "0x27"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
65 changes: 39 additions & 26 deletions Timer/MVClockView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Cocoa

class MVClockView: NSControl {

private var imageView: NSImageView!
private var clockFaceView: MVClockFaceView!
private var pauseIconImageView: NSImageView!
private var progressView: MVClockProgressView!
private var arrowView: MVClockArrowView!
Expand Down Expand Up @@ -87,11 +87,11 @@ class MVClockView: NSControl {
self.layoutSubviews()
self.addSubview(arrowView)

imageView = MVClockImageView(frame: NSMakeRect(16, 15, 118, 118))
self.addSubview(imageView)
clockFaceView = MVClockFaceView(frame: NSMakeRect(16, 15, 118, 118))
self.addSubview(clockFaceView)

pauseIconImageView = NSImageView(frame: NSMakeRect(70, 99, 10, 12))
pauseIconImageView.image = NSImage(named: NSImage.Name(rawValue: "icon-pause"))
pauseIconImageView.image = NSImage(named: "icon-pause")
pauseIconImageView.alphaValue = 0.0
self.addSubview(pauseIconImageView)

Expand All @@ -114,13 +114,13 @@ class MVClockView: NSControl {

let minutesLabelSuffix = "'"
let minutesLabelSize = minutesLabelSuffix.size(withAttributes: [
NSAttributedStringKey.font: minutesLabel.font!
NSAttributedString.Key.font: minutesLabel.font!
])
minutesLabelSuffixWidth = minutesLabelSize.width

let minutesLabelSecondsSuffix = "\""
let minutesLabelSecondsSize = minutesLabelSecondsSuffix.size(withAttributes: [
NSAttributedStringKey.font: minutesLabel.font!
NSAttributedString.Key.font: minutesLabel.font!
])
minutesLabelSecondsSuffixWidth = minutesLabelSecondsSize.width

Expand All @@ -136,11 +136,11 @@ class MVClockView: NSControl {

let secondsLabelSuffix = "'"
let secondsLabelSize = secondsLabelSuffix.size(withAttributes: [
NSAttributedStringKey.font: secondsLabel.font!
NSAttributedString.Key.font: secondsLabel.font!
])
secondsSuffixWidth = secondsLabelSize.width

self.updateClockImageView()
self.updateClockFaceView()
self.updateAllViews()

let nc = NotificationCenter.default
Expand All @@ -156,16 +156,11 @@ class MVClockView: NSControl {
}

@objc func windowFocusChanged(_ notification: Notification) {
self.updateClockImageView()
self.updateClockFaceView()
}

private func updateClockImageView(highlighted: Bool = false) {
let windowHasFocus = self.window?.isKeyWindow ?? false
var image = windowHasFocus ? "clock" : "clock-unfocus"
if highlighted {
image = "clock-highlighted"
}
imageView.image = NSImage(named: NSImage.Name(rawValue: image))
private func updateClockFaceView(highlighted: Bool = false) {
clockFaceView.update(highlighted: highlighted)
}

private func center(_ view: NSView) {
Expand Down Expand Up @@ -224,7 +219,7 @@ class MVClockView: NSControl {
let showPauseIcon = paused && self.timer != nil
NSAnimationContext.runAnimationGroup({ (ctx) in
ctx.duration = 0.2
ctx.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
ctx.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
self.pauseIconImageView.animator().alphaValue = showPauseIcon ? 1 : 0
self.timerTimeLabel.animator().alphaValue = showPauseIcon ? 0 : 1
}, completionHandler: nil)
Expand All @@ -235,15 +230,15 @@ class MVClockView: NSControl {

override func mouseDown(with event: NSEvent) {
self.didDrag = false
self.updateClockImageView(highlighted: true)
self.updateClockFaceView(highlighted: true)

self.nextResponder?.mouseDown(with: event) // Allow window to also track the event (so user can drag window)
}

override func mouseDragged(with event: NSEvent) {
if !self.didDrag {
self.didDrag = true
self.updateClockImageView()
self.updateClockFaceView()
}
}

Expand All @@ -252,7 +247,7 @@ class MVClockView: NSControl {
if self.hitTest(point) == self && !self.didDrag {
self.handleClick()
}
self.updateClockImageView()
self.updateClockFaceView()
}

override func keyUp(with theEvent: NSEvent) {
Expand Down Expand Up @@ -528,7 +523,7 @@ class MVClockProgressView: NSView {
transform.translate(x: -cp.x, y: -cp.y)
(transform as NSAffineTransform).concat()

let image = NSImage(named: windowHasFocus ? NSImage.Name(rawValue: "progress") : NSImage.Name(rawValue: "progress-unfocus"))
let image = NSImage(named: windowHasFocus ? "progress" : "progress-unfocus")
image?.draw(in: self.bounds)

ctx?.restoreGraphicsState()
Expand Down Expand Up @@ -657,10 +652,28 @@ class MVClockArrowView: NSControl {

}

class MVClockImageView: NSImageView {

override func hitTest(_ aPoint: NSPoint) -> NSView? {
return nil
class MVClockFaceView: NSView {

private var _image:NSImage?

func update(highlighted: Bool = false) {
// Load the appropriate image for the clock face
let imageName:String
if highlighted {
imageName = "clock-highlighted"
} else {
let windowHasFocus = self.window?.isKeyWindow ?? false
imageName = windowHasFocus ? "clock" : "clock-unfocus"
}

_image = NSImage(named: NSImage.Name(imageName))

setNeedsDisplay(self.bounds)
}

override func draw(_ dirtyRect: NSRect) {
if let image = _image {
image.draw(in: self.bounds)
}
}

}
Loading

0 comments on commit 3f02077

Please sign in to comment.