Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: Add MenuBar support for macOS #23

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
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
332 changes: 312 additions & 20 deletions wled-native.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1600"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "E15C19CD2CA1CABD00431441"
BuildableName = "wled-native-osx.app"
BlueprintName = "wled-native-osx"
ReferencedContainer = "container:wled-native.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "E15C19CD2CA1CABD00431441"
BuildableName = "wled-native-osx.app"
BlueprintName = "wled-native-osx"
ReferencedContainer = "container:wled-native.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "E15C19CD2CA1CABD00431441"
BuildableName = "wled-native-osx.app"
BlueprintName = "wled-native-osx"
ReferencedContainer = "container:wled-native.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@

import Foundation
import CoreData

struct WLEDChangeStateRequest: WLEDRequest {
let state: WLEDStateChange
let context: NSManagedObjectContext
}
5 changes: 1 addition & 4 deletions wled-native/Model/DeviceApi/Request/WLEDRefreshRequest.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@

import Foundation
import CoreData

struct WLEDRefreshRequest: WLEDRequest {
let context: NSManagedObjectContext
}
struct WLEDRefreshRequest: WLEDRequest { }
4 changes: 1 addition & 3 deletions wled-native/Model/DeviceApi/Request/WLEDRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,4 @@
import Foundation
import CoreData

protocol WLEDRequest {
var context: NSManagedObjectContext { get }
}
protocol WLEDRequest: Sendable { }
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@

import Foundation
import CoreData

struct WLEDSoftwareUpdateRequest: WLEDRequest {
let context: NSManagedObjectContext
let binaryFile: URL
let onCompletion: () -> ()
let onFailure: () -> ()
let onCompletion: @MainActor () -> ()
let onFailure: @MainActor () -> ()
}
2 changes: 1 addition & 1 deletion wled-native/Persistence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import CoreData
struct PersistenceController {
static let shared = PersistenceController()

static var preview: PersistenceController = {
static let preview: PersistenceController = {
let result = PersistenceController(inMemory: true)
let viewContext = result.container.viewContext
for i in 0..<10 {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
13 changes: 8 additions & 5 deletions wled-native/Service/DeviceApi/DeviceExtensions.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@

import Foundation

extension Device {
var requestManager: WLEDRequestManager {
get {
return DeviceStateFactory.shared.getStateForDevice(self).getRequestManager(device: self)
}
extension Device: @unchecked Sendable {

func refresh() async {
await self.getRequestManager().addRequest(WLEDRefreshRequest())
}

func getRequestManager() async -> WLEDRequestManager {
await WLEDRequestManagerProvider.shared.getRequestManager(device: self)
}

func getColor(state: WledState) -> Int64 {
Expand Down
84 changes: 47 additions & 37 deletions wled-native/Service/DeviceApi/WLEDJsonApiHandler.swift
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
import Foundation
import Combine
import CoreData

class WLEDJsonApiHandler : WLEDRequestHandler {
let device: Device
var urlSession: URLSession?

init(device: Device) {
self.device = device
}
final class WLEDJsonApiHandler: WLEDRequestHandler {

func getUrlSession() -> URLSession {
if (urlSession != nil) {
return urlSession!
}

let device: Device
let urlSession: URLSession = {
let sessionConfig = URLSessionConfiguration.default
sessionConfig.timeoutIntervalForRequest = 8
sessionConfig.timeoutIntervalForResource = 18
sessionConfig.waitsForConnectivity = true
sessionConfig.httpMaximumConnectionsPerHost = 1
urlSession = URLSession(configuration: sessionConfig)
return urlSession!
return URLSession(configuration: sessionConfig)
}()

init(device: Device) {
self.device = device
}

func processRequest(_ request: WLEDRequest) async {
Expand All @@ -45,23 +40,23 @@ class WLEDJsonApiHandler : WLEDRequestHandler {
print("Reading api at: \(url)")

do {
let (data, response) = try await getUrlSession().data(from: url)
let (data, response) = try await urlSession.data(from: url)

guard let httpResponse = response as? HTTPURLResponse else {
print("Invalid httpResponse in update")
self.updateDeviceOnError(context: request.context)
self.updateDeviceOnError()
return
}
guard (200...299).contains(httpResponse.statusCode) else {
print("Error with the response in update, unexpected status code: \(httpResponse)")
self.updateDeviceOnError(context: request.context)
self.updateDeviceOnError()
return
}

self.onResultFetchDataSuccess(context: request.context, data: data)
await self.onResultFetchDataSuccess(data: data)
} catch {
print("Error with fetching device: \(error)")
self.updateDeviceOnError(context: request.context)
self.updateDeviceOnError()
return
}
}
Expand All @@ -70,7 +65,7 @@ class WLEDJsonApiHandler : WLEDRequestHandler {
let url = getJsonApiUrl(path: "json/state")
guard let url else {
print("Can't post to device, url nil")
self.updateDeviceOnError(context: request.context)
self.updateDeviceOnError()
return
}
print("Posting api at: \(url)")
Expand All @@ -83,28 +78,28 @@ class WLEDJsonApiHandler : WLEDRequestHandler {
urlRequest.httpBody = jsonData

do {
let (data, response) = try await getUrlSession().data(for: urlRequest)
let (data, response) = try await urlSession.data(for: urlRequest)

guard let httpResponse = response as? HTTPURLResponse else {
print("Invalid httpResponse in post")
self.updateDeviceOnError(context: request.context)
self.updateDeviceOnError()
return
}
guard (200...299).contains(httpResponse.statusCode) else {
print("Error with the response in post, unexpected status code: \(httpResponse)")
self.updateDeviceOnError(context: request.context)
self.updateDeviceOnError()
return
}

self.onSuccessPostJson(context: request.context, data: data)
self.onSuccessPostJson(data: data)
} catch {
print("Error with fetching device after post: \(error)")
self.updateDeviceOnError(context: request.context)
self.updateDeviceOnError()
return
}
} catch {
print(error)
self.updateDeviceOnError(context: request.context)
self.updateDeviceOnError()
}
}

Expand All @@ -130,7 +125,7 @@ class WLEDJsonApiHandler : WLEDRequestHandler {
try body.append(Data(contentsOf: request.binaryFile))
} catch {
print("Error with reading binary file: \(error)")
self.updateDeviceOnError(context: request.context)
self.updateDeviceOnError()
return
}
body.append("\r\n".data(using: .utf8)!)
Expand All @@ -145,26 +140,30 @@ class WLEDJsonApiHandler : WLEDRequestHandler {

guard let httpResponse = response as? HTTPURLResponse else {
print("Invalid httpResponse in post for update install")
request.onFailure()
await request.onFailure()
return
}
guard (200...299).contains(httpResponse.statusCode) else {
print("Error with the response in update install, unexpected status code: \(httpResponse)")
request.onFailure()
await request.onFailure()
return
}

request.onCompletion()
await request.onCompletion()
} catch {
print("Error with installing device update: \(error)")
request.onFailure()
await request.onFailure()
return
}
}


private func updateDeviceOnError(context: NSManagedObjectContext) {
private func updateDeviceOnError() {

print("Device \(device.address ?? "unknown") could not be updated. Marking as offline.")
guard let context = device.managedObjectContext else {
return
}

context.performAndWait {
device.isOnline = false
Expand All @@ -190,8 +189,15 @@ class WLEDJsonApiHandler : WLEDRequestHandler {
return URL(string: urlString)
}

private func onResultFetchDataSuccess(context: NSManagedObjectContext, data: Data?) {
guard let data else { return }
@MainActor
private func onResultFetchDataSuccess(data: Data?) {
guard let context = device.managedObjectContext else {
return
}
guard let data else {
return
}

context.performAndWait {
do {
let deviceStateInfo = try JSONDecoder().decode(DeviceStateInfo.self, from: data)
Expand Down Expand Up @@ -232,12 +238,16 @@ class WLEDJsonApiHandler : WLEDRequestHandler {
}
} catch {
print(error)
updateDeviceOnError(context: context)
updateDeviceOnError()
}
}
}

private func onSuccessPostJson(context: NSManagedObjectContext, data: Data?) {
private func onSuccessPostJson(data: Data?) {
guard let context = device.managedObjectContext else {
return
}

guard let data else { return }
context.performAndWait {
do {
Expand All @@ -256,7 +266,7 @@ class WLEDJsonApiHandler : WLEDRequestHandler {
}
} catch {
print(error)
updateDeviceOnError(context: context)
updateDeviceOnError()
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions wled-native/Service/DeviceApi/WLEDRequestHandler.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@

import Foundation

protocol WLEDRequestHandler {
var device: Device { get }
protocol WLEDRequestHandler: Sendable {
func processRequest(_ request: WLEDRequest) async
}
Loading