Commit Graph
1 Commits
Author SHA1 Message Date
Kacper PaczosandGitHub a4bd398945 fix(settings): save the model only once the engine loaded it (#685)
* fix(settings): save the model only once the engine loaded it

Applying settings wrote the config first and reconfigured the engine
afterwards, and reconfiguring is what downloads a missing model. A
download that failed, was cancelled, or was interrupted therefore left
the config naming a model that never reached the disk: the next start
reported "No Speech Model" while the previously working model sat on
disk, deselected. Reconfigure first and persist only on success, so a
failed switch keeps the settings that are actually running.

On failure the pickers are put back on the saved model. They otherwise
kept showing the rejected one, which also blocked a retry, since
re-selecting the same entry emits no "changed" signal.

Selecting an engine now applies as well. Every other control on the page
applies on change, but the engine only repainted the pickers: the config
and the recognizer stayed on the previous engine until another control
was touched, and closing the dialog dropped the change without a word.
Remote API is deferred until its server URL is filled in, since applying
it empty can only fail validation.

* fix(settings): restore the engine picker after a failed engine switch

Fixes the known limitation called out in the previous commit (#692):
when applying a newly selected engine failed, the resync restored the
model pickers but left the engine combo displaying the engine that was
never applied, so the page described a state that was not running.

Set the combo back to the saved engine while holding the apply
suppression flag, so _on_engine_changed() repaints the pickers without
cascading into another apply or download prompt.

* fix(settings): resync the engine picker on every path that never applied

Review follow-ups on #685.

#692 was not actually closed. The resync lived only in the download
thread's except block, and _apply_settings_internal() reports failure by
returning False as well as by raising, so the thread fell through to
set_complete(True, "") and reported a switch that never happened. Act on
the return value instead of depending on #690 to make that except live,
and add the same handling to apply_settings()'s modal path, whose except
never resynced at all.

Add _resync_engine_ui_if_unapplied() as the backstop the review asked
for: after the modal closes, and when the dialog closes, compare the
engine on screen against the engine in the config and restore the picker
when they disagree. That also covers Remote API left without a server
URL, where applying stays deliberately deferred.

_on_engine_changed now checks _initializing / _applying_settings itself,
like every other control on this page, so the combo move made by a resync
repaints without rewriting the user's language or cascading into another
apply.

Tests no longer touch sys.modules at collection time: the reimport moved
into a module-scoped fixture that also restores the attribute on
vocalinux.ui, which is what desynced test_model_deletion on 3.9/3.10.
New cases cover the modal path that #692 is about — needs_download true
with the apply returning False, and with it raising "Download cancelled" —
plus the close hook. The stub now uses RecognitionState.IDLE rather than
the string "idle", so tests stop taking the stop_recognition branch and
sleeping 0.5s.
2026-08-26 23:59:37 -07:00