Skip to content

Commit

Permalink
Improve custom widget execution error handling and UI (#3408)
Browse files Browse the repository at this point in the history
<!-- Thank you for submitting a Pull Request and helping to improve Home
Assistant. Please complete the following sections to help the processing
and review of your changes. Please do not delete anything from this
template. -->

## Summary
<!-- Provide a brief summary of the changes you have made and most
importantly what they aim to achieve -->

## Screenshots
<!-- If this is a user-facing change not in the frontend, please include
screenshots in light and dark mode. -->

## Link to pull request in Documentation repository
<!-- Pull requests that add, change or remove functionality must have a
corresponding pull request in the Companion App Documentation repository
(https://github.com/home-assistant/companion.home-assistant). Please add
the number of this pull request after the "#" -->
Documentation: home-assistant/companion.home-assistant#

## Any other notes
<!-- If there is any other information of note, like if this Pull
Request is part of a bigger change, please include it here. -->
  • Loading branch information
bgoncal authored Feb 5, 2025
1 parent 503a339 commit 092a1e3
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 12 deletions.
6 changes: 6 additions & 0 deletions Sources/App/Resources/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1162,5 +1162,11 @@ Home Assistant is free and open source home automation software with a focus on
"widgets.sensors.description" = "Display state of sensors";
"widgets.sensors.not_configured" = "No Sensors Configured";
"widgets.sensors.title" = "Sensors";
"widgets.custom.intent_toggle_failed.title" = "Failed to 'toggle' entity";
"widgets.custom.intent_toggle_failed.body" = "Please try again";
"widgets.custom.intent_activate_failed.title" = "Failed to 'activate' entity";
"widgets.custom.intent_activate_failed.body" = "Please try again";
"widgets.custom.intent_press_failed.title" = "Failed to 'press' entity";
"widgets.custom.intent_press_failed.body" = "Please try again";
"web_view.server_selection.title" = "Choose server";
"yes_label" = "Yes";
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ struct CustomWidgetActivateAppIntent: AppIntent {
.error(
"Failed to execute ActivateAppIntent, serverId: \(serverId), domain: \(domain), entityId: \(entityId), error: \(error)"
)
let dispatcher = LocalNotificationDispatcher()
dispatcher.send(.init(
id: .intentActivateFailed,
title: L10n.Widgets.Custom.IntentActivateFailed.title,
body: L10n.Widgets.Custom.IntentActivateFailed.body
))

continuation.resume()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ struct CustomWidgetPressButtonAppIntent: AppIntent {
.error(
"Failed to execute PressButtonAppIntent, serverId: \(serverId), domain: \(domain), entityId: \(entityId), error: \(error)"
)
let dispatcher = LocalNotificationDispatcher()
dispatcher.send(.init(
id: .intentPressFailed,
title: L10n.Widgets.Custom.IntentPressFailed.title,
body: L10n.Widgets.Custom.IntentPressFailed.body
))
continuation.resume()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import AppIntents
import Foundation
import Shared
import SwiftUI
import WidgetKit

@available(iOS 16.4, *)
struct CustomWidgetToggleAppIntent: AppIntent {
Expand Down Expand Up @@ -35,11 +36,25 @@ struct CustomWidgetToggleAppIntent: AppIntent {
.error(
"Failed to execute ToggleAppIntent, serverId: \(serverId), domain: \(domain), entityId: \(entityId), error: \(error)"
)
let dispatcher = LocalNotificationDispatcher()
dispatcher.send(.init(
id: .intentToggleFailed,
title: L10n.Widgets.Custom.IntentToggleFailed.title,
body: L10n.Widgets.Custom.IntentToggleFailed.body
))
continuation.resume()
}
}
}
_ = try await ResetAllCustomWidgetConfirmationAppIntent().perform()

/* Since several entities when toggled may not report the correct state right away
This is a workaround to refresh the widget a little later
In theory through push notification we could always ask the widget to update through
and automation/blueprint etc, but it's currently not reliable https://developer.apple.com/forums/thread/773852 */
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
WidgetCenter.shared.reloadTimelines(ofKind: WidgetsKind.custom.rawValue)
}
return .result()
}
}
11 changes: 4 additions & 7 deletions Sources/Extensions/Widgets/Custom/WidgetCustom.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ struct WidgetCustom: Widget {
AnyView(emptyView)
}, contents: modelsForWidget(
widget,
blurItems: timelineEntry.disabledItems,
infoProvider: timelineEntry.magicItemInfoProvider,
states: timelineEntry.entitiesState,
showStates: timelineEntry.showStates
Expand Down Expand Up @@ -49,7 +48,6 @@ struct WidgetCustom: Widget {

private func modelsForWidget(
_ widget: CustomWidget?,
blurItems: Bool,
infoProvider: MagicItemProviderProtocol,
states: [MagicItem: WidgetCustomEntry.ItemState],
showStates: Bool
Expand Down Expand Up @@ -88,7 +86,9 @@ struct WidgetCustom: Widget {
}
}()

if showStates, [.light, .switch, .inputBoolean].contains(magicItem.domain) {
if !widget.itemsStates.isEmpty {
return Color.gray
} else if showStates, [.light, .switch, .inputBoolean].contains(magicItem.domain) {
if state?.domainState == Domain.State.off {
return Color.gray
} else {
Expand Down Expand Up @@ -130,7 +130,7 @@ struct WidgetCustom: Widget {
showConfirmation: showConfirmation,
requiresConfirmation: magicItem.customization?.requiresConfirmation ?? true,
widgetId: widget.id,
disabled: blurItems
disabled: !widget.itemsStates.isEmpty
)
}
}
Expand Down Expand Up @@ -244,7 +244,6 @@ enum WidgetCustomSupportedFamilies {
]),
magicItemInfoProvider: MockMagicItemProvider(),
entitiesState: [:],
disabledItems: false,
showLastUpdateTime: true,
showStates: true
)
Expand All @@ -259,7 +258,6 @@ enum WidgetCustomSupportedFamilies {
widget: nil,
magicItemInfoProvider: MockMagicItemProvider(),
entitiesState: [:],
disabledItems: false,
showLastUpdateTime: true,
showStates: true
)
Expand All @@ -274,7 +272,6 @@ enum WidgetCustomSupportedFamilies {
widget: nil,
magicItemInfoProvider: MockMagicItemProvider(),
entitiesState: [:],
disabledItems: false,
showLastUpdateTime: true,
showStates: true
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ struct WidgetCustomEntry: TimelineEntry {
var widget: CustomWidget?
var magicItemInfoProvider: MagicItemProviderProtocol
var entitiesState: [MagicItem: ItemState]
// True when one of items is pending confirmation
var disabledItems: Bool
var showLastUpdateTime: Bool
var showStates: Bool

Expand All @@ -29,7 +27,6 @@ struct WidgetCustomTimelineProvider: AppIntentTimelineProvider {
date: .now,
magicItemInfoProvider: Current.magicItemProvider(),
entitiesState: [:],
disabledItems: false,
showLastUpdateTime: false,
showStates: false
)
Expand All @@ -42,7 +39,6 @@ struct WidgetCustomTimelineProvider: AppIntentTimelineProvider {
widget: widget,
magicItemInfoProvider: infoProvider(),
entitiesState: [:],
disabledItems: false,
showLastUpdateTime: configuration.showLastUpdateTime,
showStates: configuration.showStates
)
Expand All @@ -59,7 +55,6 @@ struct WidgetCustomTimelineProvider: AppIntentTimelineProvider {
widget: widget,
magicItemInfoProvider: infoProvider(),
entitiesState: entitiesState,
disabledItems: !(widget?.itemsStates.isEmpty ?? false),
showLastUpdateTime: configuration.showLastUpdateTime,
showStates: configuration.showStates
),
Expand Down
3 changes: 3 additions & 0 deletions Sources/Shared/Notifications/NotificationIdentifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ public enum NotificationIdentifier: String {
case scriptAppIntentRun
case sceneAppIntentRun
case carPlayIntro
case intentToggleFailed
case intentActivateFailed
case intentPressFailed
}
18 changes: 18 additions & 0 deletions Sources/Shared/Resources/Swiftgen/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3938,6 +3938,24 @@ public enum L10n {
public static var subtitle: String { return L10n.tr("Localizable", "widgets.custom.subtitle") }
/// Custom widgets
public static var title: String { return L10n.tr("Localizable", "widgets.custom.title") }
public enum IntentActivateFailed {
/// Please try again
public static var body: String { return L10n.tr("Localizable", "widgets.custom.intent_activate_failed.body") }
/// Failed to 'activate' entity
public static var title: String { return L10n.tr("Localizable", "widgets.custom.intent_activate_failed.title") }
}
public enum IntentPressFailed {
/// Please try again
public static var body: String { return L10n.tr("Localizable", "widgets.custom.intent_press_failed.body") }
/// Failed to 'press' entity
public static var title: String { return L10n.tr("Localizable", "widgets.custom.intent_press_failed.title") }
}
public enum IntentToggleFailed {
/// Please try again
public static var body: String { return L10n.tr("Localizable", "widgets.custom.intent_toggle_failed.body") }
/// Failed to 'toggle' entity
public static var title: String { return L10n.tr("Localizable", "widgets.custom.intent_toggle_failed.title") }
}
public enum ShowUpdateTime {
/// Last update:
public static var title: String { return L10n.tr("Localizable", "widgets.custom.show_update_time.title") }
Expand Down

0 comments on commit 092a1e3

Please # to comment.