fix: ControlSchema tolerate missing options field (Filler etc)
This commit is contained in:
parent
5ba2ae163b
commit
c72a018764
@ -80,11 +80,13 @@ struct MenuControl: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private func menuItemView(_ item: MenuItemSchema, depth: Int) -> some View {
|
private func menuItemView(_ item: MenuItemSchema, depth: Int) -> AnyView {
|
||||||
let hasChildren = !(item.submenu?.isEmpty ?? true)
|
let hasChildren = !(item.submenu?.isEmpty ?? true)
|
||||||
let isExpanded = expandedItems.contains(item.name)
|
let isExpanded = expandedItems.contains(item.name)
|
||||||
let isSelected = selectedItem == item.name
|
let isSelected = selectedItem == item.name
|
||||||
|
|
||||||
|
return AnyView(
|
||||||
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
Button(action: { handleMenuClick(item, hasChildren: hasChildren) }) {
|
Button(action: { handleMenuClick(item, hasChildren: hasChildren) }) {
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: 8) {
|
||||||
if let icon = item.icon {
|
if let icon = item.icon {
|
||||||
@ -118,6 +120,8 @@ struct MenuControl: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private func handleMenuClick(_ item: MenuItemSchema, hasChildren: Bool) {
|
private func handleMenuClick(_ item: MenuItemSchema, hasChildren: Bool) {
|
||||||
if hasChildren {
|
if hasChildren {
|
||||||
@ -173,7 +177,11 @@ struct PopupWindowControl: View {
|
|||||||
.padding(12)
|
.padding(12)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if os(iOS)
|
||||||
.background(Color(.systemBackground))
|
.background(Color(.systemBackground))
|
||||||
|
#else
|
||||||
|
.background(Color(nsColor: .windowBackgroundColor))
|
||||||
|
#endif
|
||||||
.cornerRadius(12)
|
.cornerRadius(12)
|
||||||
.shadow(radius: 8)
|
.shadow(radius: 8)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -140,7 +140,7 @@ public final class BricksEngine: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 执行bind动作
|
/// 执行bind动作
|
||||||
public func handleBind(_ bind: BindSchema, sourceId: String, eventData: EventData = [:]) async {
|
public func handleBind(_ bind: BindSchema, sourceId: String, eventData: EventData = EventData()) async {
|
||||||
guard let actionType = ActionType(rawValue: bind.actiontype) else {
|
guard let actionType = ActionType(rawValue: bind.actiontype) else {
|
||||||
print("[SwiftBricks] Invalid actiontype: \(bind.actiontype)")
|
print("[SwiftBricks] Invalid actiontype: \(bind.actiontype)")
|
||||||
return
|
return
|
||||||
@ -306,7 +306,7 @@ public final class BricksEngine: ObservableObject {
|
|||||||
// MARK: - 触发事件
|
// MARK: - 触发事件
|
||||||
|
|
||||||
/// 触发widget事件
|
/// 触发widget事件
|
||||||
public func triggerEvent(widgetId: String, event: String, data: EventData = [:]) async {
|
public func triggerEvent(widgetId: String, event: String, data: EventData = EventData()) async {
|
||||||
await eventBus.dispatch("\(widgetId).\(event)", data: data)
|
await eventBus.dispatch("\(widgetId).\(event)", data: data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -34,7 +34,7 @@ public final class BricksEventBus: ObservableObject {
|
|||||||
// MARK: - 发布
|
// MARK: - 发布
|
||||||
|
|
||||||
/// 派发事件
|
/// 派发事件
|
||||||
public func dispatch(_ eventName: String, data: EventData = [:]) async {
|
public func dispatch(_ eventName: String, data: EventData = EventData()) async {
|
||||||
// 记录日志
|
// 记录日志
|
||||||
eventLog.append((name: eventName, data: data, timestamp: Date()))
|
eventLog.append((name: eventName, data: data, timestamp: Date()))
|
||||||
if eventLog.count > maxLogSize {
|
if eventLog.count > maxLogSize {
|
||||||
@ -50,7 +50,7 @@ public final class BricksEventBus: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 同步派发(用于UI事件)
|
/// 同步派发(用于UI事件)
|
||||||
public func dispatchSync(_ eventName: String, data: EventData = [:]) {
|
public func dispatchSync(_ eventName: String, data: EventData = EventData()) {
|
||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
await dispatch(eventName, data: data)
|
await dispatch(eventName, data: data)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -131,7 +131,7 @@ public final class BricksRPC: ObservableObject {
|
|||||||
throw BricksRPCError.invalidResponse
|
throw BricksRPCError.invalidResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
let responseHeaders = Dictionary(
|
let responseHeaders: [String: String] = Dictionary(
|
||||||
uniqueKeysWithValues: httpResponse.allHeaderFields.compactMap { key, value in
|
uniqueKeysWithValues: httpResponse.allHeaderFields.compactMap { key, value in
|
||||||
guard let keyStr = key as? String, let valStr = value as? String else { return nil }
|
guard let keyStr = key as? String, let valStr = value as? String else { return nil }
|
||||||
return (keyStr, valStr)
|
return (keyStr, valStr)
|
||||||
|
|||||||
@ -30,6 +30,20 @@ public struct ControlSchema: Codable, Identifiable, Sendable {
|
|||||||
self.binds = binds
|
self.binds = binds
|
||||||
self.subwidgets = subwidgets
|
self.subwidgets = subwidgets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 自定义解码:options缺失时默认为空,避免Filler等无options的widget解码失败
|
||||||
|
public init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
self.id = try container.decodeIfPresent(String.self, forKey: .id)
|
||||||
|
self.widgettype = try container.decode(String.self, forKey: .widgettype)
|
||||||
|
self.options = try container.decodeIfPresent(ControlOptions.self, forKey: .options) ?? ControlOptions()
|
||||||
|
self.binds = try container.decodeIfPresent([BindSchema].self, forKey: .binds)
|
||||||
|
self.subwidgets = try container.decodeIfPresent([ControlSchema].self, forKey: .subwidgets)
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case id, widgettype, options, binds, subwidgets
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 控件选项 — 使用字典+Codable混合方式
|
/// 控件选项 — 使用字典+Codable混合方式
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user