eleven / messenger Public

Native lists: unnamed servers show their host, not "lchat" (#484)

* core: unnamed servers show their host, never the 'lchat' placeholder

The server's default group name for a never-named instance is 'lchat',
and it leaked into every native list (rail menu, drawer, palette).
LChatAPI.groupName/serverInfo now return "" for it so callers fall back
to the host, and SavedInstance.displayName treats a cached 'lchat'
groupName the same way (older vault entries carry it).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* core: filter the never-named default on the server's name_set flag

The literal-'lchat' check erased a legitimately chosen name; /api/group
already sends name_set (admin-chosen vs compiled-in default), so that's
the authority — the literal check remains only for pre-name_set servers.
displayName drops its own literal guard: the API layer is the one filter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell 4f5d9df74870c649bb42ff9a1e7cc0228634a95f parent dc30feb
2 files changed, +24 −9
  • ios/LChatCore/Sources/LChatCore/LChatAPI.swift +19 −7
  • ios/LChatCore/Sources/LChatCore/Models.swift +5 −2
diff --git a/ios/LChatCore/Sources/LChatCore/LChatAPI.swift b/ios/LChatCore/Sources/LChatCore/LChatAPI.swift
index c77819b..a36a66f 100644
--- a/ios/LChatCore/Sources/LChatCore/LChatAPI.swift
+++ b/ios/LChatCore/Sources/LChatCore/LChatAPI.swift
@@ -184,18 +184,30 @@ public struct LChatAPI {
description: r.description ?? "", imageURL: URL(string: r.image ?? ""))
}
- /// The instance's display name (public; substituted into pages too).
+ /// The instance's display name, or "" when it was never named, so callers
+ /// fall back to the host instead of parroting the compiled-in default.
+ /// The server's `name_set` flag is the authority (an admin-chosen name —
+ /// even literally "lchat" — always shows); the literal check is only the
+ /// degraded path for older servers that don't send the flag.
public func groupName() async -> String {
- struct Resp: Codable { let name: String? }
- return (try? await getJSON("/api/group", Resp.self, authed: false))?.name ?? "lchat"
+ struct Resp: Codable { let name: String?; let name_set: Bool? }
+ guard let r = try? await getJSON("/api/group", Resp.self, authed: false) else { return "" }
+ return Self.chosenName(r.name, nameSet: r.name_set)
}
- /// Public per-instance branding: the display name plus whether a server photo
- /// is set. Both are public (shown during add-a-chat, before any key exists).
+ /// Public per-instance branding: the display name ("" when never named —
+ /// see groupName) plus whether a server photo is set. Both are public
+ /// (shown during add-a-chat, before any key exists).
public func serverInfo() async -> (name: String, hasAvatar: Bool) {
- struct Resp: Codable { let name: String?; let avatar: Bool? }
+ struct Resp: Codable { let name: String?; let name_set: Bool?; let avatar: Bool? }
let r = try? await getJSON("/api/group", Resp.self, authed: false)
- return (r?.name ?? "lchat", r?.avatar ?? false)
+ return (Self.chosenName(r?.name, nameSet: r?.name_set), r?.avatar ?? false)
+ }
+
+ static func chosenName(_ name: String?, nameSet: Bool?) -> String {
+ let n = name ?? ""
+ if let nameSet { return nameSet ? n : "" }
+ return n == "lchat" ? "" : n // pre-name_set servers: filter the default
}
/// The instance's public branding photo bytes, or nil if none is set. Served
diff --git a/ios/LChatCore/Sources/LChatCore/Models.swift b/ios/LChatCore/Sources/LChatCore/Models.swift
index dcc16da..2d821f6 100644
--- a/ios/LChatCore/Sources/LChatCore/Models.swift
+++ b/ios/LChatCore/Sources/LChatCore/Models.swift
@@ -45,8 +45,11 @@ public struct SavedInstance: Codable, Identifiable, Equatable, Hashable {
public var baseURL: URL? { URL(string: origin) }
- /// A human label for the switcher until the real group name loads.
- public var displayName: String { groupName.isEmpty ? (baseURL?.host ?? "lchat") : groupName }
+ /// A human label for the switcher until the real group name loads. An
+ /// unnamed server shows as its host — the API layer already maps the
+ /// never-named default to "" (LChatAPI.chosenName), so a non-empty
+ /// groupName here is always admin-chosen.
+ public var displayName: String { groupName.isEmpty ? hostLabel : groupName }
/// The server's host (dropping a leading www.), for the switcher subtitle.
public var hostLabel: String {