diff --git a/Modules/Bluetooth/config.plist b/Modules/Bluetooth/config.plist
index e682d921..2639fe97 100644
--- a/Modules/Bluetooth/config.plist
+++ b/Modules/Bluetooth/config.plist
@@ -39,7 +39,7 @@
popup
notifications
-
+
diff --git a/Modules/Bluetooth/main.swift b/Modules/Bluetooth/main.swift
index b74fc476..240ed082 100644
--- a/Modules/Bluetooth/main.swift
+++ b/Modules/Bluetooth/main.swift
@@ -28,15 +28,14 @@ public struct BLEDevice: Codable {
var isPeripheralInitialized: Bool = false
var id: String {
- get {
- return self.uuid?.uuidString ?? self.address
- }
+ get { self.uuid?.uuidString ?? self.address }
}
var state: Bool {
- get {
- return Store.shared.bool(key: "ble_\(self.id)", defaultValue: false)
- }
+ get { Store.shared.bool(key: "ble_\(self.id)", defaultValue: false) }
+ }
+ var notificationThreshold: String {
+ Store.shared.string(key: "ble_\(self.id)_notification", defaultValue: "")
}
private enum CodingKeys: String, CodingKey {
@@ -80,11 +79,15 @@ public class Bluetooth: Module {
private var devicesReader: DevicesReader?
private let popupView: Popup = Popup()
private let settingsView: Settings = Settings()
+ private let notificationsView: Notifications
public init() {
+ self.notificationsView = Notifications(.bluetooth)
+
super.init(
popup: self.popupView,
- settings: self.settingsView
+ settings: self.settingsView,
+ notifications: self.notificationsView
)
guard self.available else { return }
@@ -106,6 +109,7 @@ public class Bluetooth: Module {
DispatchQueue.main.async(execute: {
self.popupView.batteryCallback(active)
self.settingsView.setList(active)
+ self.notificationsView.callback(active)
})
var list: [Stack_t] = []
diff --git a/Modules/Bluetooth/notifications.swift b/Modules/Bluetooth/notifications.swift
new file mode 100644
index 00000000..dce1aab9
--- /dev/null
+++ b/Modules/Bluetooth/notifications.swift
@@ -0,0 +1,84 @@
+//
+// notifications.swift
+// Bluetooth
+//
+// Created by Serhiy Mytrovtsiy on 24/06/2024
+// Using Swift 5.0
+// Running on macOS 14.5
+//
+// Copyright © 2024 Serhiy Mytrovtsiy. All rights reserved.
+//
+
+import Cocoa
+import Kit
+
+class Notifications: NotificationsWrapper {
+ private var list: [String: Bool] = [:]
+
+ private let emptyView: EmptyView = EmptyView(msg: localizedString("No Bluetooth devices are available"))
+ private var section: PreferencesSection = PreferencesSection()
+
+ public init(_ module: ModuleType) {
+ super.init(module)
+
+ self.addArrangedSubview(self.emptyView)
+ self.addArrangedSubview(self.section)
+ self.section.isHidden = true
+
+ self.addArrangedSubview(NSView())
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ internal func callback(_ list: [BLEDevice]) {
+ if self.list.count != list.count && !self.list.isEmpty {
+ self.section.removeFromSuperview()
+ self.section = PreferencesSection()
+ self.addArrangedSubview(self.section)
+ self.list = [:]
+ }
+
+ if list.isEmpty && self.emptyView.isHidden {
+ self.emptyView.isHidden = false
+ self.section.isHidden = true
+ return
+ } else if !list.isEmpty && !self.emptyView.isHidden {
+ self.emptyView.isHidden = true
+ self.section.isHidden = false
+ }
+
+ list.forEach { (d: BLEDevice) in
+ if self.list[d.id] == nil {
+ let btn = selectView(
+ action: #selector(self.changeSensorNotificaion),
+ items: notificationLevels,
+ selected: d.notificationThreshold
+ )
+ btn.identifier = NSUserInterfaceItemIdentifier(rawValue: "\(d.uuid?.uuidString ?? d.address)")
+ section.add(PreferencesRow(d.name, component: btn))
+ self.list[d.id] = true
+ }
+ }
+
+ let devices = list.filter({ !$0.notificationThreshold.isEmpty })
+ let title = localizedString("Bluetooth threshold")
+
+ for d in devices {
+ if let threshold = Double(d.notificationThreshold) {
+ for l in d.batteryLevel {
+ let subtitle = localizedString("\(localizedString(d.name)): \(l.value)%")
+ if let value = Double(l.value) {
+ self.checkDouble(id: d.id, value: value/100, threshold: threshold, title: title, subtitle: subtitle, less: true)
+ }
+ }
+ }
+ }
+ }
+
+ @objc private func changeSensorNotificaion(_ sender: NSMenuItem) {
+ guard let id = sender.identifier, let key = sender.representedObject as? String else { return }
+ Store.shared.set(key: "ble_\(id.rawValue)_notification", value: key)
+ }
+}
diff --git a/Stats.xcodeproj/project.pbxproj b/Stats.xcodeproj/project.pbxproj
index 2764bb60..0010518f 100644
--- a/Stats.xcodeproj/project.pbxproj
+++ b/Stats.xcodeproj/project.pbxproj
@@ -45,6 +45,7 @@
5C4E8BE92B71031A00F148B6 /* Kit.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C4E8BE82B7102A700F148B6 /* Kit.h */; settings = {ATTRIBUTES = (Private, ); }; };
5C5647F82A3F6B100098FFE9 /* Telemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C5647F72A3F6B100098FFE9 /* Telemetry.swift */; };
5C621D822B4770D6004ED7AF /* process.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C621D812B4770D6004ED7AF /* process.swift */; };
+ 5C7C1DF42C29A3A00060387D /* notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7C1DF32C29A3A00060387D /* notifications.swift */; };
5C8E001029269C7F0027C75A /* protocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFE493829265055000F2856 /* protocol.swift */; };
5CA518382B543FE600EBCCC4 /* portal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CA518372B543FE600EBCCC4 /* portal.swift */; };
5CD342F42B2F2FB700225631 /* notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CD342F32B2F2FB700225631 /* notifications.swift */; };
@@ -446,6 +447,7 @@
5C4E8BE82B7102A700F148B6 /* Kit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Kit.h; sourceTree = ""; };
5C5647F72A3F6B100098FFE9 /* Telemetry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Telemetry.swift; sourceTree = ""; };
5C621D812B4770D6004ED7AF /* process.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = process.swift; sourceTree = ""; };
+ 5C7C1DF32C29A3A00060387D /* notifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = notifications.swift; sourceTree = ""; };
5C9F90A02A76B30500D41748 /* et */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = et; path = et.lproj/Localizable.strings; sourceTree = ""; };
5CA518372B543FE600EBCCC4 /* portal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = portal.swift; sourceTree = ""; };
5CD342F32B2F2FB700225631 /* notifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = notifications.swift; sourceTree = ""; };
@@ -802,6 +804,7 @@
9A11AB35266FD9F4000C1C05 /* readers.swift */,
9A94B81E26822DE0001F4F2B /* popup.swift */,
9A8B923C2696445C00FD6D83 /* settings.swift */,
+ 5C7C1DF32C29A3A00060387D /* notifications.swift */,
9A11AAD2266FD77F000C1C05 /* Info.plist */,
9A11AB25266FD828000C1C05 /* config.plist */,
);
@@ -1532,7 +1535,7 @@
New,
);
LastSwiftUpdateCheck = 1410;
- LastUpgradeCheck = 1530;
+ LastUpgradeCheck = 1540;
ORGANIZATIONNAME = "Serhiy Mytrovtsiy";
TargetAttributes = {
5C22299C29CCB3C400F00E69 = {
@@ -1820,6 +1823,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 5C7C1DF42C29A3A00060387D /* notifications.swift in Sources */,
9A11AB36266FD9F4000C1C05 /* readers.swift in Sources */,
9A94B81F26822DE0001F4F2B /* popup.swift in Sources */,
9A8B923D2696445C00FD6D83 /* settings.swift in Sources */,
diff --git a/Stats.xcodeproj/xcshareddata/xcschemes/SMC.xcscheme b/Stats.xcodeproj/xcshareddata/xcschemes/SMC.xcscheme
index 7effd0f0..57bdfb75 100644
--- a/Stats.xcodeproj/xcshareddata/xcschemes/SMC.xcscheme
+++ b/Stats.xcodeproj/xcshareddata/xcschemes/SMC.xcscheme
@@ -1,6 +1,6 @@