@situm/cordova 3.15.31 → 3.15.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.semgrepignore +8 -0
- package/azure-pipelines.yml +304 -303
- package/example/.editorconfig +1 -1
- package/example/ios/App/App.xcodeproj/project.pbxproj +2 -2
- package/example/package-lock.json +1 -1
- package/package.json +1 -1
- package/plugin.xml +5 -3
- package/src/android/app/build.gradle +1 -1
- package/src/android/app/src/main/java/es/situm/plugin/PluginHelper.java +75 -2
- package/src/android/app/src/main/java/es/situm/plugin/SitumMapper.java +1 -1
- package/src/android/app/src/main/java/es/situm/plugin/SitumPlugin.java +40 -4
- package/src/android/app/src/main/java/es/situm/plugin/TextToSpeechManager.java +117 -0
- package/src/android/situm.gradle +1 -1
- package/src/ios/Podfile +2 -2
- package/src/ios/situmcordovaplugin/SITTextToSpeechManager.h +24 -0
- package/src/ios/situmcordovaplugin/SitTextToSpeechManager.m +68 -0
- package/src/ios/situmcordovaplugin/SitumPlugin.h +1 -0
- package/src/ios/situmcordovaplugin/SitumPlugin.m +57 -1
- package/www/map-view-controller.js +23 -12
- package/www/map-view.js +11 -9
- package/www/situm.js +8 -0
|
@@ -353,7 +353,7 @@
|
|
|
353
353
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
|
354
354
|
MARKETING_VERSION = 1.0;
|
|
355
355
|
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
|
356
|
-
PRODUCT_BUNDLE_IDENTIFIER =
|
|
356
|
+
PRODUCT_BUNDLE_IDENTIFIER = com.situm.capacitorexample;
|
|
357
357
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
358
358
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
|
359
359
|
SWIFT_VERSION = 5.0;
|
|
@@ -373,7 +373,7 @@
|
|
|
373
373
|
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
|
374
374
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
|
375
375
|
MARKETING_VERSION = 1.0;
|
|
376
|
-
PRODUCT_BUNDLE_IDENTIFIER =
|
|
376
|
+
PRODUCT_BUNDLE_IDENTIFIER = com.situm.capacitorexample;
|
|
377
377
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
378
378
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
|
|
379
379
|
SWIFT_VERSION = 5.0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@situm/cordova",
|
|
3
|
-
"version": "3.15.
|
|
3
|
+
"version": "3.15.33",
|
|
4
4
|
"description": "Situm Wayfinding for Capacitor and Cordova. Integrate plug&play indoor navigation experience with floorplans, POIs, routes and turn-by-turn directions in no time. With the power of Situm.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"repository": "https://github.com/situmtech/cordova",
|
package/plugin.xml
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
|
|
4
4
|
id="@situm/cordova"
|
|
5
|
-
version="3.15.
|
|
5
|
+
version="3.15.33">
|
|
6
6
|
<name>Situm Cordova plugin Official</name>
|
|
7
7
|
<description>This is the stable branch.</description>
|
|
8
8
|
<license>MIT</license>
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
<source-file src="src/android/app/src/main/java/es/situm/plugin/PluginHelper.java" target-dir="src/es/situm/plugin" />
|
|
51
51
|
<source-file src="src/android/app/src/main/java/es/situm/plugin/SitumMapper.java" target-dir="src/es/situm/plugin" />
|
|
52
52
|
<source-file src="src/android/app/src/main/java/es/situm/plugin/DateUtils.java" target-dir="src/es/situm/plugin" />
|
|
53
|
+
<source-file src="src/android/app/src/main/java/es/situm/plugin/TextToSpeechManager.java" target-dir="src/es/situm/plugin" />
|
|
53
54
|
|
|
54
55
|
</platform>
|
|
55
56
|
|
|
@@ -93,7 +94,7 @@
|
|
|
93
94
|
<config>
|
|
94
95
|
</config>
|
|
95
96
|
<pods use-frameworks="false">
|
|
96
|
-
<pod name="SitumSDK" spec="~> 3.34.
|
|
97
|
+
<pod name="SitumSDK" spec="~> 3.34.9"/>
|
|
97
98
|
</pods>
|
|
98
99
|
</podspec>
|
|
99
100
|
|
|
@@ -106,6 +107,7 @@
|
|
|
106
107
|
<source-file src="src/ios/situmcordovaplugin/Constants.m" />
|
|
107
108
|
<source-file src="src/ios/situmcordovaplugin/SITUtils.m" />
|
|
108
109
|
<source-file src="src/ios/situmcordovaplugin/SITUtils.h" />
|
|
109
|
-
|
|
110
|
+
<source-file src="src/ios/situmcordovaplugin/SITTextToSpeechManager.m" />
|
|
111
|
+
<source-file src="src/ios/situmcordovaplugin/SITTextToSpeechManager.h" />
|
|
110
112
|
</platform>
|
|
111
113
|
</plugin>
|
|
@@ -44,7 +44,7 @@ dependencies {
|
|
|
44
44
|
implementation ('com.googlecode.json-simple:json-simple:1.1.1'){
|
|
45
45
|
exclude group: 'junit', module:'junit'
|
|
46
46
|
}
|
|
47
|
-
implementation ('es.situm:situm-sdk:3.33.
|
|
47
|
+
implementation ('es.situm:situm-sdk:3.33.2@aar') {
|
|
48
48
|
transitive = true
|
|
49
49
|
}
|
|
50
50
|
implementation 'org.apache.cordova:framework:10.1.1'
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
package es.situm.plugin;
|
|
2
2
|
|
|
3
|
-
import android.content.Intent;
|
|
4
3
|
import android.graphics.Bitmap;
|
|
5
4
|
import android.util.Log;
|
|
6
|
-
import android.widget.Toast;
|
|
7
5
|
|
|
8
6
|
import androidx.core.app.ActivityCompat;
|
|
9
7
|
|
|
@@ -50,6 +48,8 @@ import es.situm.sdk.utils.Handler;
|
|
|
50
48
|
import es.situm.sdk.userhelper.UserHelperColorScheme;
|
|
51
49
|
import es.situm.sdk.v1.SitumEvent;
|
|
52
50
|
|
|
51
|
+
import es.situm.plugin.TextToSpeechManager;
|
|
52
|
+
|
|
53
53
|
public class PluginHelper {
|
|
54
54
|
|
|
55
55
|
private static final String TAG = "PluginHelper";
|
|
@@ -64,6 +64,7 @@ public class PluginHelper {
|
|
|
64
64
|
private volatile NavigationManager nmInstance;
|
|
65
65
|
private RealTimeListener realtimeListener;
|
|
66
66
|
private volatile RealTimeManager rmInstance;
|
|
67
|
+
private TextToSpeechManager ttsManager;
|
|
67
68
|
|
|
68
69
|
private Route computedRoute;
|
|
69
70
|
private Location computedLocation;
|
|
@@ -71,6 +72,10 @@ public class PluginHelper {
|
|
|
71
72
|
private CallbackContext callbackEnterGeofences;
|
|
72
73
|
private CallbackContext callbackExitGeofences;
|
|
73
74
|
|
|
75
|
+
void setTextToSpeechManager(TextToSpeechManager ttsManager) {
|
|
76
|
+
this.ttsManager = ttsManager;
|
|
77
|
+
}
|
|
78
|
+
|
|
74
79
|
private CommunicationManager getCommunicationManagerInstance() {
|
|
75
80
|
if (cmInstance == null) { //Check for the first time
|
|
76
81
|
synchronized (CommunicationManager.class) { //Check for the second time.
|
|
@@ -109,6 +114,31 @@ public class PluginHelper {
|
|
|
109
114
|
nmInstance = navigationManager;
|
|
110
115
|
}
|
|
111
116
|
|
|
117
|
+
public void onResume() {
|
|
118
|
+
ttsManager.setCanSpeak(true);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
public void onPause() {
|
|
122
|
+
ttsManager.setCanSpeak(false);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
public void onDestroy() {
|
|
126
|
+
ttsManager.stop();
|
|
127
|
+
ttsManager = null;
|
|
128
|
+
locationListener = null;
|
|
129
|
+
locationRequest = null;
|
|
130
|
+
navigationListener = null;
|
|
131
|
+
navigationRequest = null;
|
|
132
|
+
cmInstance = null;
|
|
133
|
+
nmInstance = null;
|
|
134
|
+
realtimeListener = null;
|
|
135
|
+
rmInstance = null;
|
|
136
|
+
computedRoute = null;
|
|
137
|
+
computedLocation = null;
|
|
138
|
+
callbackEnterGeofences = null;
|
|
139
|
+
callbackExitGeofences = null;
|
|
140
|
+
}
|
|
141
|
+
|
|
112
142
|
public void getDeviceId(CordovaInterface cordova, CordovaWebView webView, JSONArray args,
|
|
113
143
|
final CallbackContext callbackContext) {
|
|
114
144
|
String deviceId = String.valueOf(SitumSdk.getDeviceID());
|
|
@@ -977,4 +1007,47 @@ public class PluginHelper {
|
|
|
977
1007
|
callbackContext.sendPluginResult(new PluginResult(Status.ERROR, e.getMessage()));
|
|
978
1008
|
}
|
|
979
1009
|
}
|
|
1010
|
+
|
|
1011
|
+
// ----------------------------------
|
|
1012
|
+
// MapView messages:
|
|
1013
|
+
// ----------------------------------
|
|
1014
|
+
|
|
1015
|
+
public void internalHandleMapViewMessage(
|
|
1016
|
+
CordovaInterface cordova,
|
|
1017
|
+
CordovaWebView webView,
|
|
1018
|
+
JSONArray args,
|
|
1019
|
+
CallbackContext callbackContext
|
|
1020
|
+
) {
|
|
1021
|
+
if (args.length() != 2) return;
|
|
1022
|
+
|
|
1023
|
+
try {
|
|
1024
|
+
String message = args.optString(0, null);
|
|
1025
|
+
Object rawPayload = args.opt(1);
|
|
1026
|
+
JSONObject payload = null;
|
|
1027
|
+
if (rawPayload == null || "null".equalsIgnoreCase(String.valueOf(rawPayload))) {
|
|
1028
|
+
payload = null;
|
|
1029
|
+
} else if (rawPayload instanceof JSONObject) {
|
|
1030
|
+
payload = (JSONObject) rawPayload;
|
|
1031
|
+
} else if (rawPayload instanceof String) {
|
|
1032
|
+
payload = new JSONObject();
|
|
1033
|
+
payload.put("value", rawPayload);
|
|
1034
|
+
}
|
|
1035
|
+
switch (message) {
|
|
1036
|
+
case "ui.speak_aloud_text":
|
|
1037
|
+
_handleSpeakAloudText(cordova, payload);
|
|
1038
|
+
break;
|
|
1039
|
+
// Any other message here...
|
|
1040
|
+
default:
|
|
1041
|
+
break;
|
|
1042
|
+
}
|
|
1043
|
+
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
|
|
1044
|
+
|
|
1045
|
+
} catch (JSONException e) {
|
|
1046
|
+
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, e.getMessage()));
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
private void _handleSpeakAloudText(CordovaInterface cordova, JSONObject payload) {
|
|
1051
|
+
ttsManager.speak(payload);
|
|
1052
|
+
}
|
|
980
1053
|
}
|
|
@@ -271,7 +271,7 @@ class SitumMapper {
|
|
|
271
271
|
|
|
272
272
|
static Map<String,String> jsonObjectToMapString(JSONObject jo) throws JSONException {
|
|
273
273
|
Map<String,String> map = new HashMap<String, String>();
|
|
274
|
-
int length = jo.length();
|
|
274
|
+
int length = jo != null ? jo.length() : 0;
|
|
275
275
|
for(int i = 0; i<length; i++){
|
|
276
276
|
map.put(jo.names().get(i).toString(),jo.getString(jo.names().get(i).toString()));
|
|
277
277
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
package es.situm.plugin;
|
|
4
4
|
|
|
5
5
|
import android.util.Log;
|
|
6
|
+
import android.content.Context;
|
|
6
7
|
|
|
7
8
|
import java.util.concurrent.TimeUnit;
|
|
8
9
|
|
|
@@ -21,10 +22,14 @@ public class SitumPlugin extends CordovaPlugin {
|
|
|
21
22
|
private static final String TAG = "SitumPlugin";
|
|
22
23
|
|
|
23
24
|
private static volatile PluginHelper pluginInstance;
|
|
25
|
+
private static final Object PLUGIN_LOCK = new Object();
|
|
26
|
+
|
|
27
|
+
private static volatile TextToSpeechManager ttsManager;
|
|
28
|
+
private static final Object TTS_LOCK = new Object();
|
|
24
29
|
|
|
25
30
|
private static PluginHelper getPluginInstance() {
|
|
26
31
|
if (pluginInstance == null) { //Check for the first time
|
|
27
|
-
synchronized (
|
|
32
|
+
synchronized (PLUGIN_LOCK) { //Check for the second time.
|
|
28
33
|
//if there is no instance available... create new one
|
|
29
34
|
if (pluginInstance == null) pluginInstance = new PluginHelper();
|
|
30
35
|
}
|
|
@@ -32,12 +37,41 @@ public class SitumPlugin extends CordovaPlugin {
|
|
|
32
37
|
return pluginInstance;
|
|
33
38
|
}
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
|
|
40
|
+
private static void setupTtsManager(Context context) {
|
|
41
|
+
if (ttsManager == null) {
|
|
42
|
+
synchronized (TTS_LOCK) {
|
|
43
|
+
if(ttsManager == null) ttsManager = new TextToSpeechManager(context);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
getPluginInstance().setTextToSpeechManager(ttsManager);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@Override
|
|
50
|
+
public void pluginInitialize() {
|
|
51
|
+
super.pluginInitialize();
|
|
37
52
|
Log.d(TAG, "Initializing Situm Plugin");
|
|
38
|
-
SitumSdk.init(cordova.getActivity());
|
|
53
|
+
SitumSdk.init(this.cordova.getActivity());
|
|
54
|
+
setupTtsManager(this.cordova.getActivity());
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@Override
|
|
58
|
+
public void onPause(boolean multitasking) {
|
|
59
|
+
getPluginInstance().onPause();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@Override
|
|
63
|
+
public void onResume(boolean multitasking) {
|
|
64
|
+
getPluginInstance().onResume();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@Override
|
|
68
|
+
public void onDestroy() {
|
|
69
|
+
getPluginInstance().onDestroy();
|
|
70
|
+
pluginInstance = null;
|
|
71
|
+
ttsManager = null;
|
|
39
72
|
}
|
|
40
73
|
|
|
74
|
+
@Override
|
|
41
75
|
public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
|
|
42
76
|
Log.d(TAG, "execute: " + action);
|
|
43
77
|
if (action.equalsIgnoreCase("setUseRemoteConfig")) {
|
|
@@ -106,6 +140,8 @@ public class SitumPlugin extends CordovaPlugin {
|
|
|
106
140
|
getPluginInstance().updateNavigationState(cordova, webView, args, callbackContext);
|
|
107
141
|
} else if(action.equalsIgnoreCase("configureUserHelper")) {
|
|
108
142
|
getPluginInstance().configureUserHelper(cordova, webView, args, callbackContext);
|
|
143
|
+
} else if(action.equalsIgnoreCase("internalHandleMapViewMessage")) {
|
|
144
|
+
getPluginInstance().internalHandleMapViewMessage(cordova, webView, args, callbackContext);
|
|
109
145
|
} else {
|
|
110
146
|
getPluginInstance().returnDefaultResponse(callbackContext);
|
|
111
147
|
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
package es.situm.plugin;
|
|
2
|
+
|
|
3
|
+
import android.content.Context;
|
|
4
|
+
import android.os.Build;
|
|
5
|
+
import android.speech.tts.TextToSpeech;
|
|
6
|
+
|
|
7
|
+
import org.json.JSONException;
|
|
8
|
+
import org.json.JSONObject;
|
|
9
|
+
|
|
10
|
+
import java.util.List;
|
|
11
|
+
import java.util.Locale;
|
|
12
|
+
|
|
13
|
+
public class TextToSpeechManager implements TextToSpeech.OnInitListener {
|
|
14
|
+
|
|
15
|
+
private static final float DEFAULT_SPEECH_RATE_VALUE = 1.0f;
|
|
16
|
+
private TextToSpeech textToSpeech;
|
|
17
|
+
private boolean canSpeak = true;
|
|
18
|
+
|
|
19
|
+
public TextToSpeechManager(Context context) {
|
|
20
|
+
String enginePackage = getPreferredTtsEnginePackage(context);
|
|
21
|
+
if (enginePackage != null) {
|
|
22
|
+
textToSpeech = new TextToSpeech(context, this, enginePackage);
|
|
23
|
+
} else {
|
|
24
|
+
textToSpeech = new TextToSpeech(context, this);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@Override
|
|
29
|
+
public void onInit(int status) {
|
|
30
|
+
if (status == TextToSpeech.SUCCESS) {
|
|
31
|
+
// Establece el idioma (opcional)
|
|
32
|
+
textToSpeech.setLanguage(Locale.getDefault());
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public void speak(JSONObject arguments) {
|
|
37
|
+
if (!canSpeak) return;
|
|
38
|
+
if (!arguments.has("text")) return;
|
|
39
|
+
|
|
40
|
+
if (arguments.has("lang")) {
|
|
41
|
+
try {
|
|
42
|
+
String lang = arguments.getString("lang");
|
|
43
|
+
textToSpeech.setLanguage(new Locale(lang));
|
|
44
|
+
} catch (JSONException e) {
|
|
45
|
+
e.printStackTrace();
|
|
46
|
+
// DO NOTHING: use the current language.
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (arguments.has("pitch")) {
|
|
51
|
+
try {
|
|
52
|
+
float pitch = (float) arguments.getDouble("pitch");
|
|
53
|
+
textToSpeech.setPitch(pitch);
|
|
54
|
+
} catch (JSONException e) {
|
|
55
|
+
e.printStackTrace();
|
|
56
|
+
// DO NOTHING: use the current pitch.
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (arguments.has("rate")) {
|
|
61
|
+
try {
|
|
62
|
+
float rate = (float) arguments.getDouble("rate");
|
|
63
|
+
textToSpeech.setSpeechRate(convertToAndroidSpeechRate(rate));
|
|
64
|
+
} catch (JSONException e) {
|
|
65
|
+
e.printStackTrace();
|
|
66
|
+
// DO NOTHING: use the current rate.
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
String text = arguments.getString("text");
|
|
72
|
+
textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, null, null);
|
|
73
|
+
} catch (JSONException e) {
|
|
74
|
+
e.printStackTrace();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ui.speak_aloud_text message sends the speech rate in FlutterTts scale [0.0f,1.0f],
|
|
79
|
+
// so convert it to the Android scale [0.0f,2.0f].
|
|
80
|
+
private float convertToAndroidSpeechRate(float value) {
|
|
81
|
+
if (value < 0 || value > 1.0f) {
|
|
82
|
+
return DEFAULT_SPEECH_RATE_VALUE;
|
|
83
|
+
}
|
|
84
|
+
return 2 * value;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
public void stop() {
|
|
88
|
+
if (textToSpeech != null) {
|
|
89
|
+
textToSpeech.stop();
|
|
90
|
+
textToSpeech.shutdown();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private String getPreferredTtsEnginePackage(Context context) {
|
|
95
|
+
TextToSpeech ttsTemp = new TextToSpeech(context, status -> {});
|
|
96
|
+
List<TextToSpeech.EngineInfo> engines = ttsTemp.getEngines();
|
|
97
|
+
ttsTemp.shutdown();
|
|
98
|
+
|
|
99
|
+
String googleTts = "com.google.android.tts";
|
|
100
|
+
if (Build.MANUFACTURER.equalsIgnoreCase("Samsung")) {
|
|
101
|
+
for (TextToSpeech.EngineInfo engine : engines) {
|
|
102
|
+
if (googleTts.equals(engine.name)) {
|
|
103
|
+
return googleTts;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
public void setCanSpeak(boolean value) {
|
|
111
|
+
// TTS is paused when screen is off, app goes background and MapView gets destroyed
|
|
112
|
+
canSpeak = value;
|
|
113
|
+
if (!canSpeak && textToSpeech != null) {
|
|
114
|
+
textToSpeech.stop();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
package/src/android/situm.gradle
CHANGED
package/src/ios/Podfile
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//
|
|
2
|
+
// SITTextToSpeechManager.h
|
|
3
|
+
// Situm Cordova
|
|
4
|
+
//
|
|
5
|
+
|
|
6
|
+
#import <Foundation/Foundation.h>
|
|
7
|
+
#import <AVFoundation/AVFoundation.h>
|
|
8
|
+
|
|
9
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
10
|
+
|
|
11
|
+
@interface SITTextToSpeechManager : NSObject
|
|
12
|
+
|
|
13
|
+
- (instancetype)init;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
Processes and speaks aloud a message that MapView's wants to communicate to the user through the 'ui.speak_aloud_text' javascript message.
|
|
17
|
+
|
|
18
|
+
@param payload An internal dictionary from within MapView that contains the required information and parameters to be able to speak aloud texts.
|
|
19
|
+
*/
|
|
20
|
+
- (void)speakWithPayload:(NSDictionary<id, id> * _Nullable)payload;
|
|
21
|
+
|
|
22
|
+
@end
|
|
23
|
+
|
|
24
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
//
|
|
2
|
+
// SITTextToSpeechManager.m
|
|
3
|
+
// Situm Cordova
|
|
4
|
+
//
|
|
5
|
+
|
|
6
|
+
#import "SITTextToSpeechManager.h"
|
|
7
|
+
|
|
8
|
+
@interface SITTextToSpeechManager () <AVSpeechSynthesizerDelegate>
|
|
9
|
+
@property (nonatomic, strong) AVSpeechSynthesizer *synthesizer;
|
|
10
|
+
@end
|
|
11
|
+
|
|
12
|
+
@implementation SITTextToSpeechManager
|
|
13
|
+
|
|
14
|
+
- (instancetype)init {
|
|
15
|
+
self = [super init];
|
|
16
|
+
if (self) {
|
|
17
|
+
self.synthesizer = [AVSpeechSynthesizer new];
|
|
18
|
+
self.synthesizer.delegate = self;
|
|
19
|
+
if (@available(iOS 13.0, *)) {
|
|
20
|
+
self.synthesizer.usesApplicationAudioSession = false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return self;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
- (void)speakWithPayload:(NSDictionary<id,id> *)payload {
|
|
27
|
+
|
|
28
|
+
if (![payload isKindOfClass:[NSDictionary class]]) return;
|
|
29
|
+
|
|
30
|
+
NSString *text = payload[@"text"];
|
|
31
|
+
NSString *lang = payload[@"lang"];
|
|
32
|
+
NSNumber *pitchNum = payload[@"pitch"];
|
|
33
|
+
NSNumber *rateNum = payload[@"rate"];
|
|
34
|
+
|
|
35
|
+
if (![text isKindOfClass:[NSString class]] ||
|
|
36
|
+
![lang isKindOfClass:[NSString class]] ||
|
|
37
|
+
![pitchNum isKindOfClass:[NSNumber class]] ||
|
|
38
|
+
![rateNum isKindOfClass:[NSNumber class]]) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
float pitch = pitchNum.floatValue;
|
|
43
|
+
float rate = rateNum.floatValue;
|
|
44
|
+
|
|
45
|
+
[self speakText:text language:lang rate:rate pitch:pitch];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
- (void)speakText:(NSString *)text language:(NSString *)language rate:(float)rate pitch:(float)pitch {
|
|
49
|
+
if (text.length == 0) return;
|
|
50
|
+
|
|
51
|
+
AVSpeechUtterance *utt = [[AVSpeechUtterance alloc] initWithString:text];
|
|
52
|
+
utt.rate = rate;
|
|
53
|
+
utt.pitchMultiplier = pitch;
|
|
54
|
+
|
|
55
|
+
AVSpeechSynthesisVoice *voice = [AVSpeechSynthesisVoice voiceWithLanguage:language];
|
|
56
|
+
if (voice) {
|
|
57
|
+
utt.voice = voice;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
61
|
+
if ([self.synthesizer isSpeaking]) {
|
|
62
|
+
[self.synthesizer stopSpeakingAtBoundary:AVSpeechBoundaryImmediate];
|
|
63
|
+
}
|
|
64
|
+
[self.synthesizer speakUtterance:utt];
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@end
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
- (void)fetchPoiCategoryIconSelected:(CDVInvokedUrlCommand *)command;
|
|
37
37
|
- (void)invalidateCache:(CDVInvokedUrlCommand *)command;
|
|
38
38
|
- (void)requestDirections:(CDVInvokedUrlCommand *)command;
|
|
39
|
+
- (void)internalHandleMapViewMessage:(CDVInvokedUrlCommand *)command;
|
|
39
40
|
// Realtime
|
|
40
41
|
- (void)requestRealTimeUpdates:(CDVInvokedUrlCommand *)command;
|
|
41
42
|
- (void)removeRealTimeUpdates:(CDVInvokedUrlCommand *)command;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#import "SitumPlugin.h"
|
|
2
2
|
#import "SitumLocationWrapper.h"
|
|
3
3
|
#import "SITUtils.h"
|
|
4
|
+
#import "SITTextToSpeechManager.h"
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
#import <Cordova/CDVAvailability.h>
|
|
@@ -17,6 +18,7 @@ static NSString *DEFAULT_SITUM_LOG = @"SitumSDK >>: ";
|
|
|
17
18
|
@interface SitumPlugin() {}
|
|
18
19
|
|
|
19
20
|
@property (nonatomic, strong) SITRoute *computedRoute;
|
|
21
|
+
@property (nonatomic, strong) SITTextToSpeechManager *ttsManager;
|
|
20
22
|
|
|
21
23
|
@end
|
|
22
24
|
|
|
@@ -122,7 +124,7 @@ static NSString *DEFAULT_SITUM_LOG = @"SitumSDK >>: ";
|
|
|
122
124
|
if (IS_LOG_ENABLED) {
|
|
123
125
|
NSLog(@"%@", [NSString stringWithFormat: @"%@ %@ Fetching buildings returned values", DEFAULT_SITUM_LOG, operation]);
|
|
124
126
|
}
|
|
125
|
-
NSArray *buildings = [mapping valueForKey:ResultsKey];
|
|
127
|
+
NSArray *buildings = [[mapping valueForKey:ResultsKey] copy];
|
|
126
128
|
CDVPluginResult* pluginResult = nil;
|
|
127
129
|
if (buildings.count == 0) {
|
|
128
130
|
if (IS_LOG_ENABLED) {
|
|
@@ -628,6 +630,60 @@ static NSString *DEFAULT_SITUM_LOG = @"SitumSDK >>: ";
|
|
|
628
630
|
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
|
629
631
|
}
|
|
630
632
|
|
|
633
|
+
// MapView messages:
|
|
634
|
+
|
|
635
|
+
- (void)internalHandleMapViewMessage:(CDVInvokedUrlCommand *)command {
|
|
636
|
+
if (command.arguments.count != 2) {
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
@try {
|
|
641
|
+
id message = command.arguments[0];
|
|
642
|
+
id rawPayload = command.arguments[1];
|
|
643
|
+
NSDictionary *payload = nil;
|
|
644
|
+
|
|
645
|
+
if (rawPayload == [NSNull null] ||
|
|
646
|
+
([rawPayload isKindOfClass:[NSString class]] &&
|
|
647
|
+
[((NSString *)rawPayload).lowercaseString isEqualToString:@"null"])) {
|
|
648
|
+
payload = nil;
|
|
649
|
+
} else if ([rawPayload isKindOfClass:[NSDictionary class]]) {
|
|
650
|
+
payload = rawPayload;
|
|
651
|
+
} else if ([rawPayload isKindOfClass:[NSString class]]) {
|
|
652
|
+
payload = @{ @"value": rawPayload };
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
NSDictionary *handlers = @{
|
|
656
|
+
@"ui.speak_aloud_text": ^{
|
|
657
|
+
[self handleSpeakAloudText:payload];
|
|
658
|
+
},
|
|
659
|
+
// Any other MapView message that should be handled natively...
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
void (^handler)(void) = handlers[message];
|
|
663
|
+
if (handler) handler();
|
|
664
|
+
|
|
665
|
+
CDVPluginResult *pluginResult =
|
|
666
|
+
[CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
|
667
|
+
[self.commandDelegate sendPluginResult:pluginResult
|
|
668
|
+
callbackId:command.callbackId];
|
|
669
|
+
|
|
670
|
+
}
|
|
671
|
+
@catch (NSException *exception) {
|
|
672
|
+
CDVPluginResult *pluginResult =
|
|
673
|
+
[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR
|
|
674
|
+
messageAsString:exception.reason];
|
|
675
|
+
[self.commandDelegate sendPluginResult:pluginResult
|
|
676
|
+
callbackId:command.callbackId];
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
- (void)handleSpeakAloudText:(NSDictionary *)payload {
|
|
681
|
+
if (!_ttsManager) {
|
|
682
|
+
_ttsManager = [[SITTextToSpeechManager alloc] init];
|
|
683
|
+
}
|
|
684
|
+
[self.ttsManager speakWithPayload:payload];
|
|
685
|
+
}
|
|
686
|
+
|
|
631
687
|
// Realtime
|
|
632
688
|
- (void)requestRealTimeUpdates:(CDVInvokedUrlCommand *)command {
|
|
633
689
|
realtimeCallbackId = command.callbackId;
|
|
@@ -76,7 +76,6 @@ class MapViewControllerImpl {
|
|
|
76
76
|
this._navigationType = 'sdk';
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
|
-
|
|
80
79
|
}
|
|
81
80
|
|
|
82
81
|
_setOnLoadCallback(callback) {
|
|
@@ -152,16 +151,7 @@ class MapViewControllerImpl {
|
|
|
152
151
|
_handleMapViewMessages(m) {
|
|
153
152
|
switch (m.type) {
|
|
154
153
|
case 'app.map_is_ready':
|
|
155
|
-
|
|
156
|
-
this._onLoadCallback &&
|
|
157
|
-
typeof this._onLoadCallback === 'function'
|
|
158
|
-
) {
|
|
159
|
-
this._onLoadCallback(this);
|
|
160
|
-
console.debug('Map is ready!');
|
|
161
|
-
}
|
|
162
|
-
if (this._navigationType) {
|
|
163
|
-
this._sendNavigationConfig(this._navigationType);
|
|
164
|
-
}
|
|
154
|
+
this._handleMapIsReady();
|
|
165
155
|
break;
|
|
166
156
|
case 'cartography.poi_selected':
|
|
167
157
|
console.debug(`poi (${m.payload.identifier}) was selected`);
|
|
@@ -200,12 +190,31 @@ class MapViewControllerImpl {
|
|
|
200
190
|
case 'viewer.navigation.stopped':
|
|
201
191
|
this._onViewerNavigationStopped(m.payload);
|
|
202
192
|
break;
|
|
193
|
+
case 'ui.speak_aloud_text':
|
|
194
|
+
// case ...: Add here any other message that must be delegated to the native side.
|
|
195
|
+
this._internalHandleMapViewMessage(m.type, m.payload);
|
|
196
|
+
break;
|
|
203
197
|
default:
|
|
204
198
|
console.debug('Got unmanaged message: ', m);
|
|
205
199
|
break;
|
|
206
200
|
}
|
|
207
201
|
}
|
|
208
202
|
|
|
203
|
+
_handleMapIsReady() {
|
|
204
|
+
if (this._onLoadCallback &&
|
|
205
|
+
typeof this._onLoadCallback === 'function') {
|
|
206
|
+
this._onLoadCallback(this);
|
|
207
|
+
console.debug('Map is ready!');
|
|
208
|
+
}
|
|
209
|
+
if (this._navigationType) {
|
|
210
|
+
this._sendNavigationConfig(this._navigationType);
|
|
211
|
+
}
|
|
212
|
+
this._sendMessageToViewer('app.set_config_item', [
|
|
213
|
+
{key: "internal.tts.engine", value: "mobile"},
|
|
214
|
+
// Any other config item here...
|
|
215
|
+
]);
|
|
216
|
+
}
|
|
217
|
+
|
|
209
218
|
// Fetch the given building and return it or undefined if not found.
|
|
210
219
|
_ensureBuilding(buildingId, callback) {
|
|
211
220
|
if (this._buildings) {
|
|
@@ -384,7 +393,9 @@ class MapViewControllerImpl {
|
|
|
384
393
|
Situm.updateNavigationState(externalNavigation, () => {}, () => {});
|
|
385
394
|
}
|
|
386
395
|
|
|
387
|
-
|
|
396
|
+
_internalHandleMapViewMessage(message, webPayload) {
|
|
397
|
+
Situm.internalHandleMapViewMessage(message, webPayload);
|
|
398
|
+
}
|
|
388
399
|
|
|
389
400
|
// ==================================================
|
|
390
401
|
// ACTIONS
|