Skip to content

feat: local display names for nodes#1620

Open
gilindoesgit wants to merge 2 commits into
meshtastic:mainfrom
gilindoesgit:feature/display-names
Open

feat: local display names for nodes#1620
gilindoesgit wants to merge 2 commits into
meshtastic:mainfrom
gilindoesgit:feature/display-names

Conversation

@gilindoesgit

Copy link
Copy Markdown

Local display names for nodes

Users can set a local display name for any node. That name is shown in the app instead of the device’s long/short name, and is stored only on the device (not sent over the mesh).


Summary

StorageNodeDisplayNameStore (UserDefaults), keyed by node number
ScopeNode list, node detail, messages (user list & relay), compass waypoint name
Edit entry pointsLong-press node → “Set display name”; Node detail → “Display name” row

UI

  • Node list – Rows show the custom display name when set, otherwise the device long/short name.
  • Long-press menu – “Set display name” opens a sheet to set or clear the name.
  • Node detail – Navigation title and a “Display name” row; tapping the row opens the edit sheet.
  • Edit sheet – Text field for the local name, with options to save or clear the display name.
  • Messages – User list and relay text use displayLongName / displayShortName.

Technical details

  • Key: Display names are stored and looked up by node number (num), the unique node ID.
  • Persistence: UserDefaults key nodeDisplayNames; JSON dictionary [String: String] with node num as string key.
  • Model: UserEntity extensions displayLongName and displayShortName; they return the stored name if set, otherwise the existing longName / shortName.
  • UI refresh: NodeDisplayNameStore.didChangeNotification is posted when a name is set or cleared; detail view subscribes to refresh the title.

Checklist

  • Display name keyed by node number only
  • Shown in list, detail, and messages; editable from list context menu and detail row
  • Clear display name restores device name
  • No change to device identity or protocol; local-only

Meshtastic Contributor added 2 commits March 8, 2026 20:44
- Add NodeDisplayNameStore (UserDefaults) keyed by node number
- Add displayLongName/displayShortName on UserEntity
- Show custom name in node list, detail, messages, relay text
- Add EditNodeDisplayNameView sheet and 'Set display name' in list/detail
- Notify UI on change via NodeDisplayNameStore.didChangeNotification

Made-with: Cursor
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


Meshtastic Contributor seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@garthvh

garthvh commented Apr 2, 2026

Copy link
Copy Markdown
Member

This feature was in the app before and just caused confusion, without this data persisting on the node it just seems like a way to frustrate users.

@TMTwatch

TMTwatch commented May 2, 2026

Copy link
Copy Markdown

Maybe a notes field could be added instead? A small icon n next in the node list could signal that there's added info in the notes

@garthvh garthvh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the PR — local display names is a genuinely useful feature and the core idea is well thought out. NodeDisplayNameStore is clean, the notification-based refresh pattern is correct, and the displayLongName/displayShortName computed properties are a nice drop-in replacement. However there are several blocking issues that need to be addressed before this can merge.


Critical — Wrong extension files / Core Data assumptions

This PR was authored against an old version of the repo. Core Data has been fully removed from this project — all persistence is SwiftData. The affected files have moved:

PR targets Correct path on main
Meshtastic/Extensions/CoreData/UserEntityExtension.swift Meshtastic/Extensions/SwiftData/UserEntityExtension.swift
Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift Meshtastic/Extensions/SwiftData/NodeInfoEntityExtension.swift
Meshtastic/Extensions/CoreData/MessageEntityExtension.swift Meshtastic/Extensions/SwiftData/MessageEntityExtension.swift

Please rebase onto current main and redirect all changes to the SwiftData extension files.

Critical — NSManagedObjectID / Core Data API in NodeInfoEntityExtension

The diff adds:

extension NodeInfoEntity: Identifiable {
    public var id: NSManagedObjectID { objectID }
}

NSManagedObjectID and objectID are Core Data APIs. NodeInfoEntity is a SwiftData @Model — it already conforms to Identifiable through SwiftData via persistentModelID. This block needs to be removed entirely.

Critical — import CoreData in EditNodeDisplayNameView.swift

EditNodeDisplayNameView imports CoreData but does not use it. Remove the import — the view only needs SwiftUI.

Critical — NodeList uses @query, not NSFetchRequest

The PR's FilteredNodeList initialiser sets up an NSFetchRequest<NodeInfoEntity> — but on main, NodeList uses @Environment(\.modelContext) and @Query (SwiftData). These APIs are incompatible. After rebasing, the node-for-display-name binding needs to be wired into the existing SwiftData query-driven list.

Warning — Force-unwrap in MessageEntityExtension.swift

let name = users.first!.displayLongName  // crash if users is somehow empty

The original code safely used optional binding. Please restore a guard or use optional chaining instead.

Warning — Indentation regressions

The diff introduces broken indentation in NodeDetail.swift, NodeListItem.swift, NodeRow.swift, and NodeList.swift — mixed tabs/spaces and misaligned braces. The .sheet call in NodeDetail is de-indented out of its ScrollViewReader scope. Please run SwiftLint before submitting (scripts/lint).

Warning — docs/PULL_REQUEST_DISPLAY_NAMES.md should be removed

This file is a copy of the PR description dropped into docs/. It is not a user guide or developer doc. Please delete it. If you would like to document the feature, add a section to docs/user/nodes.md instead (per the view-to-doc mapping in CONTRIBUTING.md).

Warning — No tests

NodeDisplayNameStore is the most independently testable piece here and has no coverage. Please add a Swift Testing suite (import Testing, @Suite, @Test, #expect) covering at minimum: set/get, clear, persistence across instances, and notification posting. See MeshtasticTests/RouterTests.swift for the project's testing conventions.


What to keep as-is

  • NodeDisplayNameStore.swift — solid implementation, keep it
  • EditNodeDisplayNameView.swift — clean UI, keep it (just remove import CoreData)
  • displayLongName / displayShortName computed properties on UserEntity — correct approach, just apply them to the right SwiftData extension file
  • The NodeDisplayNameStore.didChangeNotification + .id(displayNameRefresh) refresh pattern in NodeDetail — correct, keep it

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.

4 participants