Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions BoringNotchXPCHelper/BoringNotchXPCHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,105 @@ class BoringNotchXPCHelper: NSObject, BoringNotchXPCHelperProtocol {
}
reply(false)
}

// MARK: - Bluetooth Device Info
// Maps to the root object containing the SPBluetoothDataType
private struct SPBluetoothDataRoot: Decodable {
let bluetoothData: [SPBluetoothData]?

private enum CodingKeys: String, CodingKey {
case bluetoothData = "SPBluetoothDataType"
}
}

private struct SPBluetoothData: Decodable {
let deviceConnected: [SPBluetoothDataDevice]?
let deviceNotconnected: [SPBluetoothDataDevice]?

enum CodingKeys: String, CodingKey {
case deviceConnected = "device_connected"
case deviceNotconnected = "device_not_connected"
}
}

private struct SPBluetoothDataDevice: Decodable {
let name: String?
let info: SPBluetoothDataDeviceInfo?

init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let dict = try container.decode([String: SPBluetoothDataDeviceInfo].self)

guard let (key, value) = dict.first else {
throw DecodingError.dataCorrupted(
.init(codingPath: decoder.codingPath,
debugDescription: "Expected dictionary with a single key")
)
}

self.name = key
self.info = value
}
}

private struct SPBluetoothDataDeviceInfo: Decodable {
let adress: String?
// let deviceBatteryLevelMain: String // - not used
let minorType: String?
let productID: String?
let services: String?
let vendorID: String?

enum CodingKeys: String, CodingKey {
case adress = "device_adress"
case minorType = "device_minorType"
case productID = "device_productID"
case services = "device_services"
case vendorID = "device_vendorID"
}
}

@objc func getBluetoothDeviceMinorClass(with deviceName: String, with reply: @escaping (String?) -> Void) {
let task = Process()
let pipe = Pipe()

task.executableURL = URL(fileURLWithPath: "/usr/sbin/system_profiler")
task.arguments = ["-json", "SPBluetoothDataType"]
task.standardOutput = pipe

let fileHandle = pipe.fileHandleForReading

var data: Data?
do {
try task.run()
task.waitUntilExit() // Block until the shell exits
data = try fileHandle.readToEnd()
} catch {
reply(nil)
}

guard let data, data.isEmpty == false else {
reply(nil)
return
}

// Continue with your decoding logic
do {
let rootInfo = try JSONDecoder().decode(SPBluetoothDataRoot.self, from: data)

guard let deviceContainer = rootInfo.bluetoothData?.first,
let devices = deviceContainer.deviceConnected,
let device = devices.first(where: {$0.name == deviceName})
else {
reply(nil)
return
}

reply(device.info?.minorType?.lowercased().trimmingCharacters(in: .whitespacesAndNewlines))
} catch {
reply(nil)
}
}

// MARK: - Private helpers for DisplayServices / IOKit access
private func displayServicesGetBrightness(displayID: CGDirectDisplayID, out: inout Float) -> Bool {
Expand Down
1 change: 1 addition & 0 deletions BoringNotchXPCHelper/BoringNotchXPCHelperProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import Foundation
func isScreenBrightnessAvailable(with reply: @escaping (Bool) -> Void)
func currentScreenBrightness(with reply: @escaping (NSNumber?) -> Void)
func setScreenBrightness(_ value: Float, with reply: @escaping (Bool) -> Void)
func getBluetoothDeviceMinorClass(with deviceName: String, with reply: @escaping (String?) -> Void)
}

