Closed SENTINELITE closed 9 months ago
At the time your delegate is created the shared plugin hasn't actually been initialized. So trying to get the global settings is making a request through StreamDeckPlugin.shared
which doesn't exist yet.
The Settings API is stateless because events include the current settings when called, however as you've run into that doesn't work very well for global settings. I want to rework that API with property wrappers to make accessing settings easier.
I did some initial work on fixing the global settings in the GlobalSettings
branch. There's now a GlobalSetting
property wrapper that works much the same way as the existing Environment
property wrapper does, but it writes changes back to the SD app.
If you've got some time to test let me know what you think. The example plugin is updated to show how it all works.
Hey, Emory!
I was just going to circle back to this! I'll give it a go in the next week or so, & report back!
I appreciate it!
A few observations.
I've set up my keys like so:
struct ForcedTitleGlobalKey: EnvironmentKey, GlobalSettingKey {
static let defaultValue: Bool = false
}
struct AccessibilityGlobalKey: EnvironmentKey, GlobalSettingKey {
static let defaultValue: Bool = false
}
& while this works, it seems a cumbersome if we have more than ~3 keys.
Ideally, I feel like a macro may better suit the direction of Swift.
@GlobalSettingKey
struct SDSSettings {
var isForcedTitleGlobal: Bool
var isAccessibilityGlobal: Bool
//...
}
With that being said, I don't see why didReceiveGlobalSettings()
on the PluginDelegate
would need to exist?
The whole thing is inspired (read: ripped off) from SwiftUI, and is definitely a verbose way to declare everything.
I haven't looked into macros much, but they do seem suited to generating the boilerplate for the default value struct and getter and setter extension.
As for didReceiveGlobalSettings()
, it will probably be removed, but it's still there while I work on the new API. That being said, there could be instances where being notified of a settings change at the plugin level might be useful, though nothing immediately comes to mind.
As an aside, you shouldn't need to declare both EnvironmentKey
and GlobalSettingKey
, unless there are cases where you want to use the same declarations for both temporary and persistent values.
Got a chance to test out macros, and I think I have a working implementation. Using an attached macro, while a bit cleaner, can't generate the properties in the GlobalSettings
extension and I couldn't find a good way around it. I changed tactics a bit and tried a freestanding macro instead.
extension GlobalSettings {
#globalSetting("count", defaultValue: 0, ofType: Int.self)
#globalSetting("color", defaultValue: "#FFF", ofType: String.self)
}
The macro generates both the struct and the property for the key path inside the extension. I'm fairly happy with the implementation with the exception of having to include the type. So far I haven't found a way to infer the type to put into the generated code without switching on literally every Swift type.
I've been working on the settings API again, and as part of that changed when the plugin is initialized. The initializer is now called after the rest of the plugin is set up, so calling evens from the init
should be safe now. This is on the main
branch for now and will be in the next release.
Hey, Emory! When trying to access the Plugin's global settings, it's failing when unwrapping the
StreamDeckPlugin.shared.uuid
.Error: