Skip to content

Add Manage Callouts toggles for sound effects and delays - #247

Open
MBtheOtaku wants to merge 1 commit into
soundscape-community:mainfrom
MBtheOtaku:setting_delay
Open

Add Manage Callouts toggles for sound effects and delays#247
MBtheOtaku wants to merge 1 commit into
soundscape-community:mainfrom
MBtheOtaku:setting_delay

Conversation

@MBtheOtaku

@MBtheOtaku MBtheOtaku commented Mar 13, 2026

Copy link
Copy Markdown
Contributor

Adds two new settings under Manage Callouts: Sound Effects and Delays. Persists both toggles in app settings with defaults enabled. Wires settings UI logic to surface and handle the new switches alongside existing callout options. Applies Sound Effects toggle to callout prefix/earcon behavior in automatic destination/intersection/POI paths. Applies Delays toggle to automatic callout spacing by enabling/disabling callout delay timing. Adds new en-US localization keys for the new toggle labels and helper text. Keeps existing Allow Callouts collapse behavior intact while including the new rows when enabled

Summary by CodeRabbit

  • New Features
    • Introduced two new configurable callout settings:
      • Sound Effects: Enable or disable audio cues before spoken callouts
      • Delays: Enable or disable short pauses between automatic callouts
    • Both settings default to enabled and are accessible in the app's settings interface

Adds two new settings under Manage Callouts: Sound Effects and Delays.
Persists both toggles in app settings with defaults enabled.
Wires settings UI logic to surface and handle the new switches alongside existing callout options.
Applies Sound Effects toggle to callout prefix/earcon behavior in automatic destination/intersection/POI paths.
Applies Delays toggle to automatic callout spacing by enabling/disabling callout delay timing.
Adds new en-US localization keys for the new toggle labels and helper text.
Keeps existing Allow Callouts collapse behavior intact while including the new rows when enabled
@coderabbitai

coderabbitai Bot commented Mar 13, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR adds configurable sound effects and delay settings for callouts throughout the iOS app. It introduces new localization entries, expands the settings protocol and storage layer, integrates these settings into callout generators, updates callout models to conditionally apply prefix sounds, and extends the settings UI with new toggle options.

Changes

Cohort / File(s) Summary
Localization
apps/ios/GuideDogs/Assets/Localization/en-US.lproj/Localizable.strings
Added four new localization entries for callout sound effects and delays toggles, including label and description strings.
Settings Protocol & Storage
apps/ios/GuideDogs/Code/App/Settings/AutoCalloutSettingsProvider.swift, apps/ios/GuideDogs/Code/App/Settings/SettingsContext.swift
Added calloutSoundEffectsEnabled and calloutDelaysEnabled as new properties to the settings protocol and implemented storage via UserDefaults with corresponding keys, both defaulting to true.
Callout Generators
apps/ios/GuideDogs/Code/Behaviors/Default/AutoCalloutGenerator.swift, apps/ios/GuideDogs/Code/Behaviors/Default/BeaconCalloutGenerator.swift, apps/ios/GuideDogs/Code/Behaviors/Default/IntersectionGenerator.swift
Integrated new settings into callout generation: added defaultCalloutDelay and computed calloutDelay property; updated all callout construction sites to pass includePrefixSound parameter driven by settings.calloutSoundEffectsEnabled.
Callout Models
apps/ios/GuideDogs/Code/Behaviors/Default/Callouts/DestinationCallout.swift, apps/ios/GuideDogs/Code/Behaviors/Default/Callouts/IntersectionCallout.swift
Made includePrefixSound configurable in both callout types by converting from hardcoded constant to initializer parameter (default true), allowing dynamic control over prefix sound inclusion.
Settings UI
apps/ios/GuideDogs/Code/Visual UI/Controls/Settings/CalloutSettingsCellView.swift, apps/ios/GuideDogs/Code/Visual UI/View Controllers/Settings/SettingsViewController.swift
Expanded CalloutSettingCellType and CalloutsRow enums to include soundEffects and delays cases; refactored SettingsViewController to use dynamic cell generation with new helper methods for mapping enum cases to cell configurations; added telemetry keys for new settings.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • RDMurray

Poem

