I am attempting to add a feature to macos_ui that allows the user to launch the native macOS color picker and stream back their color selections via EventChannel
.
I am able to launch the picker (Cocoa's NSColorPanel
), but the color selection does not get streamed back. When I run the example application via XCode, I can see that the color selections are registered, but they do not seem to be streamed back to Flutter through the EventChannel
. What is the proper way to handle this? Is it even possible to stream these events back to Flutter, given that they take place in a native macOS view?
Here is the Swift code I have so far:
MacosUIPlugin.swift
import Cocoa
import FlutterMacOS
public class MacOSUiPlugin: NSObject, FlutterPlugin, FlutterStreamHandler {
private let colorPanelProvider: ColorPanelProvider
private var eventSink: FlutterEventSink?
init(colorPanelProvider: ColorPanelProvider) {
self.colorPanelProvider = colorPanelProvider
super.init()
}
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(
name: "dev.groovinchip.macos_ui",
binaryMessenger: registrar.messenger)
let colorSelectionChannel = FlutterEventChannel(
name: "dev.groovinchip.macos_ui/color_panel",
binaryMessenger: registrar.messenger)
let colorPanelProvider = ColorPanelProvider()
let instance = MacOSUiPlugin(colorPanelProvider: colorPanelProvider)
colorSelectionChannel.setStreamHandler(instance)
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "color_panel":
colorPanelProvider.openPanel()
result(true)
default:
result(FlutterMethodNotImplemented)
}
}
public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
print("listening to MacosUIPluginEvents")
eventSink = events
//colorPanelProvider.startStream()
return nil
}
public func onCancel(withArguments arguments: Any?) -> FlutterError? {
eventSink = nil
return nil
}
}
extension NSColor {
var hexString: String {
let red = Int(round(self.redComponent * 0xFF))
let green = Int(round(self.greenComponent * 0xFF))
let blue = Int(round(self.blueComponent * 0xFF))
let hexString = NSString(format: "#%02X%02X%02X", red, green, blue)
return hexString as String
}
}
ColorPanelProvider.swift
import FlutterMacOS
class ColorPanelProvider: NSObject, FlutterStreamHandler {
var eventSink: FlutterEventSink?
let colorPanel = NSColorPanel.shared
func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
print("listening to ColorPanelProvider events")
eventSink = events
return nil
}
func openPanel() {
colorPanel.setTarget(self)
colorPanel.setAction(#selector(startStream))
colorPanel.makeKeyAndOrderFront(self)
colorPanel.isContinuous = true
startStream()
}
@objc private func currentColor() -> String {
print("currentColor: \(colorPanel.color.asFlutterHexString)")
return colorPanel.color.asFlutterHexString
}
@objc public func startStream() {
print("starting ColorPanelProvider stream")
NotificationCenter.default.addObserver(
self,
selector: #selector(currentColor),
name: NSColorPanel.colorDidChangeNotification,
object: colorPanel)
eventSink?(currentColor())
}
func onCancel(withArguments arguments: Any?) -> FlutterError? {
eventSink = nil
return nil
}
}
extension NSColor {
var asFlutterHexString: String {
let red = Int(round(self.redComponent * 0xFF))
let green = Int(round(self.greenComponent * 0xFF))
let blue = Int(round(self.blueComponent * 0xFF))
let hexString = NSString(format: "#%02X%02X%02X", red, green, blue)
return hexString.replacingOccurrences(of: "#", with: "0xFF") as String
}
}