Skip to content

Restore last used server and path on cold launch#5145

Merged
bgoncal merged 3 commits into
mainfrom
bgoncal/swiftui-server-state-regression-789eb7
Jul 17, 2026
Merged

Restore last used server and path on cold launch#5145
bgoncal merged 3 commits into
mainfrom
bgoncal/swiftui-server-state-regression-789eb7

Conversation

@bgoncal

@bgoncal bgoncal commented Jul 17, 2026

Copy link
Copy Markdown
Member

Summary

The SwiftUI lifecycle migration removed UIKit scene state restoration, so a cold launch always reopened on the first server at its default page instead of the last one in use.

This persists the last-active server id and a host-agnostic path (path/query/fragment, never the host) in SettingsStore as the web view navigates, and restores them at launch. The server is always restored; the last page is restored only when "Remember Last Page" is enabled. The path is rebuilt against whichever base URL is active at load time, so it survives connectivity/location changes (internal, external, remote UI).

Screenshots

Link to pull request in Documentation repository

Documentation: home-assistant/companion.home-assistant#

Any other notes

The SwiftUI lifecycle migration dropped scene state restoration, so the app always reopened on the first server at its default page. Persist the last-active server id and a host-agnostic path in SettingsStore and restore them at launch, rebuilding the path against the currently active base URL.
Copilot AI review requested due to automatic review settings July 17, 2026 11:14
@github-actions

github-actions Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

⚠️ Unused L10n strings detected

Found 5 unused localization strings in the codebase.

Click to see details
Parsing Strings.swift...
Found 2158 L10n strings

Reading all Swift source code...
Read 7380375 characters of Swift code

Checking for unused strings...
Checked 100/2158 strings...
Checked 200/2158 strings...
Checked 300/2158 strings...
Checked 400/2158 strings...
Checked 500/2158 strings...
Checked 600/2158 strings...
Checked 700/2158 strings...
Checked 800/2158 strings...
Checked 900/2158 strings...
Checked 1000/2158 strings...
Checked 1100/2158 strings...
Checked 1200/2158 strings...
Checked 1300/2158 strings...
Checked 1400/2158 strings...
Checked 1500/2158 strings...
Checked 1600/2158 strings...
Checked 1700/2158 strings...
Checked 1800/2158 strings...
Checked 1900/2158 strings...
Checked 2000/2158 strings...
Checked 2100/2158 strings...

================================================================================
UNUSED STRINGS REPORT
================================================================================

Found 5 unused strings:


WATCH:
  - L10n.Watch.Complications.Builder.previewFooter
    Key: watch.complications.builder.preview_footer
    Line: 5835
  - L10n.Watch.Complications.Builder.sourceCustom
    Key: watch.complications.builder.source_custom
    Line: 5865
  - L10n.Watch.Complications.Builder.templateColor
    Key: watch.complications.builder.template_color
    Line: 5877
  - L10n.Watch.Complications.Builder.textTemplate
    Key: watch.complications.builder.text_template
    Line: 5895

ROOT:
  - L10n.debugSectionLabel
    Key: debug_section_label
    Line: 26

================================================================================
Total unused: 5
================================================================================

================================================================================
Copy-paste these keys into the "Lokalise: Delete Keys" workflow (keys input):
================================================================================
debug_section_label,watch.complications.builder.preview_footer,watch.complications.builder.source_custom,watch.complications.builder.template_color,watch.complications.builder.text_template

To remove them, run the
Lokalise: Delete Keys
workflow — it deletes the keys from Lokalise and opens a PR removing them from
Localizable.strings and regenerating Strings.swift. Copy-paste these keys into the keys input:

debug_section_label,watch.complications.builder.preview_footer,watch.complications.builder.source_custom,watch.complications.builder.template_color,watch.complications.builder.text_template

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR restores “cold launch” behavior for the SwiftUI lifecycle by persisting (1) the last active server identifier and (2) a host-agnostic relative path (path?query#fragment) as the web view navigates, then using those values to select the initial server and optionally restore the last page when “Remember Last Page” is enabled.

Changes:

  • Persist last-active server ID and relative URL path in SettingsStore from WKWebView navigation updates.
  • Restore initial server selection (always) and initial path (only when enabled) during launch via OnboardingStateObservable.
  • Thread the restored initialPath through SwiftUI (ContainerViewHomeAssistantViewFrontendView) into WebViewController, and add unit tests for the restoration logic.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
Tests/App/WebView/WebViewControllerTests.swift Adds unit tests for rebuilding a stored relative path onto the active base URL (needs a small fix for try/XCTUnwrap).
Tests/App/Container/OnboardingStateObservableTests.swift New tests for preferred initial server selection and initial-path restoration gating.
Sources/Shared/Settings/SettingsStore.swift Adds persisted properties for last-active server identifier and last-active URL path.
Sources/App/Frontend/WebView/WebViewController/WebViewController+WebViewSetup.swift Persists server ID and relative path during main web view URL observation.
Sources/App/Frontend/WebView/WebViewController/WebViewController+URLLoading.swift Restores a saved relative path onto the currently resolved base URL on first load; adds restoredURL(base:relativePath:).
Sources/App/Frontend/WebView/WebViewController/WebViewController.swift Adds initialURLPath to carry the restored relative path into initial loading.
Sources/App/Frontend/WebView/HomeAssistantView/HomeAssistantViewModel.swift Adds initialPath to the view model so SwiftUI can pass launch-only restore intent down to the web view host.
Sources/App/Frontend/WebView/HomeAssistantView/HomeAssistantView.swift Plumbs initialPath into FrontendView.
Sources/App/Frontend/WebView/FrontendView.swift Replaces prior restoration input with initialPath, wiring it into WebViewController.initialURLPath.
Sources/App/Container/OnboardingStateObservable.swift Implements launch server selection from persisted ID and optional initial-path restoration based on settings + server match.
Sources/App/Container/ContainerView.swift Passes the initialPath associated value into HomeAssistantView for launch-only restoration.

Comment thread Tests/App/WebView/WebViewControllerTests.swift
Comment thread Tests/App/WebView/WebViewControllerTests.swift
Comment thread Tests/App/WebView/WebViewControllerTests.swift
The added initialPath initializer used a default argument, which does not satisfy the protocol's init(server:onWebViewController:) requirement. Provide the exact required initializer delegating to the initialPath variant.
@bgoncal
bgoncal merged commit 15d1942 into main Jul 17, 2026
11 checks passed
@bgoncal
bgoncal deleted the bgoncal/swiftui-server-state-regression-789eb7 branch July 17, 2026 13:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants