Let account labels call the source by its title, not its host

An account with no user-set label was named username@host everywhere it
appears — the switcher menu, the settings rows, the playlist selector —
which overflows a menu row the moment the host has a subdomain. The
default name and the switcher's disambiguation suffixes now use the
instance's title when one is set, falling back to the host as before.
This commit is contained in:
Arkadiusz Fal
2026-09-12 23:44:35 +02:00
parent ea66d8f303
commit 839de238d3
3 changed files with 26 additions and 11 deletions

View File

@@ -142,6 +142,13 @@ struct Instance: Identifiable, Codable, Hashable, Sendable {
name ?? url.host ?? url.absoluteString
}
/// The shortest thing that names this source to the user: its title when
/// one is set, else its host. What account labels append after the `@`.
var shortLabel: String? {
if let name, !name.isEmpty { return name }
return url.host
}
/// Returns the URL string with embedded credentials stripped for safe display in the UI.
var displayURL: String {
guard var components = URLComponents(url: url, resolvingAgainstBaseURL: false),

View File

@@ -260,6 +260,10 @@ final class DataContextValidator {
/// What the account is called with no user-set label: the stored login
/// identifier, else the source's name, else its host.
///
/// After the `@` comes the source's *title* when it has one — the host is
/// the fallback, not the name: `arek@nerdvpn.de` reads, while
/// `arek@invidious.nerdvpn.de` overflows every menu row it appears in.
///
/// Device-local by nature. The username lives in the Keychain beside the
/// credential rather than in synced metadata, so it is only available on a
/// device that is signed in — two devices holding the very same account can
@@ -269,15 +273,14 @@ final class DataContextValidator {
.accountCredentialsManager(for: account)?
.username(for: account),
!username.isEmpty {
if let host = accountsManager.instance(for: account)?.url.host {
return "\(username)@\(host)"
if let label = accountsManager.instance(for: account)?.shortLabel {
return "\(username)@\(label)"
}
return username
}
if let instance = accountsManager.instance(for: account) {
if let name = instance.name, !name.isEmpty { return name }
return instance.url.host ?? instance.type.displayName
return instance.shortLabel ?? instance.type.displayName
}
return String(localized: "accounts.status.instanceMissing")

View File

@@ -153,11 +153,12 @@ enum DataContextSwitcherLabels {
///
/// The identifier comes first: two logins on the *same* instance share a
/// host, so a host suffix would repeat the server and still leave the user
/// choosing between two identical rows. The host alone is what is left when
/// the identifier is not on this device — tvOS never receives one. Neither
/// is repeated when the name already carries it: the default name for an
/// account *is* `identifier@host`, so appending it unguarded produced two
/// rows reading `X · X`.
/// choosing between two identical rows. The host — the source's title when
/// it has one — alone is what is left when the identifier is not on this
/// device — tvOS never receives one. Neither is repeated when the name
/// already carries it: the default name for an account *is*
/// `identifier@host`, so appending it unguarded produced two rows reading
/// `X · X`.
///
/// The source is the last resort and the only one that can name what two
/// logins of the same server user on two copies of the same server differ
@@ -197,11 +198,15 @@ enum DataContextSwitcherLabels {
accountsManager: AccountsManager,
username: (Account) -> String?
) -> String {
// The same short label the default account name is built from — the
// source's title, host only as the fallback — or a name that already
// reads `user@Title` would fail the "already carries it" guard and
// grow a second, longer `user@full.host` suffix.
func withoutSource(_ peer: Account) -> String {
disambiguated(
name,
username: username(peer),
host: accountsManager.instance(for: peer)?.url.host
host: accountsManager.instance(for: peer)?.shortLabel
)
}
@@ -212,7 +217,7 @@ enum DataContextSwitcherLabels {
return disambiguated(
name,
username: username(account),
host: accountsManager.instance(for: account)?.url.host,
host: accountsManager.instance(for: account)?.shortLabel,
source: accountsManager.instance(for: account)?.displayName
)
}