Skip to content

Commit

Permalink
Refactor displaying stats
Browse files Browse the repository at this point in the history
  • Loading branch information
marcingajda committed Apr 4, 2020
1 parent 9c394eb commit 01c50c3
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 85 deletions.
20 changes: 12 additions & 8 deletions Covid-19 Status.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@

/* Begin PBXBuildFile section */
D30A829024345C9F0023B9C3 /* RegionsMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = D30A828F24345C9F0023B9C3 /* RegionsMenu.swift */; };
D30B91F02433373E00E21774 /* showError.swift in Sources */ = {isa = PBXBuildFile; fileRef = D30B91EF2433373E00E21774 /* showError.swift */; };
D317DE6324356D3900BD100A /* distribution in Resources */ = {isa = PBXBuildFile; fileRef = D317DE6224356D3900BD100A /* distribution */; };
D317DE672436A5D000BD100A /* PFMoveApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = D317DE662436A5D000BD100A /* PFMoveApplication.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
D317DE6A2436A8A300BD100A /* MoveApplication.strings in Resources */ = {isa = PBXBuildFile; fileRef = D317DE692436A8A300BD100A /* MoveApplication.strings */; };
D317DE6F2436B05600BD100A /* StatsDisplay.swift in Sources */ = {isa = PBXBuildFile; fileRef = D317DE6E2436B05600BD100A /* StatsDisplay.swift */; };
D317DE712436C04400BD100A /* criticalError.swift in Sources */ = {isa = PBXBuildFile; fileRef = D317DE702436C04400BD100A /* criticalError.swift */; };
D3C1A3552427BF8900B69DCB /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3C1A3542427BF8900B69DCB /* AppDelegate.swift */; };
D3C1A3592427BF8B00B69DCB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D3C1A3582427BF8B00B69DCB /* Assets.xcassets */; };
D3C1A35C2427BF8B00B69DCB /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D3C1A35A2427BF8B00B69DCB /* Main.storyboard */; };
Expand All @@ -27,12 +28,13 @@

/* Begin PBXFileReference section */
D30A828F24345C9F0023B9C3 /* RegionsMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegionsMenu.swift; sourceTree = "<group>"; };
D30B91EF2433373E00E21774 /* showError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = showError.swift; sourceTree = "<group>"; };
D317DE6224356D3900BD100A /* distribution */ = {isa = PBXFileReference; lastKnownFileType = folder; path = distribution; sourceTree = "<group>"; };
D317DE652436A5CF00BD100A /* BridgingHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BridgingHeader.h; sourceTree = "<group>"; };
D317DE662436A5D000BD100A /* PFMoveApplication.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PFMoveApplication.m; sourceTree = "<group>"; };
D317DE682436A64200BD100A /* PFMoveApplication.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PFMoveApplication.h; sourceTree = "<group>"; };
D317DE692436A8A300BD100A /* MoveApplication.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = MoveApplication.strings; sourceTree = "<group>"; };
D317DE6E2436B05600BD100A /* StatsDisplay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsDisplay.swift; sourceTree = "<group>"; };
D317DE702436C04400BD100A /* criticalError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = criticalError.swift; sourceTree = "<group>"; };
D3C1A3512427BF8900B69DCB /* Covid-19 Status.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Covid-19 Status.app"; sourceTree = BUILT_PRODUCTS_DIR; };
D3C1A3542427BF8900B69DCB /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
D3C1A3582427BF8B00B69DCB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
Expand Down Expand Up @@ -127,14 +129,15 @@
isa = PBXGroup;
children = (
D317DE6B2436A97100BD100A /* vendors */,
D30B91EF2433373E00E21774 /* showError.swift */,
D3C1A371242AE35700B69DCB /* AboutViewController.swift */,
D3C1A3542427BF8900B69DCB /* AppDelegate.swift */,
D3C1A3662429904F00B69DCB /* Types.swift */,
D3C1A371242AE35700B69DCB /* AboutViewController.swift */,
D30A828F24345C9F0023B9C3 /* RegionsMenu.swift */,
D317DE6E2436B05600BD100A /* StatsDisplay.swift */,
D3C1A3682429908300B69DCB /* StatsFormatter.swift */,
D3C1A36A2429921800B69DCB /* fetchData.swift */,
D3C1A36D2429942200B69DCB /* Notificator.swift */,
D30A828F24345C9F0023B9C3 /* RegionsMenu.swift */,
D317DE702436C04400BD100A /* criticalError.swift */,
D3C1A36A2429921800B69DCB /* fetchData.swift */,
D3C1A3662429904F00B69DCB /* Types.swift */,
);
path = src;
sourceTree = "<group>";
Expand Down Expand Up @@ -240,12 +243,13 @@
D30A829024345C9F0023B9C3 /* RegionsMenu.swift in Sources */,
D3C1A36E2429942200B69DCB /* Notificator.swift in Sources */,
D317DE672436A5D000BD100A /* PFMoveApplication.m in Sources */,
D317DE6F2436B05600BD100A /* StatsDisplay.swift in Sources */,
D3C1A3692429908300B69DCB /* StatsFormatter.swift in Sources */,
D3C1A36B2429921800B69DCB /* fetchData.swift in Sources */,
D3C1A3672429904F00B69DCB /* Types.swift in Sources */,
D3C1A3552427BF8900B69DCB /* AppDelegate.swift in Sources */,
D30B91F02433373E00E21774 /* showError.swift in Sources */,
D3C1A372242AE35700B69DCB /* AboutViewController.swift in Sources */,
D317DE712436C04400BD100A /* criticalError.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
4 changes: 3 additions & 1 deletion Covid-19 Status/pl.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
Copyright © 2020 Marcin Gajda. All rights reserved."
*/