🐰 Hops of joy! The callout symphony now dances to the beat—
Sounds can hush, delays can pause, all tuned to users' neat!
Settings bloom with switches bright, from UI down to core,
Each callout type now sings with choice—what could a rabbit ask for? 🎵

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add Manage Callouts toggles for sound effects and delays' directly and clearly describes the main change: introducing two new UI toggles for sound effects and delays in the Manage Callouts settings. It is concise, specific, and accurately reflects the primary purpose of the changeset across all modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/ios/GuideDogs/Code/Visual UI/View Controllers/Settings/SettingsViewController.swift (1)

46-60: ⚠️ Potential issue | 🔴 Critical

allCases.count now exposes rows that still have no valid cell path.

Line 108 makes the callouts section return every CalloutsRow, but the dynamic path only creates cells for .soundEffects and .delays. When .safety or .intersection is requested, identifier falls back to "default" and Line 141 force-casts that cell to CalloutSettingsCellView, which will crash unless those rows get real reuse IDs or programmatic creation too.

Also applies to: 102-143

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ios/GuideDogs/Code/Visual` UI/View
Controllers/Settings/SettingsViewController.swift around lines 46 - 60, The
callouts mapping in cellIdentifiers and the table data source are out of sync:
CalloutsRow.allCases is being used to report rows but cellIdentifiers only
supplies reuse IDs for .soundEffects and .delays, so asking for .safety or
.intersection yields "default" and the force-cast to CalloutSettingsCellView
will crash; fix by either (A) adding explicit reuse identifiers for the missing
CalloutsRow cases in the cellIdentifiers dictionary (use the same reuse IDs you
register) or (B) change the callouts section row count (the method returning
numberOfRows for Section.callouts) to only return the rows you create, and/or
make the dequeue logic in tableView(_:cellForRowAt:) (where identifier and the
force-cast to CalloutSettingsCellView occur) safely handle unknown identifiers
by returning a properly registered default cell instead of force-casting. Ensure
the symbols affected are cellIdentifiers, CalloutsRow, numberOfRows/section
logic, identifier resolution, and the CalloutSettingsCellView dequeue/cast.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/ios/GuideDogs/Code/Behaviors/Default/Callouts/DestinationCallout.swift`:
- Around line 55-60: The beacon/geofence earcon is still played unconditionally;
update the playback sites (within DestinationCallout where
GlyphSound(.beaconFound) is invoked, around the logic covering lines ~66–115) to
respect the callout flags by only playing the earcon when causedAudioDisabled is
false (and if applicable also respect includePrefixSound) — i.e., wrap the
GlyphSound(.beaconFound) playback call in a conditional that checks
!self.causedAudioDisabled (and includePrefixSound when that flag controls prefix
sounds) so the sound-effects toggle on the callout is honored.

In `@apps/ios/GuideDogs/Code/Visual`
UI/Controls/Settings/CalloutSettingsCellView.swift:
- Around line 15-23: The CalloutSettingCellType enum still contains merge
markers and is out of sync with SettingsViewController; replace the conflicted
enum with a final set of cases that matches the controller (include all,
soundEffects, delays, poi, beacon, shake, transportation, intersection, safety
and remove/replace .mobility), then update both switch statements that read and
write settings (the "read" switch and the "write" switch that reference
CalloutSettingCellType) to handle every new case and map any old .mobility
usages to the appropriate new case (likely .transportation) so all switch arms
are exhaustive and compilation warnings/errors are resolved; ensure switch
defaults are removed or adjusted so SettingsViewController’s routing
(.transportation, .safety, .intersection) is honored.

In `@apps/ios/GuideDogs/Code/Visual` UI/View
Controllers/Settings/SettingsViewController.swift:
- Around line 24-43: Remove all merge conflict markers and reconcile the two
CalloutsRow variants so the enum is defined once (prefer the stashed expanded
list if those rows are used elsewhere) by updating private enum CalloutsRow:
Int, CaseIterable to contain the correct cases (e.g., all, soundEffects, delays,
poi, mobility, safety, intersection, beacon, shake) and ensure no
duplicate/conflicting definitions remain; then edit the Section enum to either
remove any reference to case .telemetry or re-add a matching telemetry case (and
its associated logic) so references to .telemetry compile; finally build to
verify there are no remaining conflict markers or undefined enum cases in
SettingsViewController.

---

Outside diff comments:
In `@apps/ios/GuideDogs/Code/Visual` UI/View
Controllers/Settings/SettingsViewController.swift:
- Around line 46-60: The callouts mapping in cellIdentifiers and the table data
source are out of sync: CalloutsRow.allCases is being used to report rows but
cellIdentifiers only supplies reuse IDs for .soundEffects and .delays, so asking
for .safety or .intersection yields "default" and the force-cast to
CalloutSettingsCellView will crash; fix by either (A) adding explicit reuse
identifiers for the missing CalloutsRow cases in the cellIdentifiers dictionary
(use the same reuse IDs you register) or (B) change the callouts section row
count (the method returning numberOfRows for Section.callouts) to only return
the rows you create, and/or make the dequeue logic in tableView(_:cellForRowAt:)
(where identifier and the force-cast to CalloutSettingsCellView occur) safely
handle unknown identifiers by returning a properly registered default cell
instead of force-casting. Ensure the symbols affected are cellIdentifiers,
CalloutsRow, numberOfRows/section logic, identifier resolution, and the
CalloutSettingsCellView dequeue/cast.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 39ff5367-8a36-4312-ab03-18ad006dc9ee

📥 Commits

Reviewing files that changed from the base of the PR and between ad9793a and 5fb7dd5.

📒 Files selected for processing (10)
  • apps/ios/GuideDogs/Assets/Localization/en-US.lproj/Localizable.strings
  • apps/ios/GuideDogs/Code/App/Settings/AutoCalloutSettingsProvider.swift
  • apps/ios/GuideDogs/Code/App/Settings/SettingsContext.swift
  • apps/ios/GuideDogs/Code/Behaviors/Default/AutoCalloutGenerator.swift
  • apps/ios/GuideDogs/Code/Behaviors/Default/BeaconCalloutGenerator.swift
  • apps/ios/GuideDogs/Code/Behaviors/Default/Callouts/DestinationCallout.swift
  • apps/ios/GuideDogs/Code/Behaviors/Default/Callouts/IntersectionCallout.swift
  • apps/ios/GuideDogs/Code/Behaviors/Default/IntersectionGenerator.swift
  • apps/ios/GuideDogs/Code/Visual UI/Controls/Settings/CalloutSettingsCellView.swift
  • apps/ios/GuideDogs/Code/Visual UI/View Controllers/Settings/SettingsViewController.swift

