mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-08-28 00:44:27 +00:00
fix four more the high-effort review found, two of them my own reverts
Two of these exist because I reverted half of a coupled pair while keeping the other half. iOS: apiChangeConnectionUser returns nil rather than throwing when the network retry is cancelled, so neither branch of the selectedProfile handler ran, profileSwitchStatus stayed .switchingUser, switchingProfileByTimeout latched and the picker was left permanently behind its spinner with hit testing off. I removed this else branch two passes ago believing it was only reachable with no connection - it is reachable offline, which is a row in this branch's own test matrix, and on the create path it also strands the profile just created. Kotlin has had the equivalent guard all along. Kotlin: appPreferences.incognito.set(false) went back to master's position, before the connection change - but the early return that now keeps the picker open on failure stayed. Together those clear the app-wide default while the picker still shows Incognito ticked and nothing was moved. Moved below the reassignment, where the early return puts it out of reach. changeActiveUser_ throws, and withApi does not catch, so a failure inside onCreated reached GlobalExceptionsHandler, which silently closes a modal or clears chatId - profile created, invitation not moved, nothing said. Caught and reported, matching the runCatching and the safe changeActiveUser wrapper this same function already uses. iOS: when the profile list refresh fails, the new profile is absent from users while changeProfile sets selectedUser to it, so otherUsers filters nobody out and the row count exceeds what frame(maxHeight:) allows - clipping "Add profile" at the top, for exactly the single-profile user this feature is for. Also records that Terminal/Input.hs caches any CRActiveUser as the host's current user, which keepActiveUser makes conditional. Display-only, and the response carries nothing to distinguish the two cases.
This commit is contained in:
@@ -295,6 +295,10 @@ struct ContextProfilePickerView: View {
|
||||
chatModel.users = updatedUsers
|
||||
// Only filled in onAppear otherwise, so the new profile is missing here
|
||||
users = updatedUsers.map { $0.user }.filter { u in u.activeUser || !u.hidden }
|
||||
} else if !users.contains(where: { $0.userId == newUser.userId }) {
|
||||
// changeProfile sets selectedUser to it, and otherUsers filters on that -
|
||||
// absent from users, nothing is filtered out and a row is clipped.
|
||||
users.append(newUser)
|
||||
}
|
||||
// changingProfile here too: the defer clears creatingProfile as soon as this returns
|
||||
showAddProfile = false
|
||||
|
||||
@@ -479,6 +479,15 @@ private struct ActiveProfilePicker: View {
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// apiChangeConnectionUser returns nil rather than throwing when
|
||||
// the retry is cancelled - offline. Without this the status stays
|
||||
// .switchingUser, switchingProfileByTimeout latches, and the
|
||||
// picker is left permanently behind its spinner.
|
||||
await MainActor.run {
|
||||
profileSwitchStatus = .idle
|
||||
selectedProfile = chatModel.currentUser ?? selectedProfile
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
await MainActor.run {
|
||||
|
||||
+8
-1
@@ -414,7 +414,14 @@ fun createProfileForInvitation(rhId: Long?, onCreated: suspend (User) -> Unit) {
|
||||
return@withApi
|
||||
}
|
||||
close()
|
||||
onCreated(newUser)
|
||||
try {
|
||||
onCreated(newUser)
|
||||
} catch (e: Exception) {
|
||||
// changeActiveUser_ throws, and withApi does not catch - the global handler
|
||||
// would close a modal or clear chatId with nothing said about the failure.
|
||||
Log.e(TAG, "createProfileForInvitation: moving the invitation failed: ${e.stackTraceToString()}")
|
||||
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_changing_user))
|
||||
}
|
||||
} finally {
|
||||
chatModel.creatingProfileForInvitation.value = false
|
||||
}
|
||||
|
||||
+3
-2
@@ -323,8 +323,6 @@ fun ActiveProfilePicker(
|
||||
try {
|
||||
var updatedConn: PendingContactConnection? = null
|
||||
|
||||
appPreferences.incognito.set(false)
|
||||
|
||||
if (contactConnection != null) {
|
||||
updatedConn = controller.apiChangeConnectionUser(rhId, contactConnection.pccConnId, user.userId)
|
||||
// Not moved - leave the picker open rather than stranding a profile just created
|
||||
@@ -335,6 +333,9 @@ fun ActiveProfilePicker(
|
||||
updateShownConnection(updatedConn)
|
||||
}
|
||||
}
|
||||
// After the move, not before: the picker now stays open on failure, and clearing the
|
||||
// app-wide default there would leave it off with Incognito still ticked in the picker
|
||||
appPreferences.incognito.set(false)
|
||||
|
||||
controller.changeActiveUser_(
|
||||
rhId = user.remoteHostId,
|
||||
|
||||
@@ -188,6 +188,10 @@ Two hazards left as they are on master, so review does not keep re-raising them:
|
||||
profile first is local and fast and barely widens it. Fixing it needs a `ModalViewId`
|
||||
on the picker at both call sites, including `ShareListView`, which does not offer this
|
||||
feature at all.
|
||||
- `Terminal/Input.hs` caches any `CRActiveUser` as the remote host's current user. With
|
||||
`keepActiveUser` that response can carry a profile that is deliberately not active, so a
|
||||
CLI acting as a controller caches the wrong one until the next `/user`. Display-only,
|
||||
and there is no flag in the response to distinguish the two cases.
|
||||
- `alertAfterDismissal` waits a fixed 0.5s for a sheet transition rather than observing
|
||||
it. A slow device or a late-released interactive dismissal can still outlast it. The
|
||||
deterministic version needs the presenting controller's completion handler, which is
|
||||
|
||||
Reference in New Issue
Block a user