Skip to content

feat: WiFi Advanced buffered save, unified Save UX, and guest detection improvement - #829

Merged
HankYuLinksys merged 1 commit into
hank/l1-service-merge-new-usp-clientfrom
feat/wifi-advanced-buffered-save-unified-ux
Apr 23, 2026
Merged

feat: WiFi Advanced buffered save, unified Save UX, and guest detection improvement#829
HankYuLinksys merged 1 commit into
hank/l1-service-merge-new-usp-clientfrom
feat/wifi-advanced-buffered-save-unified-ux

Conversation

@AustinChangLinksys

@AustinChangLinksys AustinChangLinksys commented Apr 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Migrate WiFi Advanced tab from fire-and-forget AsyncNotifier to FeatureState/Preservable pattern with buffered save and page-level dirty proxy
  • Unify save UX across 9 settings pages with doSomethingWithSpinner() overlay and standardized showSuccessSnackBar()/showFailedSnackBar()
  • Replace guest network SSID string matching (contains("guest")) with per-radio instance ordering (lowest index = Main, subsequent = Guest)
  • Fix dashboard topology card overflow by replacing fixed SizedBox(height: 320) with Expanded + ClipRect and scalable coverage rings

Test plan

  • WifiAdvancedFeatureState model tests — initial, isDirty, copyWith, Equatable
  • UspWifiAdvancedNotifier — performFetch, setDfsEnabled dirty/revert (uniform + mixed originals), performSave, error handling
  • Guest detection — dual-band, tri-band, no "guest" in SSID name, single SSID per radio
  • Tri-band codegen test data added
  • flutter analyze — no issues in changed files
  • 121 tests passed

Closes #828
Resolves #828

🤖 Generated with Claude Code

…on improvement

Migrate WiFi Advanced tab from fire-and-forget AsyncNotifier to
FeatureState/Preservable pattern with buffered save. Unify save UX
across all settings pages with spinner overlay and standardized
snackbars. Replace guest network string matching with per-radio
SSID instance ordering. Fix topology card overflow with Expanded
layout and scalable coverage rings.

Closes #828

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@qodo-code-review

Copy link
Copy Markdown
ⓘ You are approaching your monthly quota for Qodo. Upgrade your plan

Review Summary by Qodo

WiFi Advanced buffered save, unified Save UX, guest detection, and topology layout improvements

✨ Enhancement 🧪 Tests

Grey Divider

Walkthroughs

Description
• Migrate WiFi Advanced tab from fire-and-forget AsyncNotifier to FeatureState/Preservable pattern
  with buffered save
• Unify save UX across 9 settings pages with doSomethingWithSpinner() overlay and standardized
  snackbars
• Replace guest network SSID string matching with per-radio instance ordering (lowest index = Main)
• Fix dashboard topology card overflow by replacing fixed SizedBox with Expanded + ClipRect and
  scalable coverage rings
Diagram
flowchart LR
  A["WiFi Advanced Tab"] -->|"Migrate to FeatureState/Preservable"| B["Buffered Save Pattern"]
  B -->|"Dirty tracking"| C["Page-level Bottom Bar"]
  D["9 Settings Pages"] -->|"Unified Save UX"| E["doSomethingWithSpinner + Snackbars"]
  F["Guest Detection"] -->|"Per-radio SSID ordering"| G["Lowest index = Main, Rest = Guest"]
  H["Topology Card"] -->|"Replace fixed SizedBox"| I["Expanded + ClipRect + Scalable Rings"]
Loading

Grey Divider

File Changes

1. lib/page/wifi_settings/models/wifi_advanced_feature_state.dart ✨ Enhancement +42/-0

New FeatureState model for WiFi Advanced tab

lib/page/wifi_settings/models/wifi_advanced_feature_state.dart


2. lib/page/wifi_settings/models/wifi_advanced_settings.dart ✨ Enhancement +31/-0

User-editable WiFi Advanced settings model

lib/page/wifi_settings/models/wifi_advanced_settings.dart


3. lib/page/wifi_settings/models/wifi_advanced_status.dart ✨ Enhancement +34/-0

Transient status model for WiFi Advanced feature

lib/page/wifi_settings/models/wifi_advanced_status.dart


View more (23)
4. lib/page/wifi_settings/providers/usp_wifi_advanced_provider.dart ✨ Enhancement +126/-21

Migrate to FeatureState with buffered save and dirty tracking

lib/page/wifi_settings/providers/usp_wifi_advanced_provider.dart


5. lib/page/wifi_settings/providers/usp_wifi_advanced_state.dart ✨ Enhancement +0/-30

Remove old AsyncNotifier state model

lib/page/wifi_settings/providers/usp_wifi_advanced_state.dart


6. lib/page/wifi_settings/providers/usp_wifi_settings_provider.dart ✨ Enhancement +43/-4

Add route-level dirty proxy aggregating both WiFi tabs

lib/page/wifi_settings/providers/usp_wifi_settings_provider.dart


7. lib/page/wifi_settings/views/tabs/wifi_advanced_tab.dart ✨ Enhancement +70/-85

Refactor to use new FeatureState and buffered save pattern

lib/page/wifi_settings/views/tabs/wifi_advanced_tab.dart


8. lib/page/wifi_settings/views/tabs/wifi_list_tab.dart ✨ Enhancement +40/-106

Remove page-level save bar, delegate to parent view

lib/page/wifi_settings/views/tabs/wifi_list_tab.dart


9. lib/page/wifi_settings/views/usp_wifi_settings_view.dart ✨ Enhancement +99/-3

Add unified bottom bar and per-tab dirty state handling

lib/page/wifi_settings/views/usp_wifi_settings_view.dart


10. lib/page/wifi_settings/services/usp_wifi_settings_service.dart ✨ Enhancement +35/-3

Replace SSID string matching with per-radio instance ordering for guest detection

lib/page/wifi_settings/services/usp_wifi_settings_service.dart


11. lib/page/wifi_settings/models/wifi_network_ui_model.dart 📝 Documentation +2/-3

Update guest detection documentation to reflect new ordering approach

lib/page/wifi_settings/models/wifi_network_ui_model.dart


12. lib/page/dhcp/views/usp_dhcp_detail_view.dart ✨ Enhancement +5/-1

Wrap save call with doSomethingWithSpinner and standardized snackbars

lib/page/dhcp/views/usp_dhcp_detail_view.dart


13. lib/page/dmz/views/usp_dmz_view.dart ✨ Enhancement +8/-7

Unify save UX with spinner overlay and standardized snackbars

lib/page/dmz/views/usp_dmz_view.dart


14. lib/page/firewall/views/usp_firewall_view.dart ✨ Enhancement +8/-7

Unify save UX with spinner overlay and standardized snackbars

lib/page/firewall/views/usp_firewall_view.dart


15. lib/page/instant_safety/views/instant_safety_view.dart ✨ Enhancement +8/-7

Unify save UX with spinner overlay and standardized snackbars

lib/page/instant_safety/views/instant_safety_view.dart


16. lib/page/ipv6_port_service/views/usp_ipv6_port_service_view.dart ✨ Enhancement +5/-1

Unify save UX with spinner overlay and standardized snackbars

lib/page/ipv6_port_service/views/usp_ipv6_port_service_view.dart


17. lib/page/local_network/views/usp_local_network_view.dart ✨ Enhancement +9/-8

Unify save UX with spinner overlay and standardized snackbars

lib/page/local_network/views/usp_local_network_view.dart


18. lib/page/port_forwarding/views/usp_port_forwarding_detail_view.dart ✨ Enhancement +5/-1

Unify save UX with spinner overlay and standardized snackbars

lib/page/port_forwarding/views/usp_port_forwarding_detail_view.dart


19. lib/page/static_routing/views/usp_static_routing_view.dart ✨ Enhancement +5/-1

Unify save UX with spinner overlay and standardized snackbars

lib/page/static_routing/views/usp_static_routing_view.dart


20. lib/page/topology/cards/usp_network_topology_card.dart 🐞 Bug fix +42/-36

Fix overflow by replacing fixed SizedBox with Expanded and scalable coverage rings

lib/page/topology/cards/usp_network_topology_card.dart


21. lib/page/topology/helpers/usp_topology_builder.dart ✨ Enhancement +10/-4

Add coverageRingScale parameter for compact topology contexts

lib/page/topology/helpers/usp_topology_builder.dart


22. lib/route/route_usp_dashboard.dart ✨ Enhancement +1/-1

Update WiFi route to use unified dirty proxy provider

lib/route/route_usp_dashboard.dart


23. test/page/wifi_settings/models/wifi_advanced_feature_state_test.dart 🧪 Tests +124/-0

Add comprehensive tests for FeatureState and Settings models

test/page/wifi_settings/models/wifi_advanced_feature_state_test.dart


24. test/page/wifi_settings/providers/usp_wifi_advanced_notifier_test.dart 🧪 Tests +179/-75

Refactor tests for new FeatureState pattern with performFetch and performSave

test/page/wifi_settings/providers/usp_wifi_advanced_notifier_test.dart


25. test/page/wifi_settings/services/usp_wifi_settings_service_test.dart 🧪 Tests +158/-0

Add guest detection tests for dual-band, tri-band, and edge cases

test/page/wifi_settings/services/usp_wifi_settings_service_test.dart


26. test/mocks/test_data/wifi_settings_test_data.dart 🧪 Tests +116/-0

Add tri-band codegen test data for comprehensive coverage

test/mocks/test_data/wifi_settings_test_data.dart


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented Apr 22, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Remediation recommended

1. copyWith clears errorMessage 🐞 Bug ≡ Correctness
Description
WifiAdvancedStatus.copyWith() assigns errorMessage directly from its nullable parameter, so
calls like copyWith(isSaving: true) unintentionally wipe an existing error message. This can cause
fetch/load errors to disappear from state when toggling unrelated flags (e.g., isSaving).
Code

