apply the busy gate to the whole iOS picker, not just one row

The 500ms switchingProfileByTimeout delay left every profile and incognito
row live while a change was already in flight, so a second tap could run
apiChangeConnectionUser against a connection recreateConn was deleting.
Gate hit testing on busy instead, which subsumes the per-row disabled.

Also mirror the users.append fallback from the compose picker: a failed
listUsersAsync left the new profile absent from the list it was selected in.
This commit is contained in:
Narasimha-sc
2026-08-07 14:16:45 +00:00
parent 185c6e1d2b
commit b9525704c9
2 changed files with 13 additions and 4 deletions
@@ -352,6 +352,9 @@ struct ContextProfilePickerView: View {
private func incognitoOption() -> some View {
Button {
// As in profilerPickerUserOption: a failed changeProfile would leave the
// incognito default on while the picker still shows the chat profile.
if busy { return }
if !chat.chatInfo.profileChangeProhibited {
if incognitoDefault {
listExpanded.toggle()
@@ -516,13 +516,15 @@ private struct ActiveProfilePicker: View {
}
// The row must be dead from the moment work starts: switchingProfileByTimeout only
// latches half a second later, to keep the spinner from flickering.
// The picker must be dead from the moment work starts: switchingProfileByTimeout only
// latches half a second later, to keep the spinner from flickering, and in that window
// a second row tap would run apiChangeConnectionUser against a connection that
// recreateConn is already deleting.
private var busy: Bool { creatingProfile || switchingProfileByTimeout || profileSwitchStatus != .idle }
@ViewBuilder private func viewBody() -> some View {
profilePicker()
.allowsHitTesting(!switchingProfileByTimeout)
.allowsHitTesting(!busy)
.modifier(ThemedBackground(grouped: true))
.overlay {
if switchingProfileByTimeout {
@@ -586,7 +588,6 @@ private struct ActiveProfilePicker: View {
Spacer()
}
}
.disabled(busy)
}
// Created without activating, then routed through the same selectedProfile path as
@@ -638,6 +639,11 @@ private struct ActiveProfilePicker: View {
await MainActor.run {
if let updatedUsers = updatedUsers { chatModel.users = updatedUsers }
profiles = chatModel.users.map { $0.user }
// listUsersAsync failed, so chatModel.users predates the creation: without this
// selectedProfile below points at a profile that has no row in the picker.
if !profiles.contains(where: { $0.userId == newUser.userId }) {
profiles.append(newUser)
}
showAddProfile = false
selectedProfile = newUser
profileSwitchStatus = .switchingUser