mirror of
https://github.com/morgan9e/macos-stats
synced 2026-04-15 00:34:08 +09:00
- add low battery notification with option to select battery level (disabled/3%/5%/10%/15%/20%/30%/40%/50%)
This commit is contained in:
@@ -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"))!
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
80
Modules/Battery/settings.swift
Normal file
80
Modules/Battery/settings.swift
Normal 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)")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
21
Stats/Supporting Files/Assets.xcassets/low-battery.imageset/Contents.json
vendored
Normal file
21
Stats/Supporting Files/Assets.xcassets/low-battery.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
Stats/Supporting Files/Assets.xcassets/low-battery.imageset/low-battery.png
vendored
Normal file
BIN
Stats/Supporting Files/Assets.xcassets/low-battery.imageset/low-battery.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user