Application specific preferences saving now enabled.
This commit is contained in:
1 parent
f88e5b81a2
commit
60abcc37d9
23 files changed
+1004
-248
No files matched your search
@@ -5,11 +5,13 @@ package app
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
|
||||
"git.stormux.org/storm/fenrir/internal/applicationoverrides"
|
||||
"git.stormux.org/storm/fenrir/internal/applicationoverrides/networkmanager"
|
||||
"git.stormux.org/storm/fenrir/internal/applicationoverrides/ninjam"
|
||||
"git.stormux.org/storm/fenrir/internal/config"
|
||||
"git.stormux.org/storm/fenrir/internal/i18n"
|
||||
"git.stormux.org/storm/fenrir/internal/interaction"
|
||||
"git.stormux.org/storm/fenrir/internal/prompt"
|
||||
@@ -26,6 +28,9 @@ type overrideSnapshot struct {
|
||||
|
||||
type applicationOverride struct {
|
||||
id string
|
||||
path string
|
||||
base config.Settings
|
||||
profile *config.Document
|
||||
terminal int
|
||||
adapter applicationoverrides.Adapter
|
||||
underlying, temporary overrideSnapshot
|
||||
@@ -33,7 +38,59 @@ type applicationOverride struct {
|
||||
initialized, recognized, exitPending bool
|
||||
}
|
||||
|
||||
func (a *application) saves_unavailable() bool { return len(a.overrides) != 0 || a.overrideTransition }
|
||||
func (a *application) saves_unavailable() bool {
|
||||
return a.overrideTransition || a.overrideRestoreFailed || a.overrideFailed != nil || (a.overrideCurrent != nil && (!a.overrideCurrent.recognized || a.overrideCurrent.path == ""))
|
||||
}
|
||||
|
||||
func (a *application) settings_path() string {
|
||||
if a.overrideCurrent != nil {
|
||||
return a.overrideCurrent.path
|
||||
}
|
||||
return a.options.ConfigPath
|
||||
}
|
||||
|
||||
func (a *application) start_settings_save(path string, settings config.Settings) bool {
|
||||
if selected := a.overrideCurrent; selected != nil {
|
||||
base := selected.base
|
||||
return a.saver.start(a.ctx, settings, func() error {
|
||||
doc, err := config.Open_application_document(path, base)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return doc.Save(settings)
|
||||
})
|
||||
}
|
||||
return a.saver.save(a.ctx, path, settings)
|
||||
}
|
||||
|
||||
// Profile reads are bounded and run off the event loop, like settings writes.
|
||||
func (a *application) load_application_profile(selected *applicationOverride) {
|
||||
selected.base = config.Apply_application_settings(a.effective_settings(), a.settings_to_save())
|
||||
// Inherit the actual working selection, including startup fallback, rather
|
||||
// than unavailable saved voices or selections for a next-launch backend.
|
||||
copy_speech_selection(&selected.base.Presentation.Speech, a.settings.live.Presentation.Speech)
|
||||
selected.adapter.Configure(&selected.base)
|
||||
path, base := selected.path, selected.base
|
||||
a.overrideTransition = true
|
||||
go func() {
|
||||
doc, err := config.Open_application_document(path, base)
|
||||
select {
|
||||
case a.overrideLoads <- func() {
|
||||
a.overrideTransition = false
|
||||
if err != nil {
|
||||
selected.adapter.Close()
|
||||
delete(a.overrides, selected.terminal)
|
||||
a.voice.Say(i18n.Format("Could not load application settings: {0}", err.Error()))
|
||||
} else {
|
||||
selected.profile = doc
|
||||
selected.adapter.Reset()
|
||||
}
|
||||
a.overrideDirty = true
|
||||
}:
|
||||
case <-a.ctx.Done():
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (a *application) capture_override(terminal int) overrideSnapshot {
|
||||
settings := a.settings
|
||||
@@ -68,7 +125,7 @@ func (a *application) restore_override(done func()) bool {
|
||||
done()
|
||||
return true
|
||||
}
|
||||
if a.speechPending || a.overrideTransition || a.overrideRestoreFailed {
|
||||
if a.speechPending || a.saver.busy || a.overrideTransition || a.overrideRestoreFailed {
|
||||
return false
|
||||
}
|
||||
// A form opened under the application must never outlive that context:
|
||||
@@ -142,6 +199,9 @@ func (a *application) select_override(id string) {
|
||||
a.overrides = make(map[int]*applicationOverride)
|
||||
}
|
||||
selected := &applicationOverride{id: id, terminal: terminal, adapter: adapter}
|
||||
if a.options.ConfigPath != "" {
|
||||
selected.path = filepath.Join(filepath.Dir(a.options.ConfigPath), "applications", id+".toml")
|
||||
}
|
||||
selected.shell.Observe(a.lastSnapshot)
|
||||
a.overrides[terminal] = selected
|
||||
a.voice.Say(i18n.Format("{0} application override selected", i18n.T(adapter.Name())))
|
||||
@@ -151,7 +211,7 @@ func (a *application) select_override(id string) {
|
||||
// Called before reader.Update so exit detection and restored settings affect
|
||||
// the first shell snapshot, rather than interpreting it with the old adapter.
|
||||
func (a *application) observe_override(next screen.Snapshot) (applicationoverrides.Frame, bool) {
|
||||
if a.overrideTransition {
|
||||
if a.overrideTransition || (a.saver.busy && len(a.overrides) != 0) {
|
||||
return applicationoverrides.Frame{}, false
|
||||
}
|
||||
if a.overrideRestoreFailed {
|
||||
@@ -188,14 +248,42 @@ func (a *application) observe_override(next screen.Snapshot) (applicationoverrid
|
||||
return applicationoverrides.Frame{}, false
|
||||
}
|
||||
a.ui.close()
|
||||
if !selected.initialized && selected.profile == nil {
|
||||
a.load_application_profile(selected)
|
||||
return applicationoverrides.Frame{}, false
|
||||
}
|
||||
selected.underlying = a.capture_override(next.Terminal)
|
||||
if !selected.initialized {
|
||||
settings := a.effective_settings()
|
||||
selected.adapter.Configure(&settings)
|
||||
a.apply_remote_state(settings, false)
|
||||
a.configure_reader()
|
||||
a.engine.Clear_session_regions(next.Terminal)
|
||||
selected.initialized = true
|
||||
settings = selected.profile.Apply_application(settings)
|
||||
activate := func() {
|
||||
a.apply_remote_state(settings, false)
|
||||
a.settings.saveDraft, a.settings.resetBase = selected.profile.Settings, selected.profile.Settings
|
||||
a.settings.remoteFields = make(map[string]uint64)
|
||||
a.settings.remoteRevision = 0
|
||||
*a.quick = *new_quick_settings(settings.Presentation.Speech.Driver)
|
||||
a.configure_reader()
|
||||
a.engine.Clear_session_regions(next.Terminal)
|
||||
selected.initialized, selected.recognized = true, true
|
||||
a.overrideCurrent = selected
|
||||
}
|
||||
if !same_speech_selection(settings.Presentation.Speech, a.settings.live.Presentation.Speech) {
|
||||
a.overrideTransition = true
|
||||
a.change_speech(settings.Presentation.Speech, func(err error) {
|
||||
a.overrideTransition = false
|
||||
if err != nil {
|
||||
selected.adapter.Close()
|
||||
delete(a.overrides, selected.terminal)
|
||||
a.voice.Say(i18n.Format("Could not load application settings: {0}", err.Error()))
|
||||
return
|
||||
}
|
||||
activate()
|
||||
selected.adapter.Reset()
|
||||
})
|
||||
return applicationoverrides.Frame{}, false
|
||||
}
|
||||
activate()
|
||||
} else {
|
||||
// Numeric/runtime settings are synchronous. Speech selection is
|
||||
// restored separately before resuming a suspended adapter.
|
||||
|
||||
Reference in new issue
Block a user