- add low battery notification with option to select battery level (disabled/3%/5%/10%/15%/20%/30%/40%/50%)

This commit is contained in:
Serhiy Mytrovtsiy
2020-07-15 22:18:24 +02:00
parent eaeeb476ac
commit 706e8219ce
7 changed files with 152 additions and 10 deletions

View File

@@ -27,7 +27,7 @@ struct Battery_Usage: value_t {
var temperature: Double = 0
var ACwatts: Int = 0
var ACstatus: Bool = true
var ACstatus: Bool = false
var timeToEmpty: Int = 0
var timeToCharge: Int = 0
@@ -42,12 +42,18 @@ struct Battery_Usage: value_t {
public class Battery: Module {
private var usageReader: UsageReader? = nil
private let popupView: Popup = Popup()
private var settingsView: Settings
private let store: UnsafePointer<Store>
public init(_ store: UnsafePointer<Store>) {
self.store = store
self.settingsView = Settings("Battery", store: store)
super.init(
store: store,
popup: self.popupView,
settings: nil
settings: self.settingsView
)
guard self.available else { return }
@@ -76,6 +82,7 @@ public class Battery: Module {
return
}
self.checkNotification(value: value!)
self.popupView.usageCallback(value!)
if let widget = self.widget as? Mini {
widget.setValue(abs(value!.level), sufix: "%")
@@ -88,4 +95,24 @@ public class Battery: Module {
)
}
}
private func checkNotification(value: Battery_Usage) {
let level = self.store.pointee.string(key: "\(self.config.name)_lowLevelNotification", defaultValue: "0.15")
if level == "Disabled" {
return
}
var subtitle = "\((Int(value.level*100)))% remaining"
if value.timeToEmpty != 0 {
subtitle += " (\(Double(value.timeToEmpty*60).printSecondsToHoursMinutesSeconds()))"
}
if let notificationLevel = Double(level), value.level <= notificationLevel {
showNotification(
title: "Low battery",
subtitle: subtitle,
id: "battery-level",
icon: NSImage(named: NSImage.Name("low-battery"))!
)
}
}
}

View File

@@ -0,0 +1,80 @@
//
// settings.swift
// Battery
//
// Created by Serhiy Mytrovtsiy on 15/07/2020.
// Using Swift 5.0.
// Running on macOS 10.15.
//
// Copyright © 2020 Serhiy Mytrovtsiy. All rights reserved.
//
import Cocoa
import StatsKit
import ModuleKit
import SystemConfiguration
internal class Settings: NSView, Settings_v {
public var callback: (() -> Void) = {}
private let title: String
private let store: UnsafePointer<Store>
private var button: NSPopUpButton?
private let levelsList: [String] = ["Disabled", "0.03", "0.05", "0.1", "0.15", "0.2", "0.25", "0.3", "0.4", "0.5"]
private var lowLevelNotification: String {
get {
return self.store.pointee.string(key: "\(self.title)_lowLevelNotification", defaultValue: "0.15")
}
}
public init(_ title: String, store: UnsafePointer<Store>) {
self.title = title
self.store = store
super.init(frame: CGRect(x: Constants.Settings.margin, y: Constants.Settings.margin, width: Constants.Settings.width - (Constants.Settings.margin*2), height: 0))
self.wantsLayer = true
self.canDrawConcurrently = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public func load(widget: widget_t) {
self.subviews.forEach{ $0.removeFromSuperview() }
let rowHeight: CGFloat = 30
let levels: [String] = self.levelsList.map { (v: String) -> String in
if let level = Double(v) {
return "\(Int(level*100))%"
}
return v
}
self.addSubview(SelectTitleRow(
frame: NSRect(
x:Constants.Settings.margin,
y: Constants.Settings.margin + (rowHeight + Constants.Settings.margin) * 0,
width: self.frame.width - (Constants.Settings.margin*2),
height: rowHeight
),
title: "Low level notification",
action: #selector(changeUpdateInterval),
items: levels,
selected: self.lowLevelNotification == "Disabled" ? self.lowLevelNotification : "\(Int((Double(self.lowLevelNotification) ?? 0)*100))%"
))
self.setFrameSize(NSSize(width: self.frame.width, height: 30 + (Constants.Settings.margin*2)))
}
@objc private func changeUpdateInterval(_ sender: NSMenuItem) {
if sender.title == "Disabled" {
store.pointee.set(key: "\(self.title)_lowLevelNotification", value: sender.title)
} else if let value = Double(sender.title.replacingOccurrences(of: "%", with: "")) {
store.pointee.set(key: "\(self.title)_lowLevelNotification", value: "\(value/100)")
}
}
}

View File

@@ -97,6 +97,7 @@
9ABFF912248BF39500C9041A /* Battery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9ABFF911248BF39500C9041A /* Battery.swift */; };
9ABFF914248C30A800C9041A /* popup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9ABFF913248C30A800C9041A /* popup.swift */; };
9AD33AC624BCD3EE007E8820 /* helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AD33AC524BCD3EE007E8820 /* helpers.swift */; };
9AD64FA224BF86C100419D59 /* settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AD64FA124BF86C100419D59 /* settings.swift */; };
9AE29ADC249A50350071B02D /* Sensors.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9AE29AD5249A50350071B02D /* Sensors.framework */; };
9AE29ADD249A50350071B02D /* Sensors.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9AE29AD5249A50350071B02D /* Sensors.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9AE29AE1249A50640071B02D /* ModuleKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9AABEADD243FB13500668CB0 /* ModuleKit.framework */; };
@@ -469,6 +470,7 @@
9ABFF911248BF39500C9041A /* Battery.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Battery.swift; sourceTree = "<group>"; };
9ABFF913248C30A800C9041A /* popup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = popup.swift; sourceTree = "<group>"; };
9AD33AC524BCD3EE007E8820 /* helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = helpers.swift; sourceTree = "<group>"; };
9AD64FA124BF86C100419D59 /* settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = settings.swift; sourceTree = "<group>"; };
9AE29AD5249A50350071B02D /* Sensors.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Sensors.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9AE29AEC249A50960071B02D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; name = Info.plist; path = Modules/Sensors/Info.plist; sourceTree = SOURCE_ROOT; };
9AE29AF1249A50CD0071B02D /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = main.swift; path = Modules/Sensors/main.swift; sourceTree = SOURCE_ROOT; };
@@ -778,6 +780,7 @@
9ABFF902248BEBD700C9041A /* main.swift */,
9ABFF90F248BEE7200C9041A /* readers.swift */,
9ABFF913248C30A800C9041A /* popup.swift */,
9AD64FA124BF86C100419D59 /* settings.swift */,
9ABFF8F9248BEBCB00C9041A /* Info.plist */,
9ABFF904248BEC0B00C9041A /* config.plist */,
);
@@ -1350,6 +1353,7 @@
files = (
9ABFF910248BEE7200C9041A /* readers.swift in Sources */,
9ABFF914248C30A800C9041A /* popup.swift in Sources */,
9AD64FA224BF86C100419D59 /* settings.swift in Sources */,
9ABFF903248BEBD700C9041A /* main.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "low-battery.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -67,14 +67,8 @@ extension AppDelegate {
}
if IsNewestVersion(currentVersion: prevVersion, latestVersion: currentVersion) {
let notification = NSUserNotification()
notification.identifier = "updated-from-\(prevVersion)-to-\(currentVersion)"
notification.title = "Successfully updated"
notification.subtitle = "Stats was updated to the v\(currentVersion)"
notification.soundName = NSUserNotificationDefaultSoundName
notification.hasActionButton = false
NSUserNotificationCenter.default.deliver(notification)
showNotification(title: "Successfully updated", subtitle: "Stats was updated to the v\(currentVersion)", id: "updated-from-\(prevVersion)-to-\(currentVersion)"
)
}
os_log(.debug, log: log, "Detected previous version %s. Current version (%s) set", prevVersion, currentVersion)

View File

@@ -767,3 +767,19 @@ public enum updateIntervals: updateInterval {
case never = "Never"
}
extension updateIntervals: CaseIterable {}
public func showNotification(title: String, subtitle: String, id: String = UUID().uuidString, icon: NSImage? = nil) {
let notification = NSUserNotification()
notification.identifier = id
notification.title = title
notification.subtitle = subtitle
notification.soundName = NSUserNotificationDefaultSoundName
notification.hasActionButton = false
if icon != nil {
notification.setValue(icon, forKey: "_identityImage")
}
NSUserNotificationCenter.default.deliver(notification)
}