mirror of
https://github.com/home-assistant/iOS.git
synced 2026-04-17 06:11:11 -05:00
## Summary Widget pages displayed wrong server names and showed blank names when >6 servers were configured. The issue had two root causes: 1. **Non-unique identifiers**: `IntentPanel` identifiers were set to just `panel.path`, causing duplicate identifiers when multiple servers shared the same panel path (e.g., "lovelace") 2. **Widget matching failure**: When widgets reloaded, the matching logic couldn't handle backward compatibility, causing incorrect server names to be displayed **Changes Made:** - Changed `IntentPanel` identifier from `panel.path` to `"serverID-path"` format to ensure uniqueness across servers - Added `extractedPath` computed property to `IntentPanel` for consistent path extraction supporting both old and new identifier formats - Updated widget matching logic in `WidgetOpenPageProvider` to properly match panels by server + path when reloading widgets - Ensured backward compatibility with existing widget configurations that use the old identifier format **Before:** ```swift // Server 1: identifier = "lovelace" // Server 2: identifier = "lovelace" // Duplicate! // Widget matching: fails to match correct server ``` **After:** ```swift // Server 1: identifier = "server1-lovelace" // Server 2: identifier = "server2-lovelace" // Unique! // Widget matching: correctly matches by server + extracted path ``` The fix handles server IDs that contain hyphens and maintains backward compatibility with widgets configured using the old identifier format. ## Screenshots N/A - Fix resolves display issue shown in original bug report screenshots ## Link to pull request in Documentation repository Documentation: home-assistant/companion.home-assistant# ## Any other notes - Follows existing pattern in `PageAppEntity.swift` (line 69) for consistency - Path extraction logic is shared via `IntentPanel.extractedPath` computed property to eliminate code duplication - All linters passed (SwiftFormat, SwiftLint) <!-- START COPILOT CODING AGENT SUFFIX --> <details> <summary>Original prompt</summary> > > ---- > > *This section details on the original issue you should resolve* > > <issue_title>iOS widget showing wrong page and shows no pages if more than 6 servers defined.</issue_title> > <issue_description><!-- Please READ THIS FIRST > If your issue relates to something not looking right on Home Assistant within the Companion App, please check if the error is present in Safari on iOS too. If the issue is also seen in Safari, please open an issue on the frontend repo (https://github.com/home-assistant/frontend/issues/new?labels=bug&template=BUG_REPORT.md) instead --> > > **iOS device model, version and app version** > > Model Name: iPhone 16 Pro Max > Software Version: 26.0.1 > App version: 2025.9.2 (2025.1423) > > **Home Assistant Core Version** > 2025.9.4 > > **Describe the bug** > When adding multiple pages to the widget, the correct page description isn't shown. When I have 5 servers (named Server 1 ... Server 5), and have added the Overview page for each server, the widget shows, Server 1 Overview, Server 1 Overview, Server 3 Overview, Server 3 Overview, and Server 5 Overview. Click on the second Server 1 Overview brings up Server 1 Overview, but the widget configuration shows that its suppose to bring up Server 2 Overview. > > Additionally, if I also add Server 6 to the list of servers, all of the page names are now blanks. It doesn't show Server 1 Overview, Server 2, Overview, etc. It would appear that having more than 5 servers defined causes the widget to not display the names of any of the defined pages. > > > **To Reproduce** > > Add up to 5 servers to the Companion App configuration. Then create a HA Open Page widget and add the Overview page for the first two servers. They will both be displayed with the first Server name. > > **Expected behavior** > > Adding the two server's Overview page should show Server 1 Overview and Server 2 Overview in the widget. > > **Screenshots** > > <img width="660" height="1434" alt="Image" src="https://github.com/user-attachments/assets/c421d9b4-d1d8-421b-b7b5-b50857a15973" /> > <img width="659" height="448" alt="Image" src="https://github.com/user-attachments/assets/73ad6c2d-5f0c-4d8d-82c5-0006ea74855d" /> > <img width="660" height="442" alt="Image" src="https://github.com/user-attachments/assets/1b891db3-c49a-469c-a82d-59c726964c01" /> > <img width="660" height="448" alt="Image" src="https://github.com/user-attachments/assets/dc469e31-e588-4e24-9e01-09abca6caacc" /> > <img width="660" height="446" alt="Image" src="https://github.com/user-attachments/assets/43e783a2-0f47-4ec2-a363-b6c45c3dab84" /> > <img width="660" height="453" alt="Image" src="https://github.com/user-attachments/assets/92337fd4-1feb-4b3b-9ee9-1c0049cb3bb2" /> > <img width="660" height="449" alt="Image" src="https://github.com/user-attachments/assets/a9d0548c-0e9d-496e-8616-84a6ffdc9fdc" /> > > **Additional context** > This problem has been ongoing for a month or so. > </issue_description> > > <agent_instructions>Check WidgetOpenPage, there must be some ID that is not unique or such a thing.</agent_instructions> > > ## Comments on the Issue (you are @copilot in this section) > > <comments> > </comments> > </details> - Fixes home-assistant/iOS#3876 <!-- START COPILOT CODING AGENT TIPS --> --- 💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey). --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: bgoncal <5808343+bgoncal@users.noreply.github.com>
69 lines
2.5 KiB
Swift
69 lines
2.5 KiB
Swift
import PromiseKit
|
|
import Shared
|
|
import SwiftUI
|
|
import WidgetKit
|
|
|
|
struct WidgetOpenPageEntry: TimelineEntry {
|
|
var date = Date()
|
|
var pages: [IntentPanel] = []
|
|
}
|
|
|
|
struct WidgetOpenPageProvider: IntentTimelineProvider {
|
|
typealias Intent = WidgetOpenPageIntent
|
|
typealias Entry = WidgetOpenPageEntry
|
|
|
|
func placeholder(in context: Context) -> WidgetOpenPageEntry {
|
|
let count = WidgetFamilySizes.size(for: context.family)
|
|
let pages = stride(from: 0, to: count, by: 1).map { idx in
|
|
with(IntentPanel(identifier: "redacted\(idx)", display: "Redacted Text")) {
|
|
$0.icon = MaterialDesignIcons.bedEmptyIcon.name
|
|
}
|
|
}
|
|
|
|
return .init(pages: pages)
|
|
}
|
|
|
|
private func panels(
|
|
for context: Context,
|
|
updating existing: [IntentPanel],
|
|
timeout: Measurement<UnitDuration> = .init(value: 10.0, unit: .seconds),
|
|
completion: @escaping ([IntentPanel]) -> Void
|
|
) {
|
|
OpenPageIntentHandler.panels { panels in
|
|
var intentsToDisplay = panels
|
|
|
|
if !existing.isEmpty {
|
|
intentsToDisplay = existing.compactMap { existingValue in
|
|
intentsToDisplay.first { newPanel in
|
|
// Match by server and path, supporting both old and new identifier formats
|
|
newPanel.server == existingValue.server && newPanel.extractedPath == existingValue.extractedPath
|
|
}
|
|
}
|
|
}
|
|
completion(Array(intentsToDisplay.prefix(WidgetFamilySizes.size(for: context.family))))
|
|
}
|
|
}
|
|
|
|
func getSnapshot(for configuration: Intent, in context: Context, completion: @escaping (Entry) -> Void) {
|
|
panels(for: context, updating: configuration.pages ?? []) { panels in
|
|
completion(Entry(pages: Array(panels.prefix(WidgetFamilySizes.sizeForPreview(for: context.family)))))
|
|
}
|
|
}
|
|
|
|
private static var expiration: Measurement<UnitDuration> {
|
|
.init(value: 24, unit: .hours)
|
|
}
|
|
|
|
func getTimeline(for configuration: Intent, in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
|
|
func timeline(for pages: [IntentPanel]) -> Timeline<Entry> {
|
|
.init(
|
|
entries: [.init(pages: pages)],
|
|
policy: .after(Current.date().addingTimeInterval(Self.expiration.converted(to: .seconds).value))
|
|
)
|
|
}
|
|
panels(for: context, updating: configuration.pages ?? []) { panels in
|
|
completion(timeline(for: panels))
|
|
}
|
|
}
|
|
}
|