Skip to content

Commit

Permalink
Add wind direction for weather
Browse files Browse the repository at this point in the history
Fix the rounding on °F/°C (who wants kelvin?)
Weather cartridge should look a tad better
  • Loading branch information
glouel committed Mar 5, 2021
1 parent c908d8a commit 2e2c307
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 13 deletions.
16 changes: 16 additions & 0 deletions Aerial.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,12 @@
03A6D14625F109B900960135 /* OpenWeather.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03A6D14525F109B900960135 /* OpenWeather.swift */; };
03A6D14725F109B900960135 /* OpenWeather.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03A6D14525F109B900960135 /* OpenWeather.swift */; };
03A6D14825F109B900960135 /* OpenWeather.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03A6D14525F109B900960135 /* OpenWeather.swift */; };
03A6D14F25F294C900960135 /* location.north.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 03A6D14E25F294C900960135 /* location.north.pdf */; };
03A6D15025F294C900960135 /* location.north.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 03A6D14E25F294C900960135 /* location.north.pdf */; };
03A6D15125F294C900960135 /* location.north.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 03A6D14E25F294C900960135 /* location.north.pdf */; };
03A6D15325F297CE00960135 /* WindDirectionLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03A6D15225F297CE00960135 /* WindDirectionLayer.swift */; };
03A6D15425F297CE00960135 /* WindDirectionLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03A6D15225F297CE00960135 /* WindDirectionLayer.swift */; };
03A6D15525F297CE00960135 /* WindDirectionLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03A6D15225F297CE00960135 /* WindDirectionLayer.swift */; };
03AA7A5D24C84C6300A47970 /* cloud.bolt.rain.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 03AA7A2524C84C6200A47970 /* cloud.bolt.rain.pdf */; };
03AA7A5E24C84C6300A47970 /* cloud.bolt.rain.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 03AA7A2524C84C6200A47970 /* cloud.bolt.rain.pdf */; };
03AA7A5F24C84C6300A47970 /* cloud.bolt.rain.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 03AA7A2524C84C6200A47970 /* cloud.bolt.rain.pdf */; };
Expand Down Expand Up @@ -1072,6 +1078,8 @@
03A596D423AA752F0097EA66 /* InfoClockView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoClockView.swift; sourceTree = "<group>"; };
03A596D823AB8F000097EA66 /* InfoLocationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoLocationView.swift; sourceTree = "<group>"; };
03A6D14525F109B900960135 /* OpenWeather.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenWeather.swift; sourceTree = "<group>"; };
03A6D14E25F294C900960135 /* location.north.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = location.north.pdf; sourceTree = "<group>"; };
03A6D15225F297CE00960135 /* WindDirectionLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindDirectionLayer.swift; sourceTree = "<group>"; };
03AA7A2524C84C6200A47970 /* cloud.bolt.rain.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = cloud.bolt.rain.pdf; sourceTree = "<group>"; };
03AA7A3C24C84C6200A47970 /* wind.snow.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = wind.snow.pdf; sourceTree = "<group>"; };
03AA7A3D24C84C6200A47970 /* snow.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = snow.pdf; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1352,6 +1360,7 @@
03AA7A5C24C84C6300A47970 /* wind.pdf */,
03AA7A3C24C84C6200A47970 /* wind.snow.pdf */,
03AA7A4124C84C6200A47970 /* wrench.pdf */,
03A6D14E25F294C900960135 /* location.north.pdf */,
);
path = Weather;
sourceTree = "<group>";
Expand Down Expand Up @@ -1550,6 +1559,7 @@
03A42A9F2449F959003B3012 /* YahooLogoLayer.swift */,
03A42AA2244A0E5F003B3012 /* ConditionLayer.swift */,
033D68802453080C0016F837 /* ConditionSymbolLayer.swift */,
03A6D15225F297CE00960135 /* WindDirectionLayer.swift */,
);
path = Weather;
sourceTree = "<group>";
Expand Down Expand Up @@ -2153,6 +2163,7 @@
03AA7A7924C84C6300A47970 /* sun.max.pdf in Resources */,
03933B8F24C3986800A98D94 /* SourcesViewController.xib in Resources */,
03F752EA24EEFC3100945B1D /* text.cursor.pdf in Resources */,
03A6D15025F294C900960135 /* location.north.pdf in Resources */,
033811B424C1E243002E23E0 /* InfoViewController.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -2273,6 +2284,7 @@
03F752E624EED21100945B1D /* video_inspire_california_vineyard_sierra-mar_sunrise_110.png in Resources */,
03AA7A5F24C84C6300A47970 /* cloud.bolt.rain.pdf in Resources */,
03AA7A7A24C84C6300A47970 /* sun.max.pdf in Resources */,
03A6D15125F294C900960135 /* location.north.pdf in Resources */,
0300B7EE24D1B536006132E5 /* bubble.left.and.bubble.right.pdf in Resources */,
03AA7A8C24C84C6300A47970 /* thermometer.sun.pdf in Resources */,
03977F02250E6918008FBAFD /* de.json in Resources */,
Expand Down Expand Up @@ -2454,6 +2466,7 @@
03AA7A7824C84C6300A47970 /* sun.max.pdf in Resources */,
03933B8E24C3986800A98D94 /* SourcesViewController.xib in Resources */,
03F752E924EEFC3100945B1D /* text.cursor.pdf in Resources */,
03A6D14F25F294C900960135 /* location.north.pdf in Resources */,
033811B324C1E243002E23E0 /* InfoViewController.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -2601,6 +2614,7 @@
0396D55224B8B7ED00CC021B /* LocationLayer.swift in Sources */,
0396D55424B8B7ED00CC021B /* InfoTableSource.swift in Sources */,
0396D55524B8B7ED00CC021B /* Solar.swift in Sources */,
03A6D15425F297CE00960135 /* WindDirectionLayer.swift in Sources */,
0396D55624B8B7ED00CC021B /* Brightness.swift in Sources */,
0300B84A24D1FD24006132E5 /* FirstSetupWindowController.swift in Sources */,
0396D55724B8B7ED00CC021B /* SourceInfo.swift in Sources */,
Expand Down Expand Up @@ -2678,6 +2692,7 @@
038D2EDF23B0FB0D00CD91F7 /* PrefsVideos.swift in Sources */,
03DC0065248BC60D005DB0F4 /* Cache.swift in Sources */,
038D2EE523B6565900CD91F7 /* InfoBatteryView.swift in Sources */,
03A6D15525F297CE00960135 /* WindDirectionLayer.swift in Sources */,
030D9B7C21551A8D00961E95 /* AerialPlayerItem.swift in Sources */,
030A0F2A245C7C7D009E1D97 /* BatteryIconLayer.swift in Sources */,
034587332449E22000C97D1B /* AnimationLayer.swift in Sources */,
Expand Down Expand Up @@ -2862,6 +2877,7 @@
0306336823A1012200046A59 /* LocationLayer.swift in Sources */,
034F29B723A7A93D004B34D5 /* InfoTableSource.swift in Sources */,
03958349217F4416008E8F9C /* Solar.swift in Sources */,
03A6D15325F297CE00960135 /* WindDirectionLayer.swift in Sources */,
F008DAFD23AADCFB00739DE1 /* Brightness.swift in Sources */,
0300B84924D1FD24006132E5 /* FirstSetupWindowController.swift in Sources */,
03C97BC324B6210500739CED /* SourceInfo.swift in Sources */,
Expand Down
53 changes: 47 additions & 6 deletions Aerial/Source/Models/API/OpenWeather.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ struct OWeather: Codable {
let coord: OWCoord?
let weather: [OWWeather]?
let base: String?
let main: OWMain?
var main: OWMain?
let visibility: Int?
let wind: OWWind?
let clouds: OWClouds?
Expand All @@ -32,6 +32,21 @@ struct OWeather: Codable {
let timezone, id: Int?
let name: String?
let cod: Int?

// We round them down a bit as openweather provides up to two decimal point precision
mutating func processTemperatures() {
guard main != nil else {
return
}

if PrefsInfo.weather.degree == .celsius {
main!.temp = main!.temp.rounded(toPlaces: 1)
main!.feelsLike = main!.feelsLike.rounded(toPlaces: 1)
} else {
main!.temp = main!.temp.rounded()
main!.feelsLike = main!.feelsLike.rounded()
}
}
}

// MARK: - OWClouds
Expand All @@ -45,9 +60,9 @@ struct OWCoord: Codable {
}
// MARK: - OWMain
struct OWMain: Codable {
let temp: Double
let feelsLike: Double
let tempMin, tempMax, pressure, humidity: Double
var temp: Double
var feelsLike: Double
var tempMin, tempMax, pressure, humidity: Double

enum CodingKeys: String, CodingKey {
case temp
Expand Down Expand Up @@ -85,6 +100,15 @@ struct OWWind: Codable {

struct OpenWeather {

static var testJson = ""

/*
static var testJson =
"""
{"coord":{"lon":-0.1257,"lat":51.5085},"weather":[{"id":802,"main":"Clouds","description":"雲","icon":"03d"}],"base":"stations","main":{"temp":6.02,"feels_like":0.51,"temp_min":5,"temp_max":6.67,"pressure":1033,"humidity":56},"visibility":10000,"wind":{"speed":4.63,"deg":50},"clouds":{"all":40},"dt":1614960144,"sys":{"type":1,"id":1414,"country":"GB","sunrise":1614926218,"sunset":1614966438},"timezone":0,"id":2643743,"name":"ロンドン","cod":200}
"""
*/

static func getUnits() -> String {
if PrefsInfo.weather.degree == .celsius {
return "metric"
Expand Down Expand Up @@ -137,6 +161,20 @@ struct OpenWeather {
}

static func fetch(completion: @escaping(Result<OWeather, NetworkError>) -> Void) {
guard testJson == "" else {
let jsonData = testJson.data(using: .utf8)!

if var openWeather = try? newJSONDecoder().decode(OWeather.self, from: jsonData) {
openWeather.processTemperatures()

completion(.success(openWeather))
} else {
completion(.failure(.unknown))
}

return
}

if PrefsInfo.weather.locationMode == .useCurrent {
let location = Locations.sharedInstance

Expand All @@ -153,7 +191,9 @@ struct OpenWeather {
print(jsonString)
let jsonData = jsonString.data(using: .utf8)!

if let openWeather = try? newJSONDecoder().decode(OWeather.self, from: jsonData) {
if var openWeather = try? newJSONDecoder().decode(OWeather.self, from: jsonData) {
openWeather.processTemperatures()

completion(.success(openWeather))
} else {
completion(.failure(.unknown))
Expand All @@ -178,7 +218,8 @@ struct OpenWeather {
print(jsonString)
let jsonData = jsonString.data(using: .utf8)!
do {
let openWeather = try newJSONDecoder().decode(OWeather.self, from: jsonData)
var openWeather = try newJSONDecoder().decode(OWeather.self, from: jsonData)
openWeather.processTemperatures()
completion(.success(openWeather))
} catch {
print("error : \(error.localizedDescription)")
Expand Down
2 changes: 1 addition & 1 deletion Aerial/Source/Views/Layers/TimerLayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class TimerLayer: AnimationTextLayer {

let dateComponentsFormatter = DateComponentsFormatter()
dateComponentsFormatter.calendar = calendar

if config!.showSeconds {
dateComponentsFormatter.allowedUnits = [.hour, .minute, .second]
dateComponentsFormatter.maximumUnitCount = 3
Expand Down
67 changes: 61 additions & 6 deletions Aerial/Source/Views/Layers/Weather/ConditionLayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class ConditionLayer: CALayer {

let tempWidth = addTemperature(at: imglayer.frame.width + 15)
addFeelsLike(at: imglayer.frame.width + 15 + (tempWidth / 2))
addWind(at: (imglayer.frame.width + 15 + tempWidth) / 2)

// Set the final size of that block
frame.size = CGSize(width: imglayer.frame.width + 15 + tempWidth, height: 75)
Expand Down Expand Up @@ -74,7 +75,12 @@ class ConditionLayer: CALayer {
func addTemperature(at: CGFloat) -> CGFloat {
// Make a vertically centered layer for t°
let temp = CAVCTextLayer()
temp.string = "\(condition!.main!.temp)°"

if PrefsInfo.weather.degree == .celsius {
temp.string = "\(condition!.main!.temp)°"
} else {
temp.string = "\(Int(condition!.main!.temp))°"
}

// Get something large first
temp.frame.size = CGSize(width: 100, height: 400)
Expand All @@ -91,19 +97,25 @@ class ConditionLayer: CALayer {

// We put the temperature at the right of the weather icon
temp.anchorPoint = CGPoint(x: 0, y: 0.5)
temp.position = CGPoint(x: at, y: 50)
temp.position = CGPoint(x: at, y: 64)

return rect.size.width
}

func addFeelsLike(at: CGFloat) {
// Make a vertically centered layer for t°
let feel = CAVCTextLayer()
feel.string = "(\(condition!.main!.feelsLike)°)"
if PrefsInfo.weather.degree == .celsius {
feel.string = "(\(condition!.main!.feelsLike)°)"
} else {
feel.string = "(\(Int(condition!.main!.feelsLike))°)"
}

feel.contentsScale = self.contentsScale

// Get something large first
feel.frame.size = CGSize(width: 100, height: 30)
(feel.font, feel.fontSize) = feel.makeFont(name: PrefsInfo.weather.fontName, size: PrefsInfo.weather.fontSize/2.5)
(feel.font, feel.fontSize) = feel.makeFont(name: PrefsInfo.weather.fontName, size: PrefsInfo.weather.fontSize/2.2)

// ReRect the temperature
let rect2 = feel.calculateRect(string: feel.string as! String, font: feel.font as! NSFont)
Expand All @@ -112,8 +124,49 @@ class ConditionLayer: CALayer {
self.addSublayer(feel)

// We put the temperature at the right of the weather icon
feel.anchorPoint = CGPoint(x: 0.5, y: 0)
feel.position = CGPoint(x: at, y: 0)
feel.anchorPoint = CGPoint(x: 0.5, y: 0.0)
feel.position = CGPoint(x: at, y: 14)
}

func addWind(at: CGFloat) {
guard let owind = condition?.wind else {
return
}

// Make a vertically centered layer for t°
let wind = CAVCTextLayer()
if PrefsInfo.weather.degree == .celsius {
wind.string = "\(owind.speed) km/s"
} else {
wind.string = "\(owind.speed) mph"
}

// Get something large first
wind.frame.size = CGSize(width: 100, height: 30)
(wind.font, wind.fontSize) = wind.makeFont(name: PrefsInfo.weather.fontName, size: PrefsInfo.weather.fontSize/2.2)

wind.contentsScale = self.contentsScale

// ReRect the temperature
let rect2 = wind.calculateRect(string: wind.string as! String, font: wind.font as! NSFont)
wind.frame = rect2
wind.contentsScale = self.contentsScale
self.addSublayer(wind)

// We put the temperature at the right of the weather icon
wind.anchorPoint = CGPoint(x: 0.5, y: 0.0)
wind.position = CGPoint(x: at + 10, y: -15)

let imglayer = WindDirectionLayer(direction: 225)
imglayer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
imglayer.position = CGPoint(x: at - (rect2.width/2) - 5, y: 1)
imglayer.contentsScale = self.contentsScale

// anchorPoint = CGPoint(x: 0.5, y: 0.5)
print("owind : \(owind.deg)")
imglayer.transform = CATransform3DMakeRotation(CGFloat((180 + owind.deg)) / 180.0 * .pi, 0.0, 0.0, -1.0)

self.addSublayer(imglayer)
}

func downloadImage(from url: URL) {
Expand All @@ -138,6 +191,8 @@ class ConditionLayer: CALayer {
self.addSublayer(imglayer)

let tempWidth = self.addTemperature(at: imglayer.frame.width + 15)
self.addFeelsLike(at: imglayer.frame.width + 15 + (tempWidth / 2))
self.addWind(at: (imglayer.frame.width + 15 + tempWidth) / 2)

// Set the final size
self.frame.size = CGSize(width: imglayer.frame.width + 15 + tempWidth, height: 75)
Expand Down
28 changes: 28 additions & 0 deletions Aerial/Source/Views/Layers/Weather/WindDirectionLayer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// WindDirectionLayer.swift
// Aerial
//
// Created by Guillaume Louel on 05/03/2021.
// Copyright © 2021 Guillaume Louel. All rights reserved.
//

import Foundation
import AVKit

class WindDirectionLayer: CALayer {
init(direction: CGFloat) {
super.init()
let imagePath = Bundle(for: PanelWindowController.self).path(
forResource: "location.north",
ofType: "pdf")

let img = NSImage(contentsOfFile: imagePath!)
frame.size.height = img!.size.height / 8
frame.size.width = img!.size.width / 8
contents = img
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Binary file added Resources/Weather/location.north.pdf
Binary file not shown.

0 comments on commit 2e2c307

Please sign in to comment.