mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-08-14 07:10:19 +00:00
Follow-up to the previous commit, which fixed the centre-pane placement by moving the form to the picker's own pane. That was wrong in two different ways, and the shared modal helpers it changed had a blast radius that was not accounted for. Placement. ModalManager.end, used for the compose picker, puts the form in a pane *beside* the chat: the picker stays fully live next to it, with no scrim, so a profile can be selected while the form is open - and apiChangeConnectionUser recreates the connection, invalidating the id the form is about to use. It also calls desktopExpandWindowToWidth, which is grow-only, so the window is permanently widened. ModalManager.start, used for the one-time link picker, does cover it, but disposes it, losing whatever was typed in its search box. ModalManager.fullscreen is an opaque Surface over every pane: nothing can be operated while the form is up, nothing is torn down, chatId is untouched and the window does not move. The manager is no longer a parameter - there is only one right answer. Modal helpers. hasModalOpen/isLastModalOpen were taught to ignore modals waiting out their close animation, but they have five other callers - ChatListView, ChatView twice, ChatItemView and SimpleXAPI - all deciding when to tear down secondary chats, and all silently changed by it. isLastModalOpen also went from an indexed read to a full iteration on a path called off the main thread. Both are reverted; the new behaviour lives in isLastModalOpenNotClosing, which only this flow calls and which walks by index. Main thread. Making onCreated suspending moved the reassignment onto withBGApi's single-thread dispatcher, so changeProfileTo mutated chatsContext, chatId and (via changeActiveUser_) chatModel.users off Main, where the receiver loop writes the same structures - the very hazard the same commit called out for its own users refresh. onCreated and close() are now handed back to Dispatchers.Main, which is where both pickers ran this before it became a callback. Also: the in-flight flag moves to ChatModel so it is not a top-level val first created inside a composition; the entry guard consults it, since with one manager per pane the per-manager check alone let a second form open and silently drop its submit; the one-time link picker's filteredProfiles is keyed on the profile count, so a profile created from it appears without relying on the composition being rebuilt; and the progress indicator skips its 500ms grace while creating, since that timer restarts from zero in the rebuilt composition and would otherwise leave the rows looking idle.