mirror of
https://codeberg.org/comaps/comaps
synced 2025-12-21 22:03:37 +00:00
[ios] Display navigation voice and change instructions in settings
Signed-off-by: Yannik Bloscheck <git@yannikbloscheck.com>
This commit is contained in:
committed by
Yannik Bloscheck
parent
96d51dfcf9
commit
053f35b519
@@ -1,8 +1,10 @@
|
|||||||
#import "MWMTextToSpeechObserver.h"
|
#import "MWMTextToSpeechObserver.h"
|
||||||
|
#import <AVFoundation/AVFoundation.h>
|
||||||
|
|
||||||
@interface MWMTextToSpeech : NSObject
|
@interface MWMTextToSpeech : NSObject
|
||||||
|
|
||||||
+ (MWMTextToSpeech *)tts;
|
+ (MWMTextToSpeech *)tts;
|
||||||
|
- (AVSpeechSynthesisVoice *)voice;
|
||||||
+ (BOOL)isTTSEnabled;
|
+ (BOOL)isTTSEnabled;
|
||||||
+ (void)setTTSEnabled:(BOOL)enabled;
|
+ (void)setTTSEnabled:(BOOL)enabled;
|
||||||
+ (BOOL)isStreetNamesTTSEnabled;
|
+ (BOOL)isStreetNamesTTSEnabled;
|
||||||
|
|||||||
@@ -134,7 +134,10 @@ using Observers = NSHashTable<Observer>;
|
|||||||
[ud setObject:locale forKey:kUserDefaultsTTSLanguageBcp47];
|
[ud setObject:locale forKey:kUserDefaultsTTSLanguageBcp47];
|
||||||
[self createVoice:locale];
|
[self createVoice:locale];
|
||||||
}
|
}
|
||||||
|
- (AVSpeechSynthesisVoice *)voice {
|
||||||
|
[self createVoice:[[self class] savedLanguage]];
|
||||||
|
return self.speechVoice;
|
||||||
|
}
|
||||||
- (BOOL)isValid { return _speechSynthesizer != nil && _speechVoice != nil; }
|
- (BOOL)isValid { return _speechSynthesizer != nil && _speechVoice != nil; }
|
||||||
+ (BOOL)isTTSEnabled { return [NSUserDefaults.standardUserDefaults boolForKey:kIsTTSEnabled]; }
|
+ (BOOL)isTTSEnabled { return [NSUserDefaults.standardUserDefaults boolForKey:kIsTTSEnabled]; }
|
||||||
+ (void)setTTSEnabled:(BOOL)enabled {
|
+ (void)setTTSEnabled:(BOOL)enabled {
|
||||||
|
|||||||
@@ -539,6 +539,12 @@
|
|||||||
"editor_report_problem_send_button" = "Send";
|
"editor_report_problem_send_button" = "Send";
|
||||||
"autodownload" = "Auto-download maps";
|
"autodownload" = "Auto-download maps";
|
||||||
|
|
||||||
|
/* Voice */
|
||||||
|
"voice" = "Voice";
|
||||||
|
"voice_explanation" = "It's possible to pick a better voice in the system settings under *Accesibility*, *Read & Speak*, *Voices*.";
|
||||||
|
"voice_explanation_before_version26" = "It's possible to pick a better voice in the system settings under *Accesibility*, *Spoken Content*, *Voices*.";
|
||||||
|
"unknown" = "Unknown";
|
||||||
|
|
||||||
/* Place page confirmation messages and time ago formatting */
|
/* Place page confirmation messages and time ago formatting */
|
||||||
"existence_confirmed_time_ago" = "Existence confirmed %@";
|
"existence_confirmed_time_ago" = "Existence confirmed %@";
|
||||||
"hours_confirmed_time_ago" = "Confirmed %@";
|
"hours_confirmed_time_ago" = "Confirmed %@";
|
||||||
|
|||||||
@@ -558,7 +558,11 @@
|
|||||||
"editor_report_problem_send_button" = "Send";
|
"editor_report_problem_send_button" = "Send";
|
||||||
"autodownload" = "Auto-download maps";
|
"autodownload" = "Auto-download maps";
|
||||||
|
|
||||||
|
/* Voice */
|
||||||
|
"voice" = "Voice";
|
||||||
|
"voice_explanation" = "It's possible to pick a better voice in the system settings under *Accesibility*, *Read & Speak*, *Voices*.";
|
||||||
|
"voice_explanation_before_version26" = "It's possible to pick a better voice in the system settings under *Accesibility*, *Spoken Content*, *Voices*.";
|
||||||
|
"unknown" = "Unknown";
|
||||||
|
|
||||||
/* Place page confirmation messages and time ago formatting */
|
/* Place page confirmation messages and time ago formatting */
|
||||||
"existence_confirmed_time_ago" = "Existence confirmed %@";
|
"existence_confirmed_time_ago" = "Existence confirmed %@";
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import Combine
|
import Combine
|
||||||
|
import AVFoundation
|
||||||
|
|
||||||
/// The settings
|
/// The settings
|
||||||
@objc class Settings: NSObject {
|
@objc class Settings: NSObject {
|
||||||
@@ -325,6 +326,16 @@ import Combine
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// The voice used for voice guidance during routing
|
||||||
|
@objc static var voiceForVoiceRouting: String? {
|
||||||
|
if let voice = MWMTextToSpeech.tts().voice() {
|
||||||
|
return voice.name
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// If street names should be announced in the voice guidance during routing
|
/// If street names should be announced in the voice guidance during routing
|
||||||
@objc static var shouldAnnounceStreetnamesWhileVoiceRouting: Bool {
|
@objc static var shouldAnnounceStreetnamesWhileVoiceRouting: Bool {
|
||||||
get {
|
get {
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ import SwiftUI
|
|||||||
struct SettingsNavigationView: View {
|
struct SettingsNavigationView: View {
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
|
|
||||||
|
/// The scene phase of the environment
|
||||||
|
@Environment(\.scenePhase) private var scenePhase
|
||||||
|
|
||||||
|
|
||||||
/// If the perspective view should be used during routing
|
/// If the perspective view should be used during routing
|
||||||
@State var hasPerspectiveViewWhileRouting: Bool = true
|
@State var hasPerspectiveViewWhileRouting: Bool = true
|
||||||
|
|
||||||
@@ -48,6 +52,10 @@ struct SettingsNavigationView: View {
|
|||||||
@State var shouldAvoidStepsWhileRouting: Bool = false
|
@State var shouldAvoidStepsWhileRouting: Bool = false
|
||||||
|
|
||||||
|
|
||||||
|
/// A date for forcing a refresh of the view
|
||||||
|
@State var forceRefreshDate: Date = Date.now
|
||||||
|
|
||||||
|
|
||||||
/// The actual view
|
/// The actual view
|
||||||
var body: some View {
|
var body: some View {
|
||||||
List {
|
List {
|
||||||
@@ -73,6 +81,28 @@ struct SettingsNavigationView: View {
|
|||||||
Text("pref_tts_language_title")
|
Text("pref_tts_language_title")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HStack {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Text("voice")
|
||||||
|
|
||||||
|
if #available(iOS 26, *) {
|
||||||
|
Text("voice_explanation")
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
} else {
|
||||||
|
Text("voice_explanation_before_version26")
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
Text(Settings.voiceForVoiceRouting ?? "unknown")
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
.id(UUID())
|
||||||
|
}
|
||||||
|
|
||||||
Toggle(isOn: $shouldAnnounceStreetnamesWhileVoiceRouting) {
|
Toggle(isOn: $shouldAnnounceStreetnamesWhileVoiceRouting) {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
Text("pref_tts_street_names_title")
|
Text("pref_tts_street_names_title")
|
||||||
@@ -111,6 +141,7 @@ struct SettingsNavigationView: View {
|
|||||||
.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
|
.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.id(forceRefreshDate)
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
Toggle("avoid_tolls", isOn: $shouldAvoidTollRoadsWhileRouting)
|
Toggle("avoid_tolls", isOn: $shouldAvoidTollRoadsWhileRouting)
|
||||||
@@ -147,6 +178,9 @@ struct SettingsNavigationView: View {
|
|||||||
shouldAvoidMotorwaysWhileRouting = Settings.shouldAvoidMotorwaysWhileRouting
|
shouldAvoidMotorwaysWhileRouting = Settings.shouldAvoidMotorwaysWhileRouting
|
||||||
shouldAvoidStepsWhileRouting = Settings.shouldAvoidStepsWhileRouting
|
shouldAvoidStepsWhileRouting = Settings.shouldAvoidStepsWhileRouting
|
||||||
}
|
}
|
||||||
|
.onChange(of: scenePhase) { _ in
|
||||||
|
forceRefreshDate = Date.now
|
||||||
|
}
|
||||||
.onChange(of: hasPerspectiveViewWhileRouting) { changedHasPerspectiveViewWhileRouting in
|
.onChange(of: hasPerspectiveViewWhileRouting) { changedHasPerspectiveViewWhileRouting in
|
||||||
Settings.hasPerspectiveViewWhileRouting = changedHasPerspectiveViewWhileRouting
|
Settings.hasPerspectiveViewWhileRouting = changedHasPerspectiveViewWhileRouting
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user