lib/page/wifi_settings/models/wifi_advanced_status.dart[R20-30]

+  WifiAdvancedStatus copyWith({
+    bool? isLoading,
+    bool? isSaving,
+    String? errorMessage,
+  }) {
+    return WifiAdvancedStatus(
+      isLoading: isLoading ?? this.isLoading,
+      isSaving: isSaving ?? this.isSaving,
+      errorMessage: errorMessage,
+    );
+  }
Evidence
WifiAdvancedStatus.copyWith does not preserve the prior errorMessage when the caller omits it,
unlike other status models in this codebase (e.g., WifiSettingsStatus.copyWith uses `errorMessage
?? this.errorMessage). Since the notifier updates flags via state.status.copyWith(isSaving:
true/false)`, an existing error message would be cleared as a side effect.

lib/page/wifi_settings/models/wifi_advanced_status.dart[20-30]
lib/page/wifi_settings/providers/usp_wifi_advanced_provider.dart[82-96]
lib/page/wifi_settings/models/wifi_settings_status.dart[41-56]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`WifiAdvancedStatus.copyWith()` currently sets `errorMessage` to the passed parameter value, which defaults to `null`. This means any call that updates `isLoading`/`isSaving` without explicitly passing `errorMessage` will clear an existing error.

### Issue Context
Other status models (e.g. `WifiSettingsStatus`) preserve `errorMessage` by default.

### Fix
Update `WifiAdvancedStatus.copyWith` so `errorMessage` defaults to the previous value when not provided.

### Fix Focus Areas
- lib/page/wifi_settings/models/wifi_advanced_status.dart[20-30]
- lib/page/wifi_settings/providers/usp_wifi_advanced_provider.dart[82-96]
- lib/page/wifi_settings/models/wifi_settings_status.dart[41-56]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Guest misclassified with empty LowerLayers 🐞 Bug ≡ Correctness
Description
Guest SSID detection groups SSIDs by ssid.lowerLayers; when LowerLayers is missing/empty,
multiple SSIDs are grouped under the same empty key and all but the first are marked as guest. This
can incorrectly label networks as guest on devices that return empty LowerLayers values.
Code

lib/page/wifi_settings/services/usp_wifi_settings_service.dart[R69-80]

+      final ssidsByRadio = <String, List<WiFiSsid>>{};
+      for (final ssid in ssids.items) {
+        final radioKey = _ensureTrailingDot(ssid.lowerLayers);
+        (ssidsByRadio[radioKey] ??= []).add(ssid);
+      }
+      for (final group in ssidsByRadio.values) {
+        group.sort((a, b) => _ssidInstanceIndex(a.instancePath)
+            .compareTo(_ssidInstanceIndex(b.instancePath)));
+        for (final ssid in group.skip(1)) {
+          guestSsidPaths.add(_ensureTrailingDot(ssid.instancePath));
+        }
+      }
Evidence
The new algorithm uses ssid.lowerLayers as the grouping key without special-casing empty strings.
Codegen sets lowerLayers to '' when the TR-181 parameter is absent, so an empty value is a
realistic input; in that case, all SSIDs with missing LowerLayers are grouped together and
group.skip(1) marks them as guest.

lib/page/wifi_settings/services/usp_wifi_settings_service.dart[61-81]
lib/generated/wi_fi_ssids.g.dart[87-97]
lib/generated/wi_fi_ssids.g.dart[8-23]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Guest detection currently treats `ssid.lowerLayers == ''` as a valid radio key. If multiple SSIDs have empty/missing `LowerLayers`, they get grouped together and all but the first are marked as guest.

### Issue Context
`WiFiSsid.lowerLayers` is codegen-populated with `(response['...LowerLayers'] ?? '')`, so empty string is a real runtime value.

### Fix
When building `ssidsByRadio`, handle empty/invalid `lowerLayers` explicitly. Options:
- Skip guest classification for SSIDs with empty `lowerLayers` (treat as Main), or
- Fall back to a safer heuristic for those SSIDs only (e.g., name-based), or
- Use a per-SSID unique key when `lowerLayers` is empty so no SSID is marked guest due to grouping.

Add a unit test covering empty `LowerLayers` inputs.

### Fix Focus Areas
- lib/page/wifi_settings/services/usp_wifi_settings_service.dart[61-81]
- lib/generated/wi_fi_ssids.g.dart[87-97]
- test/page/wifi_settings/services/usp_wifi_settings_service_test.dart[586-738]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@HankYuLinksys HankYuLinksys left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks good!

@HankYuLinksys
HankYuLinksys merged commit 10178ff into hank/l1-service-merge-new-usp-client Apr 23, 2026
@HankYuLinksys
HankYuLinksys deleted the feat/wifi-advanced-buffered-save-unified-ux branch April 23, 2026 03:29
@AustinChangLinksys AustinChangLinksys linked an issue Apr 23, 2026 that may be closed by this pull request
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[WiFi] WiFi Settings Complete Support

2 participants