/*
Expand Down
33 changes: 33 additions & 0 deletions boringNotch.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@
B1F0A0022E60000100000001 /* BrightnessManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1F0A0012E60000100000001 /* BrightnessManager.swift */; };
B1F747F92EC7E94000F841DB /* LottieView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1F747F82EC7E94000F841DB /* LottieView.swift */; };
B1FEB4992C7686630066EBBC /* PanGesture.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1FEB4982C7686630066EBBC /* PanGesture.swift */; };
D9958EED2ED3BA190021100C /* SymbolPicker in Frameworks */ = {isa = PBXBuildFile; productRef = D9958EEC2ED3BA190021100C /* SymbolPicker */; };
D9958EEE2ED468050021100C /* IOBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9B69FAF2ECFC09E009BDE40 /* IOBluetooth.framework */; };
D9958EF02ED4680A0021100C /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9958EEF2ED4680A0021100C /* CoreBluetooth.framework */; };
D9B69FA32ECE8074009BDE40 /* BluetoothManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9B69FA22ECE8074009BDE40 /* BluetoothManager.swift */; };
F38DE6482D8243E7008B5C6D /* BatteryActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F38DE6472D8243E2008B5C6D /* BatteryActivityManager.swift */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -308,6 +312,9 @@
B1F0A0012E60000100000001 /* BrightnessManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrightnessManager.swift; sourceTree = "<group>"; };
B1F747F82EC7E94000F841DB /* LottieView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LottieView.swift; sourceTree = "<group>"; };
B1FEB4982C7686630066EBBC /* PanGesture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PanGesture.swift; sourceTree = "<group>"; };
D9958EEF2ED4680A0021100C /* CoreBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreBluetooth.framework; path = System/Library/Frameworks/CoreBluetooth.framework; sourceTree = SDKROOT; };
D9B69FA22ECE8074009BDE40 /* BluetoothManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BluetoothManager.swift; sourceTree = "<group>"; };
D9B69FAF2ECFC09E009BDE40 /* IOBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOBluetooth.framework; path = System/Library/Frameworks/IOBluetooth.framework; sourceTree = SDKROOT; };
F38DE6472D8243E2008B5C6D /* BatteryActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatteryActivityManager.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -340,8 +347,10 @@
files = (
111BEA5F2ED07A340079DD4E /* MacroVisionKit in Frameworks */,
9A987A102C73CA8D005CA465 /* Collections in Frameworks */,
D9958EF02ED4680A0021100C /* CoreBluetooth.framework in Frameworks */,
1194E8852EA57D23009C82D6 /* SkyLightWindow in Frameworks */,
112B0EBB2E30DD5000562D6C /* MediaRemoteAdapter.framework in Frameworks */,
D9958EEE2ED468050021100C /* IOBluetooth.framework in Frameworks */,
14D0321D2C68F3350096E6A1 /* Sparkle in Frameworks */,
111BEA6F2ED166E20079DD4E /* MacroVisionKit in Frameworks */,
11F748732EC9DA9300F841DB /* Lottie in Frameworks */,
Expand All @@ -351,6 +360,7 @@
B19016222CC15B3D00E3F12E /* Defaults in Frameworks */,
111BE95D2ECD71E10079DD4E /* AsyncXPCConnection in Frameworks */,
B1628B922CC260C0003D8DF3 /* SwiftUIIntrospect in Frameworks */,
D9958EED2ED3BA190021100C /* SymbolPicker in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -518,6 +528,7 @@
14C08BB52C8DE42D000F8AA0 /* CalendarManager.swift */,
B1F0A0012E60000100000001 /* BrightnessManager.swift */,
59D8C23B2E589FAA00147B33 /* VolumeManager.swift */,
D9B69FA22ECE8074009BDE40 /* BluetoothManager.swift */,
);
path = managers;
sourceTree = "<group>";
Expand Down Expand Up @@ -599,6 +610,8 @@
14D031EC2C689DB70096E6A1 /* Frameworks */ = {
isa = PBXGroup;
children = (
D9958EEF2ED4680A0021100C /* CoreBluetooth.framework */,
D9B69FAF2ECFC09E009BDE40 /* IOBluetooth.framework */,
14D031EF2C689DC00096E6A1 /* ApplicationServices.framework */,
14D031ED2C689DB70096E6A1 /* IOKit.framework */,
112B0EBA2E30DD5000562D6C /* MediaRemoteAdapter.framework */,
Expand Down Expand Up @@ -814,6 +827,7 @@
111BEA502ECFBF7F0079DD4E /* MacroVisionKit */,
111BEA5E2ED07A340079DD4E /* MacroVisionKit */,
111BEA6E2ED166E20079DD4E /* MacroVisionKit */,
D9958EEC2ED3BA190021100C /* SymbolPicker */,
);
productName = dynamicNotch;
productReference = 14CEF4122C5CAED300855D72 /* boringNotch.app */;
Expand Down Expand Up @@ -859,6 +873,7 @@
11F748712EC9DA9300F841DB /* XCRemoteSwiftPackageReference "lottie-spm" */,
111BE95B2ECD71E10079DD4E /* XCRemoteSwiftPackageReference "AsyncXPCConnection" */,
111BEA6D2ED166E20079DD4E /* XCRemoteSwiftPackageReference "MacroVisionKit" */,
D9958EEB2ED3BA190021100C /* XCRemoteSwiftPackageReference "SymbolPicker" */,
);
productRefGroup = 14CEF4132C5CAED300855D72 /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -941,6 +956,7 @@
B1C974342C642B6D0000E707 /* MarqueeTextView.swift in Sources */,
14288DE82C6E01C800B9F80C /* ProgressIndicator.swift in Sources */,
1113ABC52E80E27000EC13B2 /* ShelfItemView.swift in Sources */,
D9B69FA32ECE8074009BDE40 /* BluetoothManager.swift in Sources */,
1113ABC62E80E27000EC13B2 /* ShelfPersistenceService.swift in Sources */,
1113ABC82E80E27000EC13B2 /* ShelfItem.swift in Sources */,
1113ABCA2E80E27000EC13B2 /* ShelfSelectionModel.swift in Sources */,
Expand Down Expand Up @@ -1239,6 +1255,8 @@
INFOPLIST_KEY_LSBackgroundOnly = NO;
INFOPLIST_KEY_LSUIElement = YES;
INFOPLIST_KEY_NSAppleEventsUsageDescription = "This app uses AppleEvents to control music";
INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "This app monitors Bluetooth device connections";
INFOPLIST_KEY_NSBluetoothPeripheralUsageDescription = "This app monitors Bluetooth device connections";
INFOPLIST_KEY_NSCalendarsUsageDescription = "This app uses the calendar to display your calendar events";
INFOPLIST_KEY_NSCameraUsageDescription = "This app uses the camera to display a live camera view";
INFOPLIST_KEY_NSHumanReadableCopyright = "";
Expand Down Expand Up @@ -1292,6 +1310,8 @@
INFOPLIST_KEY_LSBackgroundOnly = NO;
INFOPLIST_KEY_LSUIElement = YES;
INFOPLIST_KEY_NSAppleEventsUsageDescription = "This app uses AppleEvents to control music";
INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "This app monitors Bluetooth device connections";
INFOPLIST_KEY_NSBluetoothPeripheralUsageDescription = "This app monitors Bluetooth device connections";
INFOPLIST_KEY_NSCalendarsUsageDescription = "This app uses the calendar to display your calendar events";
INFOPLIST_KEY_NSCameraUsageDescription = "This app uses the camera to display a live camera view";
INFOPLIST_KEY_NSHumanReadableCopyright = "";
Expand Down Expand Up @@ -1436,6 +1456,14 @@
minimumVersion = 9.0.2;
};
};
D9958EEB2ED3BA190021100C /* XCRemoteSwiftPackageReference "SymbolPicker" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/xnth97/SymbolPicker.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.6.2;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
Expand Down Expand Up @@ -1497,6 +1525,11 @@
package = B19016202CC15B3D00E3F12E /* XCRemoteSwiftPackageReference "Defaults" */;
productName = Defaults;
};
D9958EEC2ED3BA190021100C /* SymbolPicker */ = {
isa = XCSwiftPackageProductDependency;
package = D9958EEB2ED3BA190021100C /* XCRemoteSwiftPackageReference "SymbolPicker" */;
productName = SymbolPicker;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 14CEF40A2C5CAED200855D72 /* Project object */;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions boringNotch/Assets.xcassets/bluetooth.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "baseline_bluetooth_black_36pt_1x.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "baseline_bluetooth_black_36pt_2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "baseline_bluetooth_black_36pt_3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "baseline_settings_bluetooth_black_36pt_1x.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "baseline_settings_bluetooth_black_36pt_2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "baseline_settings_bluetooth_black_36pt_3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions boringNotch/Assets.xcassets/bluetooth.slash.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "baseline_bluetooth_disabled_black_36pt_1x.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "baseline_bluetooth_disabled_black_36pt_2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "baseline_bluetooth_disabled_black_36pt_3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions boringNotch/BoringViewCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ enum SneakContentType {
case mic
case battery
case download
case bluetooth
}

struct sneakPeek {
Expand Down Expand Up @@ -59,6 +60,7 @@ class BoringViewCoordinator: ObservableObject {
@AppStorage("firstLaunch") var firstLaunch: Bool = true
@AppStorage("showWhatsNew") var showWhatsNew: Bool = true
@AppStorage("musicLiveActivityEnabled") var musicLiveActivityEnabled: Bool = true
@AppStorage("bluetoothLiveActivityEnabled") var bluetoothLiveActivityEnabled: Bool = false
@AppStorage("currentMicStatus") var currentMicStatus: Bool = true

@AppStorage("alwaysShowTabs") var alwaysShowTabs: Bool = true {
Expand Down
Loading