// Fenrir console screen reader. // Copyright (c) 2026 Storm Dragon // SPDX-License-Identifier: GPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the Free // Software Foundation, either version 3 of the License, or (at your option) // any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with // this program. If not, see . package app import ( "time" "git.stormux.org/storm/fenrir/internal/diagnostic" "git.stormux.org/storm/fenrir/internal/i18n" "git.stormux.org/storm/fenrir/internal/presentation" ) func (a *application) play(cue presentation.Cue) bool { if a.settings.live.Presentation.Sound.Enabled && a.cues != nil && cue != "" { return a.cues.Play(cue) } return false } func (a *application) present(text string, cue presentation.Cue) { if !a.play(cue) && !a.temporarySilence { a.voice.Say(text) } } func (a *application) present_speech_state() { if a.muted { a.play(presentation.SpeechOff) } else { a.present(i18n.T("speech enabled"), presentation.SpeechOn) } } func (a *application) present_indentation(message presentation.Message) { if a.temporarySilence || a.muted { return } accepted := false if message.Indentation != nil && a.settings.live.Presentation.Sound.Enabled && a.settings.live.Presentation.Sound.Volume > 0 && a.cues != nil { accepted = a.cues.Play_indentation(message.Indentation.Level) } if !accepted || message.Indentation.Speech { a.voice.Say(message.Text) } } func (a *application) present_attributes(message presentation.Message) { if a.temporarySilence || a.muted { return } accepted := message.Cue != "" && a.settings.live.Presentation.Sound.Volume > 0 && a.play(message.Cue) if !accepted || message.Attributes.Speech { a.voice.Say(message.Text) } } func (a *application) play_progress() { if a.ui.active { a.engine.Reset_progress() } if a.cues != nil { if a.ui.active { a.cues.Clear_progress() } else if !a.engine.Progress_active() { // A passive redraw can reset detection halfway through a beep. // Discard stale waiting tones, but let the current one finish. a.cues.Discard_progress() } } if !a.ui.active && a.settings.live.Presentation.Sound.Enabled && a.cues != nil { if value, ok := a.engine.Next_progress(time.Now()); ok { if a.cues.Play_progress(value) { diagnostic.Record("progress tone", "percentage", value) } } } }