"COVID-19 (%@): Confirmed | Deaths | Recured" = "COVID-19 (%@): Przypadki | Zgony | Wyzdrowienia";
"COVID-19 Status" = "COVID-19 Status";
"COVID-19 (%@)\nConfirmed | Deaths | Recured" = "COVID-19 (%@)\nPrzypadki | Zgony | Wyzdrowienia";
"Today: +%@ confirmed +%@ deaths" = "Dzisiaj: +%@ przypadki +%@ zgony";
"version %@" = "wesja %@";
"Loading..." = "Ładowanie...";
"COVID-19 Status: Error" = "COVID-19 Status: Błąd";
"unknown cause" = "powód nieznany";
"An error occured" = "Wystąpił błąd";
Expand Down
8 changes: 4 additions & 4 deletions Covid-19 Status/src/AboutViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ class AboutViewController: NSViewController {
super.viewDidLoad()

guard let version = version else {
showError(text: "The app UI is broken (version)")
criticalError(message: "The app UI is broken (version)")
return
}

guard let sourceLink = sourceLink else {
showError(text: "The app UI is broken (source link)")
criticalError(message: "The app UI is broken (source link)")
return
}

Expand All @@ -45,12 +45,12 @@ class AboutViewController: NSViewController {

@IBAction func sourceLinkHandler(sender: NSClickGestureRecognizer) {
guard let link = sourceLink?.stringValue else {
showError(text: "Can't open the URL address.")
criticalError(message: "Can't open the URL address.")
return
}

guard let urlAddress = URL(string: link) else {
showError(text: "Can't open the URL address.")
criticalError(message: "Can't open the URL address.")
return
}

Expand Down
88 changes: 22 additions & 66 deletions Covid-19 Status/src/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
var lastCoronaStats: CoronaStats?
var timer: Timer?

var display: StatsDisplay = StatsDisplay()

@IBOutlet weak var menu: NSMenu?
@IBOutlet weak var regionsMenu: RegionsMenu?
@IBOutlet weak var retryMenuItem: NSMenuItem?
Expand Down Expand Up @@ -51,57 +53,15 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}) ?? lastCoronaStats.worldStats
}

func refreshView(stats: RegionStats) {
let formatter = StatsFormatter(stats: stats)

DispatchQueue.main.async {
guard let deltaMenuItem = self.deltaMenuItem else {
showError(text: "The 'deltaMenuItem' element does not exists")
return
}

guard let button = self.button else {
showError(text: "The 'button' element does not exists")
return
}

button.attributedTitle = formatter.getRegionStatus()
deltaMenuItem.title = formatter.getRegionDelta()
button.toolTip = formatter.getTooltip()
}
}

@IBAction func alertsSwitchHandler(_ sender: NSMenuItem) {
setAlertsEnabled(enabled: !alertsEnabled)
}

func showErrorState(message: String) {
DispatchQueue.main.async {
guard let deltaMenuItem = self.deltaMenuItem else {
showError(text: "The app UI is broken (delta menu item)")
NSApp.terminate(nil)
return
}

guard let button = self.button else {
showError(text: "The app UI is broken (button)")
NSApp.terminate(nil)
return
}

button.attributedTitle = menuBarTextFormatter(
label: NSLocalizedString("COVID-19 Status: Error", comment: "")
)
deltaMenuItem.title = message
button.toolTip = message
}
}

@objc func doUpdate() {
print("Updating data")
fetchData { coronaStats, error in
guard let coronaStats = coronaStats else {
self.showErrorState(message: error ?? NSLocalizedString("unknown cause", comment: ""))
self.display.showError(message: error)
self.retryMenuItem?.isHidden = false
return
}
Expand All @@ -119,58 +79,53 @@ class AppDelegate: NSObject, NSApplicationDelegate {
return
}

self.refreshView(stats: currentStats)
self.display.showStats(region: currentStats)
self.notificator.handle(stats: currentStats)
}
}

func applicationDidFinishLaunching(_ aNotification: Notification) {
PFMoveToApplicationsFolderIfNecessary()

let statusBar = NSStatusBar.system
statusBarItem = statusBar.statusItem(withLength: NSStatusItem.variableLength)
statusBarItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)

guard let statusBarItem = statusBarItem else {
showError(text: "The app UI is broken (status bar item)")
NSApp.terminate(nil)
criticalError(message: "The app UI is broken (status bar item)")
return
}