Comment on lines +55 to 60
init(_ calloutOrigin: CalloutOrigin, _ entityKey: String, _ causedAudioDisabled: Bool = false, includePrefixSound: Bool = true) {
self.origin = calloutOrigin
self.entityKey = entityKey
self.causedAudioDisabled = causedAudioDisabled
self.includePrefixSound = includePrefixSound
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Apply the sound-effects toggle to the beacon-geofence earcon too.

The new flag is stored on the callout, but Line 94 still plays GlyphSound(.beaconFound) unconditionally when causedAudioDisabled is true. With Sound Effects turned off, that automatic destination path will still emit an earcon.

Suggested fix
         if causedAudioDisabled {
-            let earcon = GlyphSound(.beaconFound)
             var text = GDLocalizedString("beacon.beacon_location_within_audio_beacon_muted", formattedDistance)
             // Append suggestion to launch NaviLens if available at location
             if (poi != nil) && LocationDetail(entity: poi!).source.hasNaviLens {
                 text += " " + GDLocalizedString("beacon.suggest_navilens")
             }
             let tts = TTSSound(text, at: markerLocation)
+
+            guard includePrefixSound else {
+                return Sounds(tts)
+            }
+
+            let earcon = GlyphSound(.beaconFound)
             
             guard let layered = LayeredSound(earcon, tts) else {
                 return Sounds([earcon, tts])
             }

Also applies to: 66-115

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ios/GuideDogs/Code/Behaviors/Default/Callouts/DestinationCallout.swift`
around lines 55 - 60, The beacon/geofence earcon is still played
unconditionally; update the playback sites (within DestinationCallout where
GlyphSound(.beaconFound) is invoked, around the logic covering lines ~66–115) to
respect the callout flags by only playing the earcon when causedAudioDisabled is
false (and if applicable also respect includePrefixSound) — i.e., wrap the
GlyphSound(.beaconFound) playback call in a conditional that checks
!self.causedAudioDisabled (and includePrefixSound when that flag controls prefix
sounds) so the sound-effects toggle on the callout is honored.

Comment on lines 15 to +23
internal enum CalloutSettingCellType {
<<<<<<< Updated upstream
case all, poi, mobility, beacon, shake
=======
case all, soundEffects, delays, poi, beacon, shake
case transportation
case intersection
case safety
>>>>>>> Stashed changes

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e

file='apps/ios/GuideDogs/Code/Visual UI/Controls/Settings/CalloutSettingsCellView.swift'
controller='apps/ios/GuideDogs/Code/Visual UI/View Controllers/Settings/SettingsViewController.swift'

echo "Conflict markers in the cell view:"
rg -n '^(<<<<<<<|=======|>>>>>>>)' "$file"

echo
echo "Callout setting cases referenced by the cell view and controller:"
rg -n '\.(all|soundEffects|delays|poi|mobility|transportation|safety|intersection|beacon|shake)\b' "$file" "$controller"

Repository: soundscape-community/soundscape

Length of output: 6958


🏁 Script executed:

cat -n 'apps/ios/GuideDogs/Code/Visual UI/Controls/Settings/CalloutSettingsCellView.swift' | sed -n '10,130p'

Repository: soundscape-community/soundscape

Length of output: 5050


Finish the merge resolution and synchronize the enum with its switches.

The file contains unresolved merge conflicts at lines 16–23 (enum), 42–49 (read switch), and 88–98 (write switch). After resolution, line 53 references .mobility, while SettingsViewController.swift routes .transportation, .safety, and .intersection as separate cell types (lines 189–195). The enum definition and both switch statements must be aligned to match the controller's expectations. The file will not compile until conflicts are resolved and cases are synchronized.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ios/GuideDogs/Code/Visual`
UI/Controls/Settings/CalloutSettingsCellView.swift around lines 15 - 23, The
CalloutSettingCellType enum still contains merge markers and is out of sync with
SettingsViewController; replace the conflicted enum with a final set of cases
that matches the controller (include all, soundEffects, delays, poi, beacon,
shake, transportation, intersection, safety and remove/replace .mobility), then
update both switch statements that read and write settings (the "read" switch
and the "write" switch that reference CalloutSettingCellType) to handle every
new case and map any old .mobility usages to the appropriate new case (likely
.transportation) so all switch arms are exhaustive and compilation
warnings/errors are resolved; ensure switch defaults are removed or adjusted so
SettingsViewController’s routing (.transportation, .safety, .intersection) is
honored.

Comment on lines +24 to +43
<<<<<<< Updated upstream
private enum CalloutsRow: Int, CaseIterable {
case all = 0
case poi = 1
case mobility = 2
case beacon = 3
case shake = 4
=======
/// Rows in the "Callouts" section
private enum CalloutsRow: Int, CaseIterable {
case all = 0
case soundEffects = 1
case delays = 2
case poi = 3
case mobility = 4
case safety = 5
case intersection = 6
case beacon = 7
case shake = 8
>>>>>>> Stashed changes

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e

file='apps/ios/GuideDogs/Code/Visual UI/View Controllers/Settings/SettingsViewController.swift'

echo "Conflict markers and likely compile blockers:"
rg -n '^(<<<<<<<|=======|>>>>>>>)|case \.telemetry|identifier \?\?' "$file"

echo
echo "Relevant excerpt:"
sed -n '24,170p' "$file"

Repository: soundscape-community/soundscape

Length of output: 7433


🏁 Script executed:

rg -n 'enum Section' apps/ios/GuideDogs/Code/Visual\ UI/View\ Controllers/Settings/SettingsViewController.swift -A 15

Repository: soundscape-community/soundscape

Length of output: 537


Resolve merge conflicts; do not merge the .telemetry case reference.

This file contains multiple unresolved merge conflict markers (lines 24, 68, 123, 145, 168) preventing compilation. Beyond those, line 150 references case .telemetry: in the Section enum, but .telemetry is commented out and not an active case—this causes a compile error in the stashed version. The file must have conflicts resolved and the .telemetry case removed or properly defined before this can build.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ios/GuideDogs/Code/Visual` UI/View
Controllers/Settings/SettingsViewController.swift around lines 24 - 43, Remove
all merge conflict markers and reconcile the two CalloutsRow variants so the
enum is defined once (prefer the stashed expanded list if those rows are used
elsewhere) by updating private enum CalloutsRow: Int, CaseIterable to contain
the correct cases (e.g., all, soundEffects, delays, poi, mobility, safety,
intersection, beacon, shake) and ensure no duplicate/conflicting definitions
remain; then edit the Section enum to either remove any reference to case
.telemetry or re-add a matching telemetry case (and its associated logic) so
references to .telemetry compile; finally build to verify there are no remaining
conflict markers or undefined enum cases in SettingsViewController.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant