diff --git a/apps/ios/GuideDogs/Assets/Localization/en-US.lproj/Localizable.strings b/apps/ios/GuideDogs/Assets/Localization/en-US.lproj/Localizable.strings index db76031c4..6bff86011 100644 --- a/apps/ios/GuideDogs/Assets/Localization/en-US.lproj/Localizable.strings +++ b/apps/ios/GuideDogs/Assets/Localization/en-US.lproj/Localizable.strings @@ -416,6 +416,25 @@ /* Language display name. %1$@ is a language name, %2$@ is the country name. e.g. "English (United Kingdom)" {NumberedPlaceholder="%1$@", "%2$@"} */ "settings.language.language_name" = "%1$@ (%2$@)"; +/* Footer under “General” */ +"settings.section.general.footer" = "General settings for the app"; + +/* Footer under “Audio” (already existed): */ +"settings.audio.mix_with_others.description" = "Control how audio interacts with other media"; + +/* Footer under “Callouts” */ +"settings.callouts.footer" = "Manage the callouts that help navigate"; + +/* Footer under “Street Preview” (already existed): */ +"preview.include_unnamed_roads.subtitle" = "Settings for including unnamed roads"; + +/* Footer under “Troubleshooting” */ +"settings.section.troubleshooting.footer" = "Options for troubleshooting the app"; + +/* Footer under “About” */ +"settings.section.about.footer" = "Information about the app"; + + //------------------------------------------------------------------------------ // MARK: Settings (Audio) //------------------------------------------------------------------------------ @@ -1632,13 +1651,20 @@ /* Callouts Information, Nearby places like shops and restaurants */ "callouts.places_and_landmarks.info" = "Nearby places like shops and restaurants"; -/* Callouts Title, Mobility. Mobility: "The ability to move or be moved freely." */ +/* Mobility callout */ "callouts.mobility" = "Mobility"; +"callouts.mobility.info" = "Practical features like crosswalks and bus stops"; + +/* Safety callout */ +"callouts.safety" = "Safety"; +"callouts.safety.info" = "Potential hazards like steps and construction areas"; + +/* Intersections callout */ +"callouts.intersection" = "Intersections"; +"callouts.intersection.info" = "Announce street names and their directions"; -/* Callouts Information, Intersection and transportation information */ -"callouts.mobility.info" = "Intersection and transportation info"; -/* Title for a toggle under the Manage Callouts settings section. This toggle enables or disables periodic callouts that inform the user about their distance from the location of the audio beacon. */ +/* Title for a toggle under the Manage Callouts settings section. This toggle enables or disables periodic callouts that inform the user about their distance from the location of the audio beacon */ "callouts.audio_beacon" = "Distance to the Audio Beacon"; /* Callouts Information, Updates about didtance to the audio beacon when it's set */ diff --git a/apps/ios/GuideDogs/Code/Visual UI/Controls/Settings/CalloutSettingsCellView.swift b/apps/ios/GuideDogs/Code/Visual UI/Controls/Settings/CalloutSettingsCellView.swift index 8b6d09251..a1661f0b1 100644 --- a/apps/ios/GuideDogs/Code/Visual UI/Controls/Settings/CalloutSettingsCellView.swift +++ b/apps/ios/GuideDogs/Code/Visual UI/Controls/Settings/CalloutSettingsCellView.swift @@ -13,90 +13,83 @@ protocol CalloutSettingsCellViewDelegate: AnyObject { } internal enum CalloutSettingCellType { - case all, poi, mobility, beacon, shake + case all, poi, beacon, shake + case transportation + case intersection + case safety } class CalloutSettingsCellView: UITableViewCell { - + weak var delegate: CalloutSettingsCellViewDelegate? - + var type: CalloutSettingCellType! { didSet { guard let type = type, let settingSwitch = self.accessoryView as? UISwitch else { return } - - // Update the switch + settingSwitch.isEnabled = type == .all || SettingsContext.shared.automaticCalloutsEnabled - + switch type { case .all: settingSwitch.isOn = SettingsContext.shared.automaticCalloutsEnabled - return case .poi: settingSwitch.isOn = SettingsContext.shared.placeSenseEnabled - return - case .mobility: - settingSwitch.isOn = SettingsContext.shared.mobilitySenseEnabled - return case .beacon: settingSwitch.isOn = SettingsContext.shared.destinationSenseEnabled - return case .shake: settingSwitch.isOn = SettingsContext.shared.shakeCalloutsEnabled + case .transportation: + settingSwitch.isOn = SettingsContext.shared.mobilitySenseEnabled + case .intersection: + settingSwitch.isOn = SettingsContext.shared.intersectionSenseEnabled + case .safety: + settingSwitch.isOn = SettingsContext.shared.safetySenseEnabled } } } - + @IBAction func onSettingValueChanged(_ sender: Any) { guard let type = type, let settingSwitch = self.accessoryView as? UISwitch else { return } - - defer { - delegate?.onCalloutSettingChanged(type) - } - + + defer { delegate?.onCalloutSettingChanged(type) } + let isOn = settingSwitch.isOn - - let log: ([String]) -> Void = { (categories: [String]) in + + let log: ([String]) -> Void = { categories in for category in categories { GDLogActionInfo("Toggled \(category) callouts to: \(isOn)") - GDATelemetry.track("settings.autocallouts_\(category)", value: isOn.description) } } - + switch type { case .all: SettingsContext.shared.automaticCalloutsEnabled = isOn GDATelemetry.track("settings.allow_callouts", value: isOn.description) - return - case .poi: - // Places, Landmark, and Information Senses SettingsContext.shared.placeSenseEnabled = isOn SettingsContext.shared.landmarkSenseEnabled = isOn SettingsContext.shared.informationSenseEnabled = isOn log(["places", "landmarks", "info"]) - return - - case .mobility: - // Mobility, Safety, and Intersection Sense - SettingsContext.shared.mobilitySenseEnabled = isOn - SettingsContext.shared.safetySenseEnabled = isOn - SettingsContext.shared.intersectionSenseEnabled = isOn - log(["mobility", "safety", "intersections"]) - return - case .beacon: - // Destination sense SettingsContext.shared.destinationSenseEnabled = isOn log(["destination"]) - return case .shake: SettingsContext.shared.shakeCalloutsEnabled = isOn GDATelemetry.track("settings.shake_callouts", value: isOn.description) + case .transportation: + SettingsContext.shared.mobilitySenseEnabled = isOn + log(["mobility"]) + case .intersection: + SettingsContext.shared.intersectionSenseEnabled = isOn + log(["intersections"]) + case .safety: + SettingsContext.shared.safetySenseEnabled = isOn + log(["safety"]) } } } diff --git a/apps/ios/GuideDogs/Code/Visual UI/View Controllers/Settings/SettingsViewController.swift b/apps/ios/GuideDogs/Code/Visual UI/View Controllers/Settings/SettingsViewController.swift index d5e5ef20c..69cd80394 100644 --- a/apps/ios/GuideDogs/Code/Visual UI/View Controllers/Settings/SettingsViewController.swift +++ b/apps/ios/GuideDogs/Code/Visual UI/View Controllers/Settings/SettingsViewController.swift @@ -22,11 +22,13 @@ class SettingsViewController: BaseTableViewController { } private enum CalloutsRow: Int, CaseIterable { - case all = 0 - case poi = 1 - case mobility = 2 - case beacon = 3 - case shake = 4 + case all = 0 + case poi = 1 + case mobility = 2 + case safety = 3 + case intersection = 4 + case beacon = 5 + case shake = 6 } private static let cellIdentifiers: [IndexPath: String] = [ @@ -39,11 +41,14 @@ class SettingsViewController: BaseTableViewController { IndexPath(row: 0, section: Section.audio.rawValue): "mixAudio", - IndexPath(row: CalloutsRow.all.rawValue, section: Section.callouts.rawValue): "allCallouts", - IndexPath(row: CalloutsRow.poi.rawValue, section: Section.callouts.rawValue): "poiCallouts", - IndexPath(row: CalloutsRow.mobility.rawValue, section: Section.callouts.rawValue): "mobilityCallouts", - IndexPath(row: CalloutsRow.beacon.rawValue, section: Section.callouts.rawValue): "beaconCallouts", - IndexPath(row: CalloutsRow.shake.rawValue, section: Section.callouts.rawValue): "shakeCallouts", + // Callouts + IndexPath(row: CalloutsRow.all.rawValue, section: Section.callouts.rawValue): "allCallouts", + IndexPath(row: CalloutsRow.poi.rawValue, section: Section.callouts.rawValue): "poiCallouts", + IndexPath(row: CalloutsRow.mobility.rawValue, section: Section.callouts.rawValue): "mobilityCallouts", + IndexPath(row: CalloutsRow.safety.rawValue, section: Section.callouts.rawValue): "safetyCallouts", + IndexPath(row: CalloutsRow.intersection.rawValue,section: Section.callouts.rawValue): "intersectionCallouts", + IndexPath(row: CalloutsRow.beacon.rawValue, section: Section.callouts.rawValue): "beaconCallouts", + IndexPath(row: CalloutsRow.shake.rawValue, section: Section.callouts.rawValue): "shakeCallouts", IndexPath(row: 0, section: Section.streetPreview.rawValue): "streetPreview", IndexPath(row: 0, section: Section.troubleshooting.rawValue): "troubleshooting", @@ -52,11 +57,14 @@ class SettingsViewController: BaseTableViewController { ] private static let collapsibleCalloutIndexPaths: [IndexPath] = [ - IndexPath(row: CalloutsRow.poi.rawValue, section: Section.callouts.rawValue), - IndexPath(row: CalloutsRow.mobility.rawValue, section: Section.callouts.rawValue), - IndexPath(row: CalloutsRow.beacon.rawValue, section: Section.callouts.rawValue), - IndexPath(row: CalloutsRow.shake.rawValue, section: Section.callouts.rawValue) + IndexPath(row: CalloutsRow.poi.rawValue, section: Section.callouts.rawValue), + IndexPath(row: CalloutsRow.mobility.rawValue, section: Section.callouts.rawValue), + IndexPath(row: CalloutsRow.safety.rawValue, section: Section.callouts.rawValue), + IndexPath(row: CalloutsRow.intersection.rawValue,section: Section.callouts.rawValue), + IndexPath(row: CalloutsRow.beacon.rawValue, section: Section.callouts.rawValue), + IndexPath(row: CalloutsRow.shake.rawValue, section: Section.callouts.rawValue) ] + // MARK: Properties @@ -84,7 +92,10 @@ class SettingsViewController: BaseTableViewController { switch sectionType { case .general: return 6 case .audio: return 1 - case .callouts: return SettingsContext.shared.automaticCalloutsEnabled ? 5 : 1 + case .callouts: + return SettingsContext.shared.automaticCalloutsEnabled + ? CalloutsRow.allCases.count + : 1 case .streetPreview: return 1 case .troubleshooting: return 1 case .about: return 1 @@ -101,20 +112,14 @@ class SettingsViewController: BaseTableViewController { switch sectionType { case .callouts: - let cell = tableView.dequeueReusableCell(withIdentifier: identifier ?? "default", for: indexPath) as! CalloutSettingsCellView - cell.delegate = self + let cell = tableView.dequeueReusableCell( + withIdentifier: identifier ?? "default", + for: indexPath) as! CalloutSettingsCellView - if let rowType = CalloutsRow(rawValue: indexPath.row) { - switch rowType { - case .all: cell.type = .all - case .poi: cell.type = .poi - case .mobility: cell.type = .mobility - case .beacon: cell.type = .beacon - case .shake: cell.type = .shake - } - } + configureCalloutCell(cell, at: indexPath) return cell + // case .telemetry: // let cell = tableView.dequeueReusableCell(withIdentifier: identifier ?? "default", for: indexPath) as! TelemetrySettingsTableViewCell @@ -134,6 +139,20 @@ class SettingsViewController: BaseTableViewController { } // MARK: UITableViewDataSource + private func configureCalloutCell(_ cell: CalloutSettingsCellView, + at indexPath: IndexPath) { + cell.delegate = self + guard let rowType = CalloutsRow(rawValue: indexPath.row) else { return } + switch rowType { + case .all: cell.type = .all + case .poi: cell.type = .poi + case .mobility: cell.type = .transportation + case .safety: cell.type = .safety + case .intersection: cell.type = .intersection + case .beacon: cell.type = .beacon + case .shake: cell.type = .shake + } + } override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { guard let sectionType = Section(rawValue: section) else { return nil } diff --git a/apps/ios/GuideDogs/Code/Visual UI/Views/Settings.storyboard b/apps/ios/GuideDogs/Code/Visual UI/Views/Settings.storyboard index ebc77e8fb..f1a41f979 100644 --- a/apps/ios/GuideDogs/Code/Visual UI/Views/Settings.storyboard +++ b/apps/ios/GuideDogs/Code/Visual UI/Views/Settings.storyboard @@ -1,9 +1,8 @@ - + - - + @@ -284,8 +283,8 @@ -