fix(client/apple): a pinned card belongs to its profile, not to its host's binding
Grouping by profile asked each HOST which profile it was bound to, then handed the answer to that host's every card. So a card visibly wearing a "Gaming" chip — a pin, on a host bound to nothing — was filed under "No Profile" along with the rest. Every pinned card was, which is most of what the grouping exists to separate. Pins are not bindings. The arrangement works on CARDS now: a host's own card follows its binding, a pinned card follows its pin, and both can land in the same band when a host pinned the profile it is also bound to. The expansion moved out of the view and into the arrangement, because it is exactly what the grouping has to see. The regression is pinned by a test whose fixture is the shape that broke: a host bound to nothing, carrying two pins. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -63,8 +63,8 @@ struct HomeView: View {
|
||||
groupHeader(title, accent: group.accent)
|
||||
}
|
||||
LazyVGrid(columns: gridColumns, spacing: gridSpacing) {
|
||||
ForEach(entries(in: group)) { entry in
|
||||
hostCard(entry.host, pinned: entry.profile)
|
||||
ForEach(group.cards) { card in
|
||||
hostCard(card.host, pinned: card.pinned)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -210,16 +210,9 @@ struct HomeView: View {
|
||||
|
||||
// MARK: - Cards
|
||||
|
||||
/// One grid tile: a host's primary card, or one of its pinned host+profile cards. A pin is
|
||||
/// presentation only — same record, same live status, so it is an extra ENTRY here rather than
|
||||
/// a duplicated host (which would fork pairing, WoL and renames — design §5.2a).
|
||||
private struct HostGridEntry: Identifiable {
|
||||
let host: StoredHost
|
||||
let profile: StreamProfile?
|
||||
var id: String { "\(host.id.uuidString)#\(profile?.id ?? "")" }
|
||||
}
|
||||
|
||||
/// The grid's bands, ordered and divided per this device's preference (`HostArrangement`).
|
||||
/// The grid's bands, ordered and divided per this device's preference — cards and all, so a
|
||||
/// pinned card can be filed under the profile it connects with rather than under its host's
|
||||
/// binding (`HostArrangement`).
|
||||
private var hostGroups: [HostGroup] {
|
||||
HostArrangement.groups(
|
||||
hosts: store.hosts, catalog: profiles.catalog,
|
||||
@@ -228,15 +221,6 @@ struct HomeView: View {
|
||||
grouping: HostGrouping(rawValue: groupingRaw) ?? .none)
|
||||
}
|
||||
|
||||
/// A band's hosts, each immediately followed by its pinned cards — so a pin reads as belonging
|
||||
/// to its host rather than as a stray tile somewhere in the grid.
|
||||
private func entries(in group: HostGroup) -> [HostGridEntry] {
|
||||
group.hosts.flatMap { host in
|
||||
[HostGridEntry(host: host, profile: nil)]
|
||||
+ profiles.pinned(for: host).map { HostGridEntry(host: host, profile: $0) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Online = advertising on mDNS OR answered the reachability probe (a routed/VPN host never
|
||||
/// advertises). One definition, used by the cards and by the Status grouping alike.
|
||||
private func isOnline(_ host: StoredHost) -> Bool {
|
||||
|
||||
Reference in New Issue
Block a user