guard statusBarItem.button != nil else {
showError(text: "Menu bar item was not created. Try removing some menu bar items")
NSApp.terminate(nil)
guard let menu = menu else {
criticalError(message: "The app UI is broken (menu)")
return
}

guard let menu = menu else {
showError(text: "The app UI is broken (menu)")
NSApp.terminate(nil)
guard let regionsMenu = regionsMenu else {
criticalError(message: "The app UI is broken (regions menu)")
return
}

guard let regionsMenu = regionsMenu else {
showError(text: "The app UI is broken (regions menu)")
NSApp.terminate(nil)
guard let deltaMenuItem = deltaMenuItem else {
criticalError(message: "The app UI is broken (delta menu item)")
return
}

guard let button = statusBarItem.button else {
criticalError(message: "Menu bar item was not created. Try removing some menu bar items")
return
}

button = statusBarItem.button
statusBarItem.menu = menu
display.setComponents(statusItem: button, deltaItem: deltaMenuItem)

regionsMenu.onRegionChange { region in
self.currentRegion = region

guard let stats = self.getCurrentRegionStats() else {
return
}

self.refreshView(stats: stats)
self.display.showStats(region: stats)
}

regionsMenu.setCurrent(
region: settings.string(forKey: "country") ?? WORLD
)

regionsMenu.setCurrent(region: settings.string(forKey: "country") ?? WORLD)
setAlertsEnabled(enabled: settings.bool(forKey: "alerts"))

doUpdate()
Expand All @@ -196,14 +151,15 @@ class AppDelegate: NSObject, NSApplicationDelegate {
) as? NSWindowController

guard let aboutWindowController = aboutWindowController else {
showError(text: "The About window failed")
criticalError(message: "The About window failed", terminate: false)
return
}

aboutWindowController.showWindow(self)
}

@IBAction func retryHandler(_ sender: AnyObject) {
display.showLoading()
doUpdate()
}
}
2 changes: 1 addition & 1 deletion Covid-19 Status/src/RegionsMenu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class RegionsMenu: NSMenu {

@objc func changeRegionHandler(sender: NSMenuItem) {
guard let region = sender.representedObject as? String else {
showError(text: "Button returned not a string")
criticalError(message: "Button returned not a string")
return
}

Expand Down
52 changes: 52 additions & 0 deletions Covid-19 Status/src/StatsDisplay.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// StatsDisplay.swift
// Covid-19 Status
//
// Created by Marcin Gajda on 03/04/2020.
// Copyright © 2020 Marcin Gajda. All rights reserved.
//

import Foundation
import Cocoa

class StatsDisplay: NSObject {
var statusDisplay: NSStatusBarButton?
var deltaDisplay: NSMenuItem?

func setComponents(statusItem: NSStatusBarButton, deltaItem: NSMenuItem) {
statusDisplay = statusItem
deltaDisplay = deltaItem
}

func showStats(region: RegionStats) {
let formatter = StatsFormatter(stats: region)

DispatchQueue.main.async {
self.statusDisplay?.attributedTitle = formatter.getRegionStatus()
self.statusDisplay?.toolTip = formatter.getTooltip()
self.deltaDisplay?.title = formatter.getRegionDelta()
}
}

func showError(message: String?) {
let error = message ?? NSLocalizedString("unknown cause", comment: "")

DispatchQueue.main.async {
self.statusDisplay?.attributedTitle = menuBarTextFormatter(
label: NSLocalizedString("COVID-19 Status: Error", comment: "")
)
self.statusDisplay?.toolTip = error
self.deltaDisplay?.title = error
}
}

func showLoading() {
DispatchQueue.main.async {
self.statusDisplay?.attributedTitle = menuBarTextFormatter(
label: NSLocalizedString("Loading...", comment: "")
)
self.statusDisplay?.toolTip = NSLocalizedString("COVID-19 Status", comment: "")
self.deltaDisplay?.title = NSLocalizedString("Loading...", comment: "")
}
}
}
2 changes: 1 addition & 1 deletion Covid-19 Status/src/StatsFormatter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class StatsFormatter {
let countryName = NSLocalizedString(stats.country, comment: "")

return String(
format: NSLocalizedString("COVID-19 (%@): Confirmed | Deaths | Recured", comment: ""),
format: NSLocalizedString("COVID-19 (%@)\nConfirmed | Deaths | Recured", comment: ""),
countryName
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// showError.swift
// criticalError.swift
// Covid-19 Status
//
// Created by Marcin Gajda on 29/03/2020.
Expand All @@ -9,11 +9,15 @@
import Foundation
import Cocoa

func showError(text: String) {
func criticalError(message: String, terminate: Bool = true) {
let alert = NSAlert()
alert.messageText = NSLocalizedString("An error occured", comment: "")
alert.informativeText = text
alert.informativeText = message
alert.alertStyle = .critical
alert.addButton(withTitle: "OK")
alert.runModal()

if terminate {
NSApp.terminate(nil)
}
}
2 changes: 1 addition & 1 deletion Covid-19 Status/src/fetchData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ var API = "https://corona-stats.online?format=json&source=2"

func fetchData(completion: @escaping ((CoronaStats?, String?) -> Void)) {
guard let url = NSURL(string: API)?.absoluteURL else {
showError(text: "API address is not an URL")
criticalError(message: "API address is not an URL")
return
}

Expand Down

0 comments on commit 01c50c3

Please sign in to comment.