Skip to content

feat(app): allow users to rename their Omi device (#2824)#5952

Open
eulicesl wants to merge 1 commit intoBasedHardware:mainfrom
eulicesl:feat/rename-device-refresh
Open

feat(app): allow users to rename their Omi device (#2824)#5952
eulicesl wants to merge 1 commit intoBasedHardware:mainfrom
eulicesl:feat/rename-device-refresh

Conversation

@eulicesl
Copy link
Copy Markdown

@eulicesl eulicesl commented Mar 23, 2026

Summary

  • Problem: Users cannot rename their Omi device — the settings UI shows the hardware BLE name with no way to customize it
  • What changed: Added a rename dialog in device settings that persists custom names locally and tracks device ownership to auto-reset on device switch
  • What did NOT change (scope boundary): No backend changes, no BLE protocol changes, no new dependencies

Linked Issue / Bounty

Root Cause

  • N/A — new feature

How It Works

  1. SharedPreferencesUtil.updateDeviceNameOnConnect() tracks the current device ID alongside the custom name — if a different device connects, the name resets to hardware default
  2. _showRenameDeviceDialog() in device settings presents a modal text field; saves to SharedPreferences on confirm
  3. Forget/unpair flows clear both deviceName and deviceNameDeviceId to prevent stale state
  4. All user-facing strings are localized via app_en.arb

Change Type

  • Feature

Scope

  • Mobile app

Security Impact

  • New permissions or capabilities introduced? No
  • Auth or token handling changed? No
  • Data access scope changed (screen data, OCR, user data)? No
  • New or changed network calls? No
  • Plugin or tool execution surface changed? No

Testing

  • Built locally
  • Manual verification: rename flow tested on iOS simulator — rename, reconnect, device switch, forget/unpair
  • Existing tests pass (flutter test test/providers/device_provider_test.dart)
  • flutter analyze clean on touched files
  • New tests added — no unit tests for dialog UI; rename logic is thin enough that integration test would be more valuable

Human Verification

  • Verified scenarios: rename → reconnect preserves name; switch device → resets to hardware name; forget → clears both fields; empty name rejected
  • Edge cases checked: empty string submission, very long name, rapid rename-then-disconnect
  • What I did not verify: Android (tested iOS only); multi-device BLE pairing race conditions

Evidence

Demo recording: https://github.com/user-attachments/assets/b6802017-8ad2-4470-86e6-cc91bed9e7af

Docs

  • N/A — no docs impact (settings UI feature, no API or config changes)

Performance, Privacy, and Reliability

No impact — SharedPreferences read/write only, no network calls added

Migration / Backward Compatibility

  • Backward compatible? Yes — new SharedPreferences keys are additive, existing users see hardware name until they rename
  • Migration needed? No

Risks and Mitigations

  • deviceNameDeviceId could become stale if the device ID format changes upstream — mitigated by always falling back to hardware name when ID mismatch occurs

AI Disclosure

🤖 Built with Claude Code

  • AI-assisted: initial implementation scaffold, rebase onto latest main
  • How I verified correctness: manual testing on iOS simulator, flutter analyze, existing test suite

@eulicesl eulicesl force-pushed the feat/rename-device-refresh branch 2 times, most recently from efd1a90 to 0199da8 Compare March 29, 2026 15:33
@eulicesl
Copy link
Copy Markdown
Author

This PR is now ready for review.

A few notes to make the review path unambiguous:

  • This branch has been rebased onto current main
  • Targeted validation has been re-run successfully:
    • flutter test test/providers/device_provider_test.dart
    • targeted flutter analyze on the touched rename-device files
  • This PR is intended to be the canonical review path for the device-rename work and supersedes feat(app): allow users to rename their Omi device #4749, which is the older stale/conflicted thread
  • I also have demo proof for the user-visible behavior and will attach/link it in the PR for bounty/review evidence

User-visible behavior covered by this PR:

  • rename a device from settings
  • preserve the custom name across reconnects for the same physical device
  • reset to the hardware/default name when switching to a different device
  • clear custom-name ownership mapping on forget/unpair

I kept this branch intentionally tight so the review surface matches the actual feature scope.

@eulicesl eulicesl marked this pull request as ready for review March 29, 2026 16:59
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 29, 2026

Greptile Summary

This PR adds device-rename support to the Omi app. Users can now tap the device name in settings to open a rename dialog; the custom name is persisted locally via a new deviceNameDeviceId ownership key in SharedPreferences, preserved across reconnects for the same physical device, and reset to the hardware-reported name when a different device connects. The forget/unpair paths in both device.dart and device_settings.dart are updated to clear the ownership key so stale custom names do not leak.

Key observations:

  • The ownership logic in updateDeviceNameOnConnect is correct and well-commented.
  • P1: The empty-name validation error snackbar in the rename dialog is rendered behind the still-open dialog (since AppSnackbar uses globalNavigatorKey → root scaffold → below the dialog overlay). Users who tap Save with an empty field see no error feedback; the dialog simply stays open with no explanation.
  • P2: Two 'Omi DevKit' fallback strings in device_settings.dart (lines 85 and 340) are hardcoded English literals rather than localized keys, violating the project's flutter-localization rule.
  • P2: All 35 non-English locale files stub the four new string keys with their English values; proper translations should be added before the feature ships to international users.

Confidence Score: 4/5

Safe to merge after fixing the invisible validation error snackbar; everything else is style/localization cleanup.

One P1 UX defect: the empty-name validation fires a snackbar that renders behind the open dialog, giving users no visible feedback. The underlying rename logic and persistence mechanism are sound. Two hardcoded fallback strings and untranslated non-English locales are P2 polish items that don't block the feature but should be addressed.

app/lib/pages/settings/device_settings.dart — the rename dialog's error-feedback path and hardcoded fallback strings need attention.

Important Files Changed

Filename Overview
app/lib/pages/settings/device_settings.dart Core of the feature: adds _showRenameDeviceDialog, updates the device name row to be tappable, and clears deviceNameDeviceId on forget/unpair. P1 bug: error snackbar for empty-name validation fires behind the dialog and is invisible. Also has two hardcoded 'Omi DevKit' English fallbacks that should be localized.
app/lib/backend/preferences.dart Adds deviceNameDeviceId getter/setter and updateDeviceNameOnConnect helper; logic is correct — preserves custom names for the same device, resets to hardware name when a different device connects.
app/lib/providers/device_provider.dart Replaces two direct deviceName = device.name assignments with updateDeviceNameOnConnect(device.id, device.name) — correctly delegates ownership tracking to the preferences helper.
app/lib/providers/onboarding_provider.dart Same pattern as device_provider.dart — replaces two raw deviceName = assignments with updateDeviceNameOnConnect calls during the onboarding pairing flow.
app/lib/pages/home/device.dart Adds deviceNameDeviceId = '' clear on unpair and simplifies ?.name?.toLowerCase() ?? '' to !.name.toLowerCase() — safe because name is non-nullable on BtDevice.
app/lib/l10n/app_en.arb Adds four new localization keys with correct English values and descriptions.
app/lib/l10n/app_localizations.dart Abstract class updated with the four new getter stubs — standard codegen output.
app/lib/l10n/app_localizations_de.dart Representative of all 35 non-English locale files: new strings are added as English verbatim (untranslated).

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Device connects] --> B{updateDeviceNameOnConnect}
    B --> C{deviceNameDeviceId empty?}
    C -- Yes --> D[Set deviceName = hardwareName]
    C -- No --> E{Same device ID?}
    E -- No --> F[Set deviceName = hardwareName]
    E -- Yes --> G{deviceName empty?}
    G -- Yes --> H[Set deviceName = hardwareName]
    G -- No --> I[Keep custom name]
    D --> J[Set deviceNameDeviceId = newId]
    F --> J
    H --> J
    I --> J
    K[User taps device name row] --> L[_showRenameDeviceDialog]
    L --> M{User saves}
    M -- Empty name --> N[AppSnackbar.showSnackbarError
⚠️ shown BEHIND dialog]
    M -- Valid name --> O[Save deviceName to prefs]
    O --> P{device != null?}
    P -- Yes --> Q[Save deviceNameDeviceId = device.id]
    P -- No --> R[deviceNameDeviceId NOT updated]
    Q --> S[Pop dialog + setState + success snackbar]
    R --> S
    T[Forget / Unpair] --> U[Clear deviceName]
    U --> V[Clear deviceNameDeviceId]
Loading

Comments Outside Diff (1)

  1. app/lib/pages/settings/device_settings.dart, line 151-154 (link)

    Error snackbar appears behind dialog

    AppSnackbar.showSnackbarError calls ScaffoldMessenger.of(globalNavigatorKey.currentState!.context) (see app_snackbar.dart:7). This resolves to the root Scaffold's snackbar overlay, which is layered below the dialog's Overlay entry. When the user taps Save with an empty name, the error message fires but is rendered beneath the still-open dialog — making it completely invisible. The user sees nothing happen and has no indication why the save was rejected.

    Consider using inline validation (a red error Text widget below the TextField inside the dialog) or closing the dialog before showing the snackbar instead:

    // Option A – inline validation
    StatefulBuilder(
      builder: (ctx, setDialogState) {
        String? errorText;
        return Column(
          children: [
            TextField(
              controller: controller,
              decoration: InputDecoration(
                hintText: context.l10n.enterDeviceName,
                errorText: errorText,
                ...
              ),
            ),
            // ... save button calls setDialogState(() => errorText = 'Device name cannot be empty');
          ],
        );
      },
    )

Reviews (2): Last reviewed commit: "fix(app): address rename-device review f..." | Re-trigger Greptile

@eulicesl eulicesl marked this pull request as draft March 29, 2026 18:48
@eulicesl
Copy link
Copy Markdown
Author

Addressed the two open rename-device issues on this branch:

  1. Rename row was effectively not tappable

    • removed the copyValue override from the device-name row so the rename action is no longer shadowed
    • the settings row now behaves as an actual rename entry point
  2. Stale device-name ownership on unpair

    • ensured the unpair / forget flows clear both:
      • deviceName
      • deviceNameDeviceId
    • this prevents a stale custom-name mapping from leaking into future pairing state

Additional cleanup while landing the fix:

  • regenerated localization outputs so the rename-device strings used by the dialog are available on the branch consistently

Validation I ran:

  • targeted flutter analyze on the touched rename-device files and adjacent device-provider files
    • no new errors from this fix
    • branch still has pre-existing warnings/info in nearby files outside the core rename-device logic

Keeping this PR in draft until the review surface is actually quiet and maintainer-ready.

@eulicesl
Copy link
Copy Markdown
Author

Final readiness note for maintainers:

  • The earlier Greptile findings about the unreachable rename dialog and stale deviceNameDeviceId cleanup were fixed on later commits in the current head.
  • Current branch behavior on the final head:
    • the device-name row opens the rename flow instead of being shadowed by copy-to-clipboard behavior
    • forget/unpair paths clear both deviceName and deviceNameDeviceId
    • localization outputs were regenerated so the rename dialog strings are present consistently on the branch
  • Latest branch check status on the final head is green.

This PR is the canonical rename-device review path and is ready for maintainer review.

@eulicesl eulicesl marked this pull request as ready for review March 29, 2026 19:54
@eulicesl eulicesl force-pushed the feat/rename-device-refresh branch 2 times, most recently from ba021cb to 8af6fea Compare April 4, 2026 18:37
Copilot AI review requested due to automatic review settings April 4, 2026 18:37
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds local device renaming support and preserves a user-defined device name across reconnects by tracking which physical device “owns” the custom name.

Changes:

  • Centralized “set device name on connect” behavior in SharedPreferencesUtil.updateDeviceNameOnConnect() using a new deviceNameDeviceId ownership key.
  • Updated connect flows (onboarding + device provider) to use the new update method instead of overwriting deviceName directly.
  • Added a rename-device dialog entry point in Device Settings, plus new English l10n strings.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
app/lib/providers/onboarding_provider.dart Uses updateDeviceNameOnConnect() during onboarding connect instead of overwriting deviceName.
app/lib/providers/device_provider.dart Uses updateDeviceNameOnConnect() when establishing/refreshing connections.
app/lib/pages/settings/device_settings.dart Adds rename dialog + device name row interaction; clears rename ownership on disconnect/forget.
app/lib/pages/home/device.dart Clears deviceNameDeviceId on unpair/forget flow.
app/lib/l10n/app_en.arb Adds new user-facing strings for rename flow.
app/lib/backend/preferences.dart Adds deviceNameDeviceId and updateDeviceNameOnConnect() to preserve/reset custom names across device switches.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread app/lib/pages/settings/device_settings.dart Outdated
Comment thread app/lib/backend/preferences.dart
@eulicesl eulicesl force-pushed the feat/rename-device-refresh branch 3 times, most recently from e1a7f4a to e597492 Compare April 6, 2026 04:36
@eulicesl eulicesl changed the title feat(app): allow users to rename their Omi device feat(app): allow users to rename their Omi device (#2824) Apr 6, 2026
@eulicesl eulicesl force-pushed the feat/rename-device-refresh branch 2 times, most recently from fe3fc89 to ec43494 Compare April 6, 2026 17:23
@eulicesl eulicesl force-pushed the feat/rename-device-refresh branch from ec43494 to 7307415 Compare April 14, 2026 14:20
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.

rename my Omi device ($300)

2 participants