@ateam-ai-mobile/ui 0.1.4 → 0.1.7
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/dist/index.d.mts +325 -21
- package/dist/index.d.ts +325 -21
- package/dist/index.js +1447 -429
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1411 -401
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/WorkspaceBanner.tsx +71 -0
- package/src/auth/HandoffScreen.tsx +94 -0
- package/src/auth/JoinScreen.tsx +145 -0
- package/src/auth/LoginScreen.tsx +181 -0
- package/src/auth/OpenJoinScreen.tsx +131 -0
- package/src/auth/handoffExchange.ts +49 -0
- package/src/auth/inviteJoin.ts +44 -0
- package/src/auth/login.ts +57 -0
- package/src/auth/openJoin.ts +56 -0
- package/src/chat/MessageBubble.tsx +14 -1
- package/src/chat/QuestionChips.tsx +76 -0
- package/src/chat/UIActionsRow.tsx +7 -1
- package/src/index.ts +38 -1
- package/src/plugin/Plugin.tsx +14 -9
- package/src/providers.ts +44 -0
- package/src/voice/VoiceCallSheet.tsx +4 -32
- package/src/voice/VoiceMicIndicator.tsx +99 -0
- package/src/voice/VoiceSessionHost.tsx +77 -0
- package/src/voice/useVoiceCall.ts +40 -231
- package/src/voice/voiceSession.ts +628 -0
package/dist/index.js
CHANGED
|
@@ -34,9 +34,13 @@ __export(index_exports, {
|
|
|
34
34
|
ChatInput: () => ChatInput,
|
|
35
35
|
DaySeparator: () => DaySeparator,
|
|
36
36
|
EmbeddedPluginWebView: () => EmbeddedPluginWebView,
|
|
37
|
+
HandoffScreen: () => HandoffScreen,
|
|
37
38
|
JobProgressBar: () => JobProgressBar,
|
|
39
|
+
JoinScreen: () => JoinScreen,
|
|
38
40
|
Lightbox: () => Lightbox,
|
|
41
|
+
LoginScreen: () => LoginScreen,
|
|
39
42
|
MessageBubble: () => MessageBubble,
|
|
43
|
+
OpenJoinScreen: () => OpenJoinScreen,
|
|
40
44
|
Plugin: () => Plugin,
|
|
41
45
|
PluginSurface: () => PluginSurface,
|
|
42
46
|
TableCardBlock: () => TableCardBlock,
|
|
@@ -44,30 +48,44 @@ __export(index_exports, {
|
|
|
44
48
|
TypingIndicator: () => TypingIndicator,
|
|
45
49
|
UIActionsRow: () => UIActionsRow,
|
|
46
50
|
VoiceCallSheet: () => VoiceCallSheet,
|
|
51
|
+
VoiceMicIndicator: () => VoiceMicIndicator,
|
|
52
|
+
VoiceSessionHost: () => VoiceSessionHost,
|
|
47
53
|
WidgetHost: () => WidgetHost,
|
|
48
54
|
WidgetWebView: () => WidgetWebView,
|
|
55
|
+
WorkspaceBanner: () => WorkspaceBanner,
|
|
49
56
|
buildPluginBridgeJS: () => buildPluginBridgeJS,
|
|
57
|
+
completeInviteJoin: () => completeInviteJoin,
|
|
58
|
+
completeOpenJoin: () => completeOpenJoin,
|
|
59
|
+
completeProviderSignIn: () => completeProviderSignIn,
|
|
60
|
+
googleClientIds: () => googleClientIds,
|
|
61
|
+
handoffErrorMessage: () => handoffErrorMessage,
|
|
62
|
+
inviteHeadline: () => inviteHeadline,
|
|
63
|
+
openJoinErrorMessage: () => openJoinErrorMessage,
|
|
50
64
|
openWidget: () => openWidget,
|
|
65
|
+
runHandoffExchange: () => runHandoffExchange,
|
|
51
66
|
setClipboardProvider: () => setClipboardProvider,
|
|
67
|
+
setOAuthProvider: () => setOAuthProvider,
|
|
52
68
|
setPluginWebViewExtraHosts: () => setPluginWebViewExtraHosts,
|
|
53
69
|
setUIActionNavigator: () => setUIActionNavigator,
|
|
70
|
+
shouldRecoverToDefaultTenant: () => shouldRecoverToDefaultTenant,
|
|
54
71
|
useLightboxStore: () => useLightboxStore,
|
|
55
72
|
usePluginBridge: () => usePluginBridge,
|
|
56
73
|
useVoiceCall: () => useVoiceCall,
|
|
57
|
-
useWidgetHostStore: () => useWidgetHostStore
|
|
74
|
+
useWidgetHostStore: () => useWidgetHostStore,
|
|
75
|
+
voiceSession: () => voiceSession
|
|
58
76
|
});
|
|
59
77
|
module.exports = __toCommonJS(index_exports);
|
|
60
78
|
|
|
61
79
|
// src/AdasChatScreen.tsx
|
|
62
80
|
var import_react9 = require("react");
|
|
63
|
-
var
|
|
64
|
-
var
|
|
81
|
+
var import_react_native12 = require("react-native");
|
|
82
|
+
var import_core13 = require("@ateam-ai-mobile/core");
|
|
65
83
|
|
|
66
84
|
// src/chat/MessageBubble.tsx
|
|
67
85
|
var import_react7 = require("react");
|
|
68
|
-
var
|
|
86
|
+
var import_react_native8 = require("react-native");
|
|
69
87
|
var import_react_native_markdown_display = __toESM(require("react-native-markdown-display"));
|
|
70
|
-
var
|
|
88
|
+
var import_core10 = require("@ateam-ai-mobile/core");
|
|
71
89
|
var import_plugin_runtime6 = require("@ateam-ai-mobile/plugin-runtime");
|
|
72
90
|
|
|
73
91
|
// src/chat/JobProgressBar.tsx
|
|
@@ -261,6 +279,13 @@ var import_core7 = require("@ateam-ai-mobile/core");
|
|
|
261
279
|
var import_plugin_runtime5 = require("@ateam-ai-mobile/plugin-runtime");
|
|
262
280
|
|
|
263
281
|
// src/providers.ts
|
|
282
|
+
var _oauth = null;
|
|
283
|
+
function setOAuthProvider(oauth) {
|
|
284
|
+
_oauth = oauth;
|
|
285
|
+
}
|
|
286
|
+
function getOAuthProvider() {
|
|
287
|
+
return _oauth;
|
|
288
|
+
}
|
|
264
289
|
var _clipboard = null;
|
|
265
290
|
function setClipboardProvider(clipboard) {
|
|
266
291
|
_clipboard = clipboard;
|
|
@@ -785,8 +810,10 @@ function Plugin({ id, manifest, commandBufferRef, props: engineProps }) {
|
|
|
785
810
|
const { plugin, loading, error, bundleMissing } = (0, import_plugin_runtime2.usePlugin)(id, manifest);
|
|
786
811
|
const connectorId = id.startsWith("mcp:") ? id.split(":")[1] : manifest._connectorId;
|
|
787
812
|
const bridge = (0, import_plugin_runtime2.useNativeBridge)(id, connectorId, commandBufferRef);
|
|
788
|
-
const
|
|
789
|
-
|
|
813
|
+
const { device, native, deviceState, voice } = (0, import_react4.useMemo)(
|
|
814
|
+
() => (0, import_plugin_runtime2.resolvePluginRuntimeProps)({ pluginId: id, manifest, plugin }),
|
|
815
|
+
[id, manifest, plugin]
|
|
816
|
+
);
|
|
790
817
|
const theme = (0, import_plugin_runtime2.usePluginTheme)();
|
|
791
818
|
const user = (0, import_core4.getUser)();
|
|
792
819
|
const context = (0, import_react4.useMemo)(() => ({
|
|
@@ -809,7 +836,7 @@ function Plugin({ id, manifest, commandBufferRef, props: engineProps }) {
|
|
|
809
836
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style: styles3.center, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: styles3.errorMessage, children: error || "Plugin not found" }) });
|
|
810
837
|
}
|
|
811
838
|
const { Component } = plugin;
|
|
812
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PluginErrorBoundary, { pluginId: id, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Component, { bridge, native, theme, context, props: engineProps }) });
|
|
839
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PluginErrorBoundary, { pluginId: id, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Component, { bridge, device, native, deviceState, voice, theme, context, props: engineProps }) });
|
|
813
840
|
}
|
|
814
841
|
var styles3 = import_react_native3.StyleSheet.create({
|
|
815
842
|
center: {
|
|
@@ -959,7 +986,8 @@ function UIActionsRow({ actions }) {
|
|
|
959
986
|
const focus = a.payload?.id || a.payload?.entity_id || a.payload?.focusId;
|
|
960
987
|
const surface = import_plugin_runtime5.useSurfaceStore.getState().manifests[id];
|
|
961
988
|
if (surface) {
|
|
962
|
-
|
|
989
|
+
const props = { ...focus ? { focus } : {}, ...a.payload?.data || {} };
|
|
990
|
+
import_plugin_runtime5.useSurfaceStore.getState().show(id, Object.keys(props).length ? props : void 0);
|
|
963
991
|
return;
|
|
964
992
|
}
|
|
965
993
|
const params = {};
|
|
@@ -1034,47 +1062,107 @@ var styles4 = import_react_native5.StyleSheet.create({
|
|
|
1034
1062
|
}
|
|
1035
1063
|
});
|
|
1036
1064
|
|
|
1037
|
-
// src/chat/
|
|
1065
|
+
// src/chat/QuestionChips.tsx
|
|
1038
1066
|
var import_react_native6 = require("react-native");
|
|
1039
1067
|
var import_core8 = require("@ateam-ai-mobile/core");
|
|
1040
1068
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1041
1069
|
var fontFam2 = import_react_native6.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
1070
|
+
function resolveOptions(inputType, options) {
|
|
1071
|
+
if (Array.isArray(options) && options.length) return options.filter((o) => typeof o === "string" && o.trim());
|
|
1072
|
+
if (inputType === "confirm") return ["Yes", "No"];
|
|
1073
|
+
return [];
|
|
1074
|
+
}
|
|
1075
|
+
function QuestionChips({
|
|
1076
|
+
inputType,
|
|
1077
|
+
options
|
|
1078
|
+
}) {
|
|
1079
|
+
const opts = resolveOptions(inputType, options);
|
|
1080
|
+
if (!opts.length) return null;
|
|
1081
|
+
const answer = (label) => {
|
|
1082
|
+
try {
|
|
1083
|
+
import_core8.useChatStore.getState().sendMessage(label);
|
|
1084
|
+
} catch {
|
|
1085
|
+
}
|
|
1086
|
+
};
|
|
1087
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native6.View, { style: styles5.row, children: opts.map((label, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1088
|
+
import_react_native6.Pressable,
|
|
1089
|
+
{
|
|
1090
|
+
accessibilityRole: "button",
|
|
1091
|
+
accessibilityLabel: label,
|
|
1092
|
+
onPress: () => answer(label),
|
|
1093
|
+
style: ({ pressed }) => [styles5.chip, pressed && styles5.chipPressed],
|
|
1094
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native6.Text, { style: styles5.label, numberOfLines: 2, children: label })
|
|
1095
|
+
},
|
|
1096
|
+
`${label}-${i}`
|
|
1097
|
+
)) });
|
|
1098
|
+
}
|
|
1099
|
+
var styles5 = import_react_native6.StyleSheet.create({
|
|
1100
|
+
row: {
|
|
1101
|
+
flexDirection: "row",
|
|
1102
|
+
flexWrap: "wrap",
|
|
1103
|
+
gap: 6,
|
|
1104
|
+
marginTop: 10
|
|
1105
|
+
},
|
|
1106
|
+
chip: {
|
|
1107
|
+
paddingHorizontal: 12,
|
|
1108
|
+
paddingVertical: 8,
|
|
1109
|
+
backgroundColor: import_core8.ada.orangeSoft,
|
|
1110
|
+
borderColor: import_core8.ada.orange,
|
|
1111
|
+
borderWidth: 1,
|
|
1112
|
+
borderRadius: 14
|
|
1113
|
+
},
|
|
1114
|
+
chipPressed: {
|
|
1115
|
+
backgroundColor: import_core8.ada.orange
|
|
1116
|
+
},
|
|
1117
|
+
label: {
|
|
1118
|
+
color: import_core8.ada.orangeDeep,
|
|
1119
|
+
fontSize: import_core8.fontSize.xs,
|
|
1120
|
+
fontWeight: "600",
|
|
1121
|
+
fontFamily: fontFam2
|
|
1122
|
+
}
|
|
1123
|
+
});
|
|
1124
|
+
|
|
1125
|
+
// src/chat/TableCardBlock.tsx
|
|
1126
|
+
var import_react_native7 = require("react-native");
|
|
1127
|
+
var import_core9 = require("@ateam-ai-mobile/core");
|
|
1128
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1129
|
+
var fontFam3 = import_react_native7.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
1042
1130
|
function TableCardBlock({ columns, rows }) {
|
|
1043
1131
|
if (!columns?.length || !rows?.length) return null;
|
|
1044
1132
|
const [titleCol, ...detailCols] = columns;
|
|
1045
|
-
return /* @__PURE__ */ (0,
|
|
1133
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.View, { style: styles6.wrap, children: rows.map((row, i) => {
|
|
1046
1134
|
const cells = Array.isArray(row) ? row : [row];
|
|
1047
1135
|
const title = cells[0];
|
|
1048
|
-
return /* @__PURE__ */ (0,
|
|
1049
|
-
/* @__PURE__ */ (0,
|
|
1050
|
-
detailCols.length > 0 && /* @__PURE__ */ (0,
|
|
1136
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native7.View, { style: styles6.card, children: [
|
|
1137
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.Text, { style: styles6.title, children: String(title ?? "") }),
|
|
1138
|
+
detailCols.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.View, { style: styles6.details, children: detailCols.map((col, ci) => {
|
|
1051
1139
|
const value = cells[ci + 1];
|
|
1052
1140
|
if (value == null || value === "") return null;
|
|
1053
|
-
return /* @__PURE__ */ (0,
|
|
1054
|
-
/* @__PURE__ */ (0,
|
|
1055
|
-
/* @__PURE__ */ (0,
|
|
1141
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native7.View, { style: styles6.row, children: [
|
|
1142
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.Text, { style: styles6.label, children: String(col) }),
|
|
1143
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.Text, { style: styles6.value, children: String(value) })
|
|
1056
1144
|
] }, ci);
|
|
1057
1145
|
}) })
|
|
1058
1146
|
] }, i);
|
|
1059
1147
|
}) });
|
|
1060
1148
|
}
|
|
1061
|
-
var
|
|
1149
|
+
var styles6 = import_react_native7.StyleSheet.create({
|
|
1062
1150
|
wrap: {
|
|
1063
1151
|
marginVertical: 6,
|
|
1064
1152
|
gap: 8
|
|
1065
1153
|
},
|
|
1066
1154
|
card: {
|
|
1067
|
-
backgroundColor:
|
|
1068
|
-
borderRadius:
|
|
1155
|
+
backgroundColor: import_core9.ada.paper,
|
|
1156
|
+
borderRadius: import_core9.borderRadius.md,
|
|
1069
1157
|
borderWidth: 1,
|
|
1070
|
-
borderColor:
|
|
1071
|
-
padding:
|
|
1158
|
+
borderColor: import_core9.ada.border,
|
|
1159
|
+
padding: import_core9.spacing.md
|
|
1072
1160
|
},
|
|
1073
1161
|
title: {
|
|
1074
|
-
color:
|
|
1075
|
-
fontSize:
|
|
1162
|
+
color: import_core9.ada.ink,
|
|
1163
|
+
fontSize: import_core9.fontSize.md,
|
|
1076
1164
|
fontWeight: "600",
|
|
1077
|
-
fontFamily:
|
|
1165
|
+
fontFamily: fontFam3,
|
|
1078
1166
|
letterSpacing: -0.2,
|
|
1079
1167
|
marginBottom: 6
|
|
1080
1168
|
},
|
|
@@ -1087,9 +1175,9 @@ var styles5 = import_react_native6.StyleSheet.create({
|
|
|
1087
1175
|
gap: 8
|
|
1088
1176
|
},
|
|
1089
1177
|
label: {
|
|
1090
|
-
color:
|
|
1091
|
-
fontSize:
|
|
1092
|
-
fontFamily:
|
|
1178
|
+
color: import_core9.ada.inkMuted,
|
|
1179
|
+
fontSize: import_core9.fontSize.xs,
|
|
1180
|
+
fontFamily: fontFam3,
|
|
1093
1181
|
fontWeight: "500",
|
|
1094
1182
|
width: 84,
|
|
1095
1183
|
textTransform: "uppercase",
|
|
@@ -1098,9 +1186,9 @@ var styles5 = import_react_native6.StyleSheet.create({
|
|
|
1098
1186
|
},
|
|
1099
1187
|
value: {
|
|
1100
1188
|
flex: 1,
|
|
1101
|
-
color:
|
|
1102
|
-
fontSize:
|
|
1103
|
-
fontFamily:
|
|
1189
|
+
color: import_core9.ada.inkSoft,
|
|
1190
|
+
fontSize: import_core9.fontSize.sm,
|
|
1191
|
+
fontFamily: fontFam3,
|
|
1104
1192
|
lineHeight: 18
|
|
1105
1193
|
}
|
|
1106
1194
|
});
|
|
@@ -1114,8 +1202,8 @@ var useLightboxStore = (0, import_zustand2.create)((set) => ({
|
|
|
1114
1202
|
}));
|
|
1115
1203
|
|
|
1116
1204
|
// src/chat/MessageBubble.tsx
|
|
1117
|
-
var
|
|
1118
|
-
var
|
|
1205
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1206
|
+
var fontFam4 = import_react_native8.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
1119
1207
|
function formatTime(date) {
|
|
1120
1208
|
const h = date.getHours();
|
|
1121
1209
|
const m = date.getMinutes().toString().padStart(2, "0");
|
|
@@ -1133,18 +1221,18 @@ function DaySeparator({ date }) {
|
|
|
1133
1221
|
} else {
|
|
1134
1222
|
label = date.toLocaleDateString(void 0, { weekday: "long", month: "short", day: "numeric" });
|
|
1135
1223
|
}
|
|
1136
|
-
return /* @__PURE__ */ (0,
|
|
1224
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.View, { style: separatorStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.View, { style: separatorStyles.pill, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: separatorStyles.text, children: label }) }) });
|
|
1137
1225
|
}
|
|
1138
1226
|
function isSameDay(a, b) {
|
|
1139
1227
|
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
1140
1228
|
}
|
|
1141
|
-
var separatorStyles =
|
|
1229
|
+
var separatorStyles = import_react_native8.StyleSheet.create({
|
|
1142
1230
|
container: {
|
|
1143
1231
|
alignItems: "center",
|
|
1144
1232
|
marginVertical: 14
|
|
1145
1233
|
},
|
|
1146
1234
|
pill: {
|
|
1147
|
-
backgroundColor:
|
|
1235
|
+
backgroundColor: import_core10.ada.paperSoft,
|
|
1148
1236
|
paddingHorizontal: 14,
|
|
1149
1237
|
paddingVertical: 5,
|
|
1150
1238
|
borderRadius: 999
|
|
@@ -1152,9 +1240,9 @@ var separatorStyles = import_react_native7.StyleSheet.create({
|
|
|
1152
1240
|
text: {
|
|
1153
1241
|
fontSize: 12,
|
|
1154
1242
|
fontWeight: "600",
|
|
1155
|
-
color:
|
|
1243
|
+
color: import_core10.ada.inkMuted,
|
|
1156
1244
|
letterSpacing: 0.4,
|
|
1157
|
-
fontFamily:
|
|
1245
|
+
fontFamily: fontFam4
|
|
1158
1246
|
}
|
|
1159
1247
|
});
|
|
1160
1248
|
function MessageBubble({ message }) {
|
|
@@ -1162,6 +1250,7 @@ function MessageBubble({ message }) {
|
|
|
1162
1250
|
const isSystem = message.role === "system";
|
|
1163
1251
|
const isNotification = !isUser && message.kind === "notification";
|
|
1164
1252
|
const st = message.jobProgress?.status;
|
|
1253
|
+
const pq = !isUser ? message.jobProgress?.pendingQuestion : void 0;
|
|
1165
1254
|
const isProgressOnly = !isUser && (st === "running" || st === "paused") && (!message.content?.trim() || message.content === "Working on it...");
|
|
1166
1255
|
const [copied, setCopied] = (0, import_react7.useState)("");
|
|
1167
1256
|
const showCopied = (0, import_react7.useCallback)((label) => {
|
|
@@ -1178,84 +1267,92 @@ function MessageBubble({ message }) {
|
|
|
1178
1267
|
const handleLongPress = (0, import_react7.useCallback)(() => {
|
|
1179
1268
|
copyText(message.content);
|
|
1180
1269
|
}, [message.content, copyText]);
|
|
1181
|
-
return /* @__PURE__ */ (0,
|
|
1182
|
-
!isUser && !isNotification && /* @__PURE__ */ (0,
|
|
1270
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native8.View, { style: [styles7.row, isUser && styles7.rowUser], children: [
|
|
1271
|
+
!isUser && !isNotification && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.View, { style: styles7.avatarOrb, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1183
1272
|
import_plugin_runtime6.AdaOrb,
|
|
1184
1273
|
{
|
|
1185
1274
|
size: 28,
|
|
1186
1275
|
state: message.jobProgress?.status === "running" ? "thinking" : "idle"
|
|
1187
1276
|
}
|
|
1188
1277
|
) }),
|
|
1189
|
-
isNotification && /* @__PURE__ */ (0,
|
|
1190
|
-
/* @__PURE__ */ (0,
|
|
1191
|
-
|
|
1278
|
+
isNotification && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.View, { style: styles7.notificationLeftStripe }),
|
|
1279
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
1280
|
+
import_react_native8.Pressable,
|
|
1192
1281
|
{
|
|
1193
1282
|
accessibilityRole: "text",
|
|
1194
1283
|
accessibilityLabel: `${isUser ? "You" : isNotification ? "Notification" : "Ada"}: ${message.content}`,
|
|
1195
1284
|
accessibilityHint: "Long-press to copy",
|
|
1196
1285
|
onLongPress: handleLongPress,
|
|
1197
1286
|
style: [
|
|
1198
|
-
|
|
1199
|
-
isUser &&
|
|
1200
|
-
isSystem &&
|
|
1201
|
-
isNotification &&
|
|
1202
|
-
isProgressOnly &&
|
|
1287
|
+
styles7.bubble,
|
|
1288
|
+
isUser && styles7.bubbleUser,
|
|
1289
|
+
isSystem && styles7.bubbleSystem,
|
|
1290
|
+
isNotification && styles7.bubbleNotification,
|
|
1291
|
+
isProgressOnly && styles7.bubbleProgress
|
|
1203
1292
|
],
|
|
1204
1293
|
children: [
|
|
1205
|
-
isNotification && /* @__PURE__ */ (0,
|
|
1206
|
-
/* @__PURE__ */ (0,
|
|
1207
|
-
/* @__PURE__ */ (0,
|
|
1294
|
+
isNotification && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native8.View, { style: styles7.notificationHeader, children: [
|
|
1295
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: styles7.notificationHeaderIcon, children: "\u{1F514}" }),
|
|
1296
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: styles7.notificationHeaderText, children: "Notification" })
|
|
1208
1297
|
] }),
|
|
1209
|
-
message.attachments && message.attachments.length > 0 && /* @__PURE__ */ (0,
|
|
1210
|
-
|
|
1298
|
+
message.attachments && message.attachments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.View, { style: styles7.attachments, children: message.attachments.map((att, i) => att.previewUri ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1299
|
+
import_react_native8.Pressable,
|
|
1211
1300
|
{
|
|
1212
1301
|
accessibilityRole: "imagebutton",
|
|
1213
1302
|
accessibilityLabel: `Photo${att.name ? `: ${att.name}` : ""}. Tap to enlarge.`,
|
|
1214
1303
|
onPress: () => useLightboxStore.getState().show(att.previewUri),
|
|
1215
|
-
children: /* @__PURE__ */ (0,
|
|
1216
|
-
|
|
1304
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1305
|
+
import_react_native8.Image,
|
|
1217
1306
|
{
|
|
1218
1307
|
source: {
|
|
1219
1308
|
uri: att.previewUri,
|
|
1220
1309
|
...att.previewUri.startsWith("http") ? {
|
|
1221
|
-
headers: { Authorization: `Bearer ${(0,
|
|
1310
|
+
headers: { Authorization: `Bearer ${(0, import_core10.getConfig)().tokenProvider.getToken()}` }
|
|
1222
1311
|
} : {}
|
|
1223
1312
|
},
|
|
1224
|
-
style:
|
|
1313
|
+
style: styles7.attachmentImage,
|
|
1225
1314
|
resizeMode: "cover",
|
|
1226
1315
|
onError: (e) => console.warn("[Image] Failed to load:", att.previewUri?.slice(0, 100), e.nativeEvent.error)
|
|
1227
1316
|
}
|
|
1228
1317
|
)
|
|
1229
1318
|
},
|
|
1230
1319
|
i
|
|
1231
|
-
) : /* @__PURE__ */ (0,
|
|
1320
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.View, { style: styles7.attachmentFile, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: styles7.attachmentFileName, numberOfLines: 1, children: att.name }) }, i)) }),
|
|
1232
1321
|
isUser ? (
|
|
1233
1322
|
// Hide the "See attachment" placeholder when the bubble already shows the photo.
|
|
1234
|
-
message.content && !(message.content === "See attachment" && message.attachments?.length) ? /* @__PURE__ */ (0,
|
|
1323
|
+
message.content && !(message.content === "See attachment" && message.attachments?.length) ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { selectable: true, style: styles7.userText, children: message.content }) : null
|
|
1235
1324
|
) : isProgressOnly ? (
|
|
1236
1325
|
// No "Working on it…" text — the indicator below is the whole message.
|
|
1237
1326
|
null
|
|
1238
|
-
) :
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1327
|
+
) : (
|
|
1328
|
+
// When the turn asked a question, show its clean question string —
|
|
1329
|
+
// never message.content, which may carry the raw JSON payload.
|
|
1330
|
+
renderAssistantContent(pq?.question || message.content, copyText)
|
|
1331
|
+
),
|
|
1332
|
+
!!copied && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.View, { style: styles7.copiedBadge, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: styles7.copiedText, children: copied }) }),
|
|
1333
|
+
message.toolCalls && message.toolCalls.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ToolCallsBadge, { calls: message.toolCalls }),
|
|
1334
|
+
message.jobProgress && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(JobProgressBar, { progress: message.jobProgress, standalone: isProgressOnly }),
|
|
1335
|
+
!isUser && message.actions && message.actions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(UIActionsRow, { actions: message.actions }),
|
|
1336
|
+
pq && // Per-chain: this bubble's OWN chain has a pending question. Parallel
|
|
1337
|
+
// pending chains each render their own chips (jobProgress is per
|
|
1338
|
+
// bubble); answered questions have no jobProgress → no chips.
|
|
1339
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(QuestionChips, { inputType: pq.inputType, options: pq.options }),
|
|
1340
|
+
!isProgressOnly && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: [styles7.timeText, isUser && styles7.timeTextUser], children: formatTime(message.timestamp) })
|
|
1244
1341
|
]
|
|
1245
1342
|
}
|
|
1246
1343
|
),
|
|
1247
|
-
isUser && /* @__PURE__ */ (0,
|
|
1344
|
+
isUser && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.View, { style: styles7.avatarSpacer })
|
|
1248
1345
|
] });
|
|
1249
1346
|
}
|
|
1250
1347
|
function renderAssistantContent(content, copyText) {
|
|
1251
1348
|
if (!content) return null;
|
|
1252
|
-
if (!content.includes(
|
|
1253
|
-
return /* @__PURE__ */ (0,
|
|
1349
|
+
if (!content.includes(import_core10.TABLE_BLOCK_OPEN)) {
|
|
1350
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MarkdownBubble, { content, copyText });
|
|
1254
1351
|
}
|
|
1255
1352
|
const segments = [];
|
|
1256
1353
|
let cursor = 0;
|
|
1257
1354
|
while (cursor < content.length) {
|
|
1258
|
-
const open = content.indexOf(
|
|
1355
|
+
const open = content.indexOf(import_core10.TABLE_BLOCK_OPEN, cursor);
|
|
1259
1356
|
if (open === -1) {
|
|
1260
1357
|
segments.push({ kind: "md", content: content.slice(cursor) });
|
|
1261
1358
|
break;
|
|
@@ -1263,37 +1360,37 @@ function renderAssistantContent(content, copyText) {
|
|
|
1263
1360
|
if (open > cursor) {
|
|
1264
1361
|
segments.push({ kind: "md", content: content.slice(cursor, open) });
|
|
1265
1362
|
}
|
|
1266
|
-
const close = content.indexOf(
|
|
1363
|
+
const close = content.indexOf(import_core10.TABLE_BLOCK_CLOSE, open + import_core10.TABLE_BLOCK_OPEN.length);
|
|
1267
1364
|
if (close === -1) {
|
|
1268
1365
|
segments.push({ kind: "md", content: content.slice(open) });
|
|
1269
1366
|
break;
|
|
1270
1367
|
}
|
|
1271
|
-
const payload = content.slice(open +
|
|
1368
|
+
const payload = content.slice(open + import_core10.TABLE_BLOCK_OPEN.length, close);
|
|
1272
1369
|
segments.push({ kind: "table", content: payload });
|
|
1273
|
-
cursor = close +
|
|
1370
|
+
cursor = close + import_core10.TABLE_BLOCK_CLOSE.length;
|
|
1274
1371
|
}
|
|
1275
|
-
return /* @__PURE__ */ (0,
|
|
1372
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: segments.map((seg, i) => {
|
|
1276
1373
|
if (seg.kind === "md") {
|
|
1277
1374
|
const trimmed = seg.content.trim();
|
|
1278
1375
|
if (!trimmed) return null;
|
|
1279
|
-
return /* @__PURE__ */ (0,
|
|
1376
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MarkdownBubble, { content: seg.content, copyText }, i);
|
|
1280
1377
|
}
|
|
1281
1378
|
try {
|
|
1282
1379
|
const data = JSON.parse(decodeURIComponent(seg.content));
|
|
1283
|
-
return /* @__PURE__ */ (0,
|
|
1380
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TableCardBlock, { columns: data.columns, rows: data.rows }, i);
|
|
1284
1381
|
} catch {
|
|
1285
1382
|
return null;
|
|
1286
1383
|
}
|
|
1287
1384
|
}) });
|
|
1288
1385
|
}
|
|
1289
1386
|
function MarkdownBubble({ content, copyText }) {
|
|
1290
|
-
return /* @__PURE__ */ (0,
|
|
1387
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1291
1388
|
import_react_native_markdown_display.default,
|
|
1292
1389
|
{
|
|
1293
1390
|
style: markdownStyles,
|
|
1294
1391
|
rules: {
|
|
1295
|
-
code_inline: (node) => /* @__PURE__ */ (0,
|
|
1296
|
-
|
|
1392
|
+
code_inline: (node) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1393
|
+
import_react_native8.Text,
|
|
1297
1394
|
{
|
|
1298
1395
|
style: markdownStyles.code_inline,
|
|
1299
1396
|
onPress: () => copyText(node.content),
|
|
@@ -1301,12 +1398,12 @@ function MarkdownBubble({ content, copyText }) {
|
|
|
1301
1398
|
},
|
|
1302
1399
|
node.key
|
|
1303
1400
|
),
|
|
1304
|
-
fence: (node) => /* @__PURE__ */ (0,
|
|
1305
|
-
|
|
1401
|
+
fence: (node) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1402
|
+
import_react_native8.Pressable,
|
|
1306
1403
|
{
|
|
1307
1404
|
onPress: () => copyText(node.content),
|
|
1308
1405
|
style: markdownStyles.fence,
|
|
1309
|
-
children: /* @__PURE__ */ (0,
|
|
1406
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: markdownStyles.fenceText, children: node.content })
|
|
1310
1407
|
},
|
|
1311
1408
|
node.key
|
|
1312
1409
|
)
|
|
@@ -1318,18 +1415,18 @@ function MarkdownBubble({ content, copyText }) {
|
|
|
1318
1415
|
function ToolCallsBadge({ calls }) {
|
|
1319
1416
|
const [expanded, setExpanded] = (0, import_react7.useState)(false);
|
|
1320
1417
|
const label = calls.filter((c) => c.name === "send_message_to_skill").map((c) => c.args.skill_name || c.skill).filter(Boolean).join(", ") || "Tool call";
|
|
1321
|
-
return /* @__PURE__ */ (0,
|
|
1322
|
-
/* @__PURE__ */ (0,
|
|
1323
|
-
/* @__PURE__ */ (0,
|
|
1324
|
-
/* @__PURE__ */ (0,
|
|
1418
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native8.View, { style: styles7.toolCalls, children: [
|
|
1419
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native8.Pressable, { style: styles7.toolToggle, onPress: () => setExpanded(!expanded), children: [
|
|
1420
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: styles7.toolLabel, children: label }),
|
|
1421
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: styles7.toolChevron, children: expanded ? "\u25B2" : "\u25BC" })
|
|
1325
1422
|
] }),
|
|
1326
|
-
expanded && calls.map((tc, i) => /* @__PURE__ */ (0,
|
|
1327
|
-
/* @__PURE__ */ (0,
|
|
1328
|
-
tc.skill && /* @__PURE__ */ (0,
|
|
1423
|
+
expanded && calls.map((tc, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native8.View, { style: styles7.toolItem, children: [
|
|
1424
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: styles7.toolName, children: tc.name }),
|
|
1425
|
+
tc.skill && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native8.Text, { style: styles7.toolSkill, children: tc.skill })
|
|
1329
1426
|
] }, i))
|
|
1330
1427
|
] });
|
|
1331
1428
|
}
|
|
1332
|
-
var
|
|
1429
|
+
var styles7 = import_react_native8.StyleSheet.create({
|
|
1333
1430
|
row: {
|
|
1334
1431
|
flexDirection: "row",
|
|
1335
1432
|
alignItems: "flex-end",
|
|
@@ -1352,15 +1449,15 @@ var styles6 = import_react_native7.StyleSheet.create({
|
|
|
1352
1449
|
},
|
|
1353
1450
|
bubble: {
|
|
1354
1451
|
maxWidth: "78%",
|
|
1355
|
-
backgroundColor:
|
|
1452
|
+
backgroundColor: import_core10.ada.botBubble,
|
|
1356
1453
|
borderWidth: 1,
|
|
1357
|
-
borderColor:
|
|
1358
|
-
borderRadius:
|
|
1454
|
+
borderColor: import_core10.ada.botBubbleBorder,
|
|
1455
|
+
borderRadius: import_core10.borderRadius.xl,
|
|
1359
1456
|
paddingHorizontal: 16,
|
|
1360
1457
|
paddingVertical: 12
|
|
1361
1458
|
},
|
|
1362
1459
|
bubbleUser: {
|
|
1363
|
-
backgroundColor:
|
|
1460
|
+
backgroundColor: import_core10.ada.userBubble,
|
|
1364
1461
|
borderColor: "transparent"
|
|
1365
1462
|
},
|
|
1366
1463
|
// Live-chain placeholder: no fill, no border, tighter padding — the
|
|
@@ -1372,20 +1469,20 @@ var styles6 = import_react_native7.StyleSheet.create({
|
|
|
1372
1469
|
paddingVertical: 2
|
|
1373
1470
|
},
|
|
1374
1471
|
bubbleSystem: {
|
|
1375
|
-
backgroundColor:
|
|
1376
|
-
borderColor:
|
|
1472
|
+
backgroundColor: import_core10.ada.orangeSoft,
|
|
1473
|
+
borderColor: import_core10.ada.orange,
|
|
1377
1474
|
maxWidth: "90%"
|
|
1378
1475
|
},
|
|
1379
1476
|
bubbleNotification: {
|
|
1380
|
-
backgroundColor:
|
|
1477
|
+
backgroundColor: import_core10.ada.orangeSoft,
|
|
1381
1478
|
borderColor: "rgba(255, 122, 40, 0.35)",
|
|
1382
|
-
borderRadius:
|
|
1479
|
+
borderRadius: import_core10.borderRadius.lg,
|
|
1383
1480
|
maxWidth: "90%"
|
|
1384
1481
|
},
|
|
1385
1482
|
notificationLeftStripe: {
|
|
1386
1483
|
width: 3,
|
|
1387
1484
|
alignSelf: "stretch",
|
|
1388
|
-
backgroundColor:
|
|
1485
|
+
backgroundColor: import_core10.ada.orange,
|
|
1389
1486
|
borderRadius: 2,
|
|
1390
1487
|
marginRight: 4
|
|
1391
1488
|
},
|
|
@@ -1399,25 +1496,25 @@ var styles6 = import_react_native7.StyleSheet.create({
|
|
|
1399
1496
|
fontSize: 12
|
|
1400
1497
|
},
|
|
1401
1498
|
notificationHeaderText: {
|
|
1402
|
-
color:
|
|
1499
|
+
color: import_core10.ada.orangeDeep,
|
|
1403
1500
|
fontSize: 11,
|
|
1404
1501
|
fontWeight: "700",
|
|
1405
1502
|
letterSpacing: 0.6,
|
|
1406
1503
|
textTransform: "uppercase",
|
|
1407
|
-
fontFamily:
|
|
1504
|
+
fontFamily: fontFam4
|
|
1408
1505
|
},
|
|
1409
1506
|
userText: {
|
|
1410
|
-
color:
|
|
1411
|
-
fontSize:
|
|
1507
|
+
color: import_core10.ada.userBubbleText,
|
|
1508
|
+
fontSize: import_core10.fontSize.md,
|
|
1412
1509
|
lineHeight: 22,
|
|
1413
|
-
fontFamily:
|
|
1510
|
+
fontFamily: fontFam4
|
|
1414
1511
|
},
|
|
1415
1512
|
timeText: {
|
|
1416
1513
|
fontSize: 11,
|
|
1417
|
-
color:
|
|
1514
|
+
color: import_core10.ada.inkMuted,
|
|
1418
1515
|
alignSelf: "flex-end",
|
|
1419
1516
|
marginTop: 4,
|
|
1420
|
-
fontFamily:
|
|
1517
|
+
fontFamily: fontFam4
|
|
1421
1518
|
},
|
|
1422
1519
|
timeTextUser: {
|
|
1423
1520
|
color: "rgba(250,246,238,0.55)"
|
|
@@ -1451,17 +1548,17 @@ var styles6 = import_react_native7.StyleSheet.create({
|
|
|
1451
1548
|
backgroundColor: "#5A8A5C",
|
|
1452
1549
|
paddingHorizontal: 8,
|
|
1453
1550
|
paddingVertical: 2,
|
|
1454
|
-
borderRadius:
|
|
1551
|
+
borderRadius: import_core10.borderRadius.sm
|
|
1455
1552
|
},
|
|
1456
1553
|
copiedText: {
|
|
1457
1554
|
color: "#fff",
|
|
1458
|
-
fontSize:
|
|
1555
|
+
fontSize: import_core10.fontSize.xs,
|
|
1459
1556
|
fontWeight: "600"
|
|
1460
1557
|
},
|
|
1461
1558
|
toolCalls: {
|
|
1462
1559
|
marginTop: 8,
|
|
1463
1560
|
borderTopWidth: 1,
|
|
1464
|
-
borderTopColor:
|
|
1561
|
+
borderTopColor: import_core10.ada.border,
|
|
1465
1562
|
paddingTop: 6
|
|
1466
1563
|
},
|
|
1467
1564
|
toolToggle: {
|
|
@@ -1470,12 +1567,12 @@ var styles6 = import_react_native7.StyleSheet.create({
|
|
|
1470
1567
|
gap: 6
|
|
1471
1568
|
},
|
|
1472
1569
|
toolLabel: {
|
|
1473
|
-
color:
|
|
1474
|
-
fontSize:
|
|
1570
|
+
color: import_core10.ada.inkSoft,
|
|
1571
|
+
fontSize: import_core10.fontSize.xs,
|
|
1475
1572
|
fontWeight: "500"
|
|
1476
1573
|
},
|
|
1477
1574
|
toolChevron: {
|
|
1478
|
-
color:
|
|
1575
|
+
color: import_core10.ada.inkMuted,
|
|
1479
1576
|
fontSize: 8
|
|
1480
1577
|
},
|
|
1481
1578
|
toolItem: {
|
|
@@ -1483,21 +1580,21 @@ var styles6 = import_react_native7.StyleSheet.create({
|
|
|
1483
1580
|
paddingLeft: 8
|
|
1484
1581
|
},
|
|
1485
1582
|
toolName: {
|
|
1486
|
-
color:
|
|
1487
|
-
fontSize:
|
|
1583
|
+
color: import_core10.ada.inkSoft,
|
|
1584
|
+
fontSize: import_core10.fontSize.xs,
|
|
1488
1585
|
fontFamily: "monospace"
|
|
1489
1586
|
},
|
|
1490
1587
|
toolSkill: {
|
|
1491
|
-
color:
|
|
1492
|
-
fontSize:
|
|
1588
|
+
color: import_core10.ada.orangeDeep,
|
|
1589
|
+
fontSize: import_core10.fontSize.xs
|
|
1493
1590
|
}
|
|
1494
1591
|
});
|
|
1495
|
-
var markdownStyles =
|
|
1592
|
+
var markdownStyles = import_react_native8.StyleSheet.create({
|
|
1496
1593
|
body: {
|
|
1497
|
-
color:
|
|
1498
|
-
fontSize:
|
|
1594
|
+
color: import_core10.ada.botBubbleText,
|
|
1595
|
+
fontSize: import_core10.fontSize.md,
|
|
1499
1596
|
lineHeight: 22,
|
|
1500
|
-
fontFamily:
|
|
1597
|
+
fontFamily: fontFam4
|
|
1501
1598
|
},
|
|
1502
1599
|
paragraph: {
|
|
1503
1600
|
marginTop: 0,
|
|
@@ -1505,35 +1602,35 @@ var markdownStyles = import_react_native7.StyleSheet.create({
|
|
|
1505
1602
|
},
|
|
1506
1603
|
strong: {
|
|
1507
1604
|
fontWeight: "700",
|
|
1508
|
-
color:
|
|
1605
|
+
color: import_core10.ada.botBubbleText
|
|
1509
1606
|
},
|
|
1510
1607
|
em: {
|
|
1511
1608
|
fontStyle: "italic"
|
|
1512
1609
|
},
|
|
1513
1610
|
code_inline: {
|
|
1514
|
-
backgroundColor:
|
|
1515
|
-
color:
|
|
1611
|
+
backgroundColor: import_core10.ada.paperDeep,
|
|
1612
|
+
color: import_core10.ada.orangeDeep,
|
|
1516
1613
|
paddingHorizontal: 5,
|
|
1517
1614
|
paddingVertical: 1,
|
|
1518
1615
|
borderRadius: 4,
|
|
1519
1616
|
fontFamily: "monospace",
|
|
1520
|
-
fontSize:
|
|
1617
|
+
fontSize: import_core10.fontSize.sm
|
|
1521
1618
|
},
|
|
1522
1619
|
fence: {
|
|
1523
|
-
backgroundColor:
|
|
1620
|
+
backgroundColor: import_core10.ada.paperDeep,
|
|
1524
1621
|
padding: 10,
|
|
1525
1622
|
borderRadius: 10
|
|
1526
1623
|
},
|
|
1527
1624
|
fenceText: {
|
|
1528
1625
|
fontFamily: "monospace",
|
|
1529
|
-
fontSize:
|
|
1530
|
-
color:
|
|
1626
|
+
fontSize: import_core10.fontSize.sm,
|
|
1627
|
+
color: import_core10.ada.ink
|
|
1531
1628
|
},
|
|
1532
1629
|
link: {
|
|
1533
|
-
color:
|
|
1630
|
+
color: import_core10.ada.orangeDeep
|
|
1534
1631
|
},
|
|
1535
1632
|
list_item: {
|
|
1536
|
-
color:
|
|
1633
|
+
color: import_core10.ada.botBubbleText
|
|
1537
1634
|
},
|
|
1538
1635
|
bullet_list: {
|
|
1539
1636
|
marginVertical: 4
|
|
@@ -1541,13 +1638,13 @@ var markdownStyles = import_react_native7.StyleSheet.create({
|
|
|
1541
1638
|
});
|
|
1542
1639
|
|
|
1543
1640
|
// src/chat/TypingIndicator.tsx
|
|
1544
|
-
var
|
|
1641
|
+
var import_react_native9 = require("react-native");
|
|
1545
1642
|
var import_plugin_runtime7 = require("@ateam-ai-mobile/plugin-runtime");
|
|
1546
|
-
var
|
|
1643
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1547
1644
|
function TypingIndicator() {
|
|
1548
|
-
return /* @__PURE__ */ (0,
|
|
1645
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native9.View, { style: styles8.row, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_plugin_runtime7.AdaOrb, { size: 32, state: "thinking" }) });
|
|
1549
1646
|
}
|
|
1550
|
-
var
|
|
1647
|
+
var styles8 = import_react_native9.StyleSheet.create({
|
|
1551
1648
|
row: {
|
|
1552
1649
|
flexDirection: "row",
|
|
1553
1650
|
alignItems: "center",
|
|
@@ -1559,11 +1656,11 @@ var styles7 = import_react_native8.StyleSheet.create({
|
|
|
1559
1656
|
|
|
1560
1657
|
// src/chat/ChatInput.tsx
|
|
1561
1658
|
var import_react8 = require("react");
|
|
1562
|
-
var
|
|
1659
|
+
var import_react_native10 = require("react-native");
|
|
1563
1660
|
var import_react_native_svg = __toESM(require("react-native-svg"));
|
|
1564
|
-
var
|
|
1661
|
+
var import_core11 = require("@ateam-ai-mobile/core");
|
|
1565
1662
|
var import_plugin_runtime8 = require("@ateam-ai-mobile/plugin-runtime");
|
|
1566
|
-
var
|
|
1663
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1567
1664
|
function ChatInput({ onSend, onCallStart, loading, prefill, placeholder }) {
|
|
1568
1665
|
const [text, setText] = (0, import_react8.useState)("");
|
|
1569
1666
|
const [height, setHeight] = (0, import_react8.useState)(40);
|
|
@@ -1583,55 +1680,55 @@ function ChatInput({ onSend, onCallStart, loading, prefill, placeholder }) {
|
|
|
1583
1680
|
setHeight(40);
|
|
1584
1681
|
}, [text, loading, onSend]);
|
|
1585
1682
|
const canSend = text.trim().length > 0;
|
|
1586
|
-
return /* @__PURE__ */ (0,
|
|
1587
|
-
onCallStart && /* @__PURE__ */ (0,
|
|
1588
|
-
/* @__PURE__ */ (0,
|
|
1589
|
-
|
|
1683
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native10.View, { style: styles9.dock, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native10.View, { style: styles9.inputRow, children: [
|
|
1684
|
+
onCallStart && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native10.Pressable, { style: styles9.callBtn, onPress: onCallStart, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_svg.default, { width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", stroke: import_core11.colors.light.accent, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_svg.Path, { d: "M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07 19.5 19.5 0 01-6-6 19.79 19.79 0 01-3.07-8.63A2 2 0 014.11 2h3a2 2 0 012 1.72 12.84 12.84 0 00.7 2.81 2 2 0 01-.45 2.11L8.09 9.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45 12.84 12.84 0 002.81.7A2 2 0 0122 16.92z" }) }) }),
|
|
1685
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1686
|
+
import_react_native10.TextInput,
|
|
1590
1687
|
{
|
|
1591
1688
|
ref: inputRef,
|
|
1592
|
-
style: [
|
|
1689
|
+
style: [styles9.input, { height: Math.min(Math.max(40, height), 120) }],
|
|
1593
1690
|
value: text,
|
|
1594
1691
|
onChangeText: setText,
|
|
1595
1692
|
onContentSizeChange: (e) => setHeight(e.nativeEvent.contentSize.height),
|
|
1596
1693
|
placeholder: placeholder || "Message A-Team...",
|
|
1597
|
-
placeholderTextColor:
|
|
1694
|
+
placeholderTextColor: import_core11.colors.light.textMuted,
|
|
1598
1695
|
multiline: true,
|
|
1599
1696
|
returnKeyType: "default",
|
|
1600
1697
|
blurOnSubmit: false,
|
|
1601
1698
|
onSubmitEditing: () => {
|
|
1602
|
-
if (
|
|
1699
|
+
if (import_react_native10.Platform.OS === "web") handleSend();
|
|
1603
1700
|
}
|
|
1604
1701
|
}
|
|
1605
1702
|
),
|
|
1606
|
-
/* @__PURE__ */ (0,
|
|
1607
|
-
|
|
1703
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1704
|
+
import_react_native10.Pressable,
|
|
1608
1705
|
{
|
|
1609
|
-
style: [
|
|
1706
|
+
style: [styles9.sendBtn, canSend && styles9.sendBtnActive],
|
|
1610
1707
|
onPress: handleSend,
|
|
1611
1708
|
disabled: !canSend,
|
|
1612
|
-
children: /* @__PURE__ */ (0,
|
|
1613
|
-
/* @__PURE__ */ (0,
|
|
1614
|
-
/* @__PURE__ */ (0,
|
|
1709
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native_svg.default, { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: canSend ? "#fff" : import_core11.colors.light.textMuted, strokeWidth: 2, children: [
|
|
1710
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_svg.Line, { x1: "22", y1: "2", x2: "11", y2: "13" }),
|
|
1711
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_svg.Polygon, { points: "22 2 15 22 11 13 2 9 22 2" })
|
|
1615
1712
|
] })
|
|
1616
1713
|
}
|
|
1617
1714
|
)
|
|
1618
1715
|
] }) });
|
|
1619
1716
|
}
|
|
1620
|
-
var
|
|
1717
|
+
var styles9 = import_react_native10.StyleSheet.create({
|
|
1621
1718
|
dock: {
|
|
1622
1719
|
paddingHorizontal: 12,
|
|
1623
1720
|
paddingVertical: 8,
|
|
1624
|
-
backgroundColor:
|
|
1721
|
+
backgroundColor: import_core11.colors.light.bgPrimary,
|
|
1625
1722
|
borderTopWidth: 0.5,
|
|
1626
|
-
borderTopColor:
|
|
1723
|
+
borderTopColor: import_core11.colors.light.border
|
|
1627
1724
|
},
|
|
1628
1725
|
inputRow: {
|
|
1629
1726
|
flexDirection: "row",
|
|
1630
1727
|
alignItems: "flex-end",
|
|
1631
|
-
backgroundColor:
|
|
1632
|
-
borderRadius:
|
|
1728
|
+
backgroundColor: import_core11.colors.light.bgInput,
|
|
1729
|
+
borderRadius: import_core11.borderRadius.xl,
|
|
1633
1730
|
borderWidth: 1,
|
|
1634
|
-
borderColor:
|
|
1731
|
+
borderColor: import_core11.colors.light.border,
|
|
1635
1732
|
paddingHorizontal: 4,
|
|
1636
1733
|
paddingVertical: 4,
|
|
1637
1734
|
gap: 4
|
|
@@ -1646,7 +1743,7 @@ var styles8 = import_react_native9.StyleSheet.create({
|
|
|
1646
1743
|
input: {
|
|
1647
1744
|
flex: 1,
|
|
1648
1745
|
fontSize: 16,
|
|
1649
|
-
color:
|
|
1746
|
+
color: import_core11.colors.light.textPrimary,
|
|
1650
1747
|
paddingHorizontal: 8,
|
|
1651
1748
|
paddingVertical: 8,
|
|
1652
1749
|
maxHeight: 120
|
|
@@ -1657,39 +1754,39 @@ var styles8 = import_react_native9.StyleSheet.create({
|
|
|
1657
1754
|
borderRadius: 18,
|
|
1658
1755
|
justifyContent: "center",
|
|
1659
1756
|
alignItems: "center",
|
|
1660
|
-
backgroundColor:
|
|
1757
|
+
backgroundColor: import_core11.colors.light.bgTertiary
|
|
1661
1758
|
},
|
|
1662
1759
|
sendBtnActive: {
|
|
1663
|
-
backgroundColor:
|
|
1760
|
+
backgroundColor: import_core11.colors.light.accent
|
|
1664
1761
|
}
|
|
1665
1762
|
});
|
|
1666
1763
|
|
|
1667
1764
|
// src/Lightbox.tsx
|
|
1668
|
-
var
|
|
1669
|
-
var
|
|
1670
|
-
var
|
|
1765
|
+
var import_react_native11 = require("react-native");
|
|
1766
|
+
var import_core12 = require("@ateam-ai-mobile/core");
|
|
1767
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1671
1768
|
function Lightbox() {
|
|
1672
1769
|
const uri = useLightboxStore((s) => s.uri);
|
|
1673
1770
|
const hide = useLightboxStore((s) => s.hide);
|
|
1674
1771
|
if (!uri) return null;
|
|
1675
|
-
return /* @__PURE__ */ (0,
|
|
1676
|
-
/* @__PURE__ */ (0,
|
|
1677
|
-
|
|
1772
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native11.Modal, { visible: true, transparent: true, animationType: "fade", onRequestClose: hide, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native11.Pressable, { style: styles10.backdrop, onPress: hide, children: [
|
|
1773
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1774
|
+
import_react_native11.Image,
|
|
1678
1775
|
{
|
|
1679
1776
|
source: {
|
|
1680
1777
|
uri,
|
|
1681
1778
|
...uri.startsWith("http") ? {
|
|
1682
|
-
headers: { Authorization: `Bearer ${(0,
|
|
1779
|
+
headers: { Authorization: `Bearer ${(0, import_core12.getConfig)().tokenProvider.getToken()}` }
|
|
1683
1780
|
} : {}
|
|
1684
1781
|
},
|
|
1685
|
-
style:
|
|
1782
|
+
style: styles10.image,
|
|
1686
1783
|
resizeMode: "contain"
|
|
1687
1784
|
}
|
|
1688
1785
|
),
|
|
1689
|
-
/* @__PURE__ */ (0,
|
|
1786
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native11.View, { style: styles10.closeHint, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native11.Text, { style: styles10.closeHintText, children: "Tap to close" }) })
|
|
1690
1787
|
] }) });
|
|
1691
1788
|
}
|
|
1692
|
-
var
|
|
1789
|
+
var styles10 = import_react_native11.StyleSheet.create({
|
|
1693
1790
|
backdrop: {
|
|
1694
1791
|
flex: 1,
|
|
1695
1792
|
backgroundColor: "rgba(0,0,0,0.92)",
|
|
@@ -1711,7 +1808,7 @@ var styles9 = import_react_native10.StyleSheet.create({
|
|
|
1711
1808
|
});
|
|
1712
1809
|
|
|
1713
1810
|
// src/AdasChatScreen.tsx
|
|
1714
|
-
var
|
|
1811
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1715
1812
|
function isSameDay2(a, b) {
|
|
1716
1813
|
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
1717
1814
|
}
|
|
@@ -1721,11 +1818,11 @@ function AdasChatScreen({
|
|
|
1721
1818
|
footerAccessory,
|
|
1722
1819
|
withLightbox = true
|
|
1723
1820
|
}) {
|
|
1724
|
-
const messages = (0,
|
|
1725
|
-
const loading = (0,
|
|
1726
|
-
const conversationLoaded = (0,
|
|
1727
|
-
const loadConversation = (0,
|
|
1728
|
-
const sendMessage = (0,
|
|
1821
|
+
const messages = (0, import_core13.useChatStore)((s) => s.messages);
|
|
1822
|
+
const loading = (0, import_core13.useChatStore)((s) => s.loading);
|
|
1823
|
+
const conversationLoaded = (0, import_core13.useChatStore)((s) => s.conversationLoaded);
|
|
1824
|
+
const loadConversation = (0, import_core13.useChatStore)((s) => s.loadConversation);
|
|
1825
|
+
const sendMessage = (0, import_core13.useChatStore)((s) => s.sendMessage);
|
|
1729
1826
|
const listRef = (0, import_react9.useRef)(null);
|
|
1730
1827
|
const [refreshing, setRefreshing] = (0, import_react9.useState)(false);
|
|
1731
1828
|
const [prefill, setPrefill] = (0, import_react9.useState)("");
|
|
@@ -1733,12 +1830,12 @@ function AdasChatScreen({
|
|
|
1733
1830
|
if (!conversationLoaded) loadConversation();
|
|
1734
1831
|
}, [conversationLoaded, loadConversation]);
|
|
1735
1832
|
(0, import_react9.useEffect)(() => {
|
|
1736
|
-
const unsub =
|
|
1833
|
+
const unsub = import_core13.pluginCommandEmitter.on("prepare-chat-message", ({ text }) => {
|
|
1737
1834
|
if (text) setPrefill(text);
|
|
1738
1835
|
});
|
|
1739
1836
|
return unsub;
|
|
1740
1837
|
}, []);
|
|
1741
|
-
const useInverted =
|
|
1838
|
+
const useInverted = import_react_native12.Platform.OS !== "web";
|
|
1742
1839
|
const listData = (0, import_react9.useMemo)(
|
|
1743
1840
|
() => useInverted ? [...messages].reverse() : messages,
|
|
1744
1841
|
[messages, useInverted]
|
|
@@ -1763,23 +1860,23 @@ function AdasChatScreen({
|
|
|
1763
1860
|
const renderItem = (0, import_react9.useCallback)(({ item, index }) => {
|
|
1764
1861
|
const older = useInverted ? listData[index + 1] : listData[index - 1];
|
|
1765
1862
|
const showDaySep = !older || !isSameDay2(older.timestamp, item.timestamp);
|
|
1766
|
-
return /* @__PURE__ */ (0,
|
|
1767
|
-
showDaySep && /* @__PURE__ */ (0,
|
|
1768
|
-
/* @__PURE__ */ (0,
|
|
1863
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react_native12.View, { children: [
|
|
1864
|
+
showDaySep && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DaySeparator, { date: item.timestamp }),
|
|
1865
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MessageBubble, { message: item })
|
|
1769
1866
|
] });
|
|
1770
1867
|
}, [listData, useInverted]);
|
|
1771
|
-
const typingIndicator = loading && !(useInverted ? listData[0] : listData[listData.length - 1])?.jobProgress ? /* @__PURE__ */ (0,
|
|
1772
|
-
return /* @__PURE__ */ (0,
|
|
1773
|
-
|
|
1868
|
+
const typingIndicator = loading && !(useInverted ? listData[0] : listData[listData.length - 1])?.jobProgress ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TypingIndicator, {}) : null;
|
|
1869
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1870
|
+
import_react_native12.KeyboardAvoidingView,
|
|
1774
1871
|
{
|
|
1775
|
-
style:
|
|
1776
|
-
behavior:
|
|
1872
|
+
style: styles11.root,
|
|
1873
|
+
behavior: import_react_native12.Platform.OS === "ios" ? "padding" : void 0,
|
|
1777
1874
|
children: [
|
|
1778
|
-
/* @__PURE__ */ (0,
|
|
1779
|
-
|
|
1875
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1876
|
+
import_react_native12.FlatList,
|
|
1780
1877
|
{
|
|
1781
1878
|
ref: listRef,
|
|
1782
|
-
style:
|
|
1879
|
+
style: styles11.list,
|
|
1783
1880
|
data: listData,
|
|
1784
1881
|
inverted: useInverted,
|
|
1785
1882
|
keyExtractor: (m) => m.id,
|
|
@@ -1787,13 +1884,13 @@ function AdasChatScreen({
|
|
|
1787
1884
|
ListHeaderComponent: useInverted ? typingIndicator : null,
|
|
1788
1885
|
ListFooterComponent: useInverted ? null : typingIndicator,
|
|
1789
1886
|
onContentSizeChange: useInverted ? void 0 : () => scrollToLatest(false),
|
|
1790
|
-
refreshControl: /* @__PURE__ */ (0,
|
|
1887
|
+
refreshControl: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native12.RefreshControl, { refreshing, onRefresh: handleRefresh, tintColor: import_core13.ada.orange }),
|
|
1791
1888
|
keyboardShouldPersistTaps: "handled",
|
|
1792
|
-
contentContainerStyle:
|
|
1889
|
+
contentContainerStyle: styles11.listContent
|
|
1793
1890
|
}
|
|
1794
1891
|
),
|
|
1795
1892
|
footerAccessory,
|
|
1796
|
-
/* @__PURE__ */ (0,
|
|
1893
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1797
1894
|
ChatInput,
|
|
1798
1895
|
{
|
|
1799
1896
|
onSend: handleSend,
|
|
@@ -1803,16 +1900,16 @@ function AdasChatScreen({
|
|
|
1803
1900
|
placeholder
|
|
1804
1901
|
}
|
|
1805
1902
|
),
|
|
1806
|
-
withLightbox && /* @__PURE__ */ (0,
|
|
1807
|
-
/* @__PURE__ */ (0,
|
|
1903
|
+
withLightbox && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Lightbox, {}),
|
|
1904
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(WidgetHost, {})
|
|
1808
1905
|
]
|
|
1809
1906
|
}
|
|
1810
1907
|
);
|
|
1811
1908
|
}
|
|
1812
|
-
var
|
|
1909
|
+
var styles11 = import_react_native12.StyleSheet.create({
|
|
1813
1910
|
root: {
|
|
1814
1911
|
flex: 1,
|
|
1815
|
-
backgroundColor:
|
|
1912
|
+
backgroundColor: import_core13.ada.paper
|
|
1816
1913
|
},
|
|
1817
1914
|
list: {
|
|
1818
1915
|
flex: 1
|
|
@@ -1824,42 +1921,42 @@ var styles10 = import_react_native11.StyleSheet.create({
|
|
|
1824
1921
|
|
|
1825
1922
|
// src/widgets/WidgetWebView.tsx
|
|
1826
1923
|
var import_react10 = require("react");
|
|
1827
|
-
var
|
|
1924
|
+
var import_react_native13 = require("react-native");
|
|
1828
1925
|
var import_react_native_webview2 = require("react-native-webview");
|
|
1829
|
-
var import_core13 = require("@ateam-ai-mobile/core");
|
|
1830
1926
|
var import_core14 = require("@ateam-ai-mobile/core");
|
|
1831
|
-
var
|
|
1832
|
-
var
|
|
1927
|
+
var import_core15 = require("@ateam-ai-mobile/core");
|
|
1928
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1929
|
+
var fontFam5 = import_react_native13.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
1833
1930
|
function WidgetWebView({ visible, title, bundleUrl, onClose }) {
|
|
1834
1931
|
const [loading, setLoading] = (0, import_react10.useState)(true);
|
|
1835
1932
|
const [error, setError] = (0, import_react10.useState)(null);
|
|
1836
1933
|
const uri = (0, import_react10.useMemo)(() => {
|
|
1837
1934
|
if (!bundleUrl) return null;
|
|
1838
1935
|
if (/^https?:\/\//i.test(bundleUrl)) return bundleUrl;
|
|
1839
|
-
return `${(0,
|
|
1936
|
+
return `${(0, import_core15.getCoreApiUrl)()}${bundleUrl}`;
|
|
1840
1937
|
}, [bundleUrl]);
|
|
1841
|
-
return /* @__PURE__ */ (0,
|
|
1842
|
-
|
|
1938
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1939
|
+
import_react_native13.Modal,
|
|
1843
1940
|
{
|
|
1844
1941
|
visible,
|
|
1845
1942
|
animationType: "slide",
|
|
1846
1943
|
presentationStyle: "pageSheet",
|
|
1847
1944
|
onRequestClose: onClose,
|
|
1848
|
-
children: /* @__PURE__ */ (0,
|
|
1849
|
-
/* @__PURE__ */ (0,
|
|
1850
|
-
/* @__PURE__ */ (0,
|
|
1851
|
-
/* @__PURE__ */ (0,
|
|
1852
|
-
/* @__PURE__ */ (0,
|
|
1945
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native13.View, { style: styles12.root, children: [
|
|
1946
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native13.View, { style: styles12.bar, children: [
|
|
1947
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.Pressable, { onPress: onClose, hitSlop: 12, style: styles12.closeBtn, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.Text, { style: styles12.closeIcon, children: "\u2715" }) }),
|
|
1948
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.Text, { style: styles12.title, numberOfLines: 1, children: title || "Widget" }),
|
|
1949
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.View, { style: styles12.closeBtn })
|
|
1853
1950
|
] }),
|
|
1854
|
-
!uri ? /* @__PURE__ */ (0,
|
|
1855
|
-
/* @__PURE__ */ (0,
|
|
1856
|
-
/* @__PURE__ */ (0,
|
|
1857
|
-
] }) : /* @__PURE__ */ (0,
|
|
1858
|
-
/* @__PURE__ */ (0,
|
|
1951
|
+
!uri ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.View, { style: styles12.errorWrap, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.Text, { style: styles12.errorText, children: "No bundle available for this widget." }) }) : error ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native13.View, { style: styles12.errorWrap, children: [
|
|
1952
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.Text, { style: styles12.errorText, children: "Couldn't load widget" }),
|
|
1953
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.Text, { style: styles12.errorSub, children: error })
|
|
1954
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
1955
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1859
1956
|
import_react_native_webview2.WebView,
|
|
1860
1957
|
{
|
|
1861
1958
|
source: { uri },
|
|
1862
|
-
style:
|
|
1959
|
+
style: styles12.web,
|
|
1863
1960
|
onLoadStart: () => {
|
|
1864
1961
|
setLoading(true);
|
|
1865
1962
|
setError(null);
|
|
@@ -1877,16 +1974,16 @@ function WidgetWebView({ visible, title, bundleUrl, onClose }) {
|
|
|
1877
1974
|
setSupportMultipleWindows: false
|
|
1878
1975
|
}
|
|
1879
1976
|
),
|
|
1880
|
-
loading && /* @__PURE__ */ (0,
|
|
1977
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.View, { pointerEvents: "none", style: styles12.spinner, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native13.ActivityIndicator, { color: import_core14.ada.orange }) })
|
|
1881
1978
|
] })
|
|
1882
1979
|
] })
|
|
1883
1980
|
}
|
|
1884
1981
|
);
|
|
1885
1982
|
}
|
|
1886
|
-
var
|
|
1983
|
+
var styles12 = import_react_native13.StyleSheet.create({
|
|
1887
1984
|
root: {
|
|
1888
1985
|
flex: 1,
|
|
1889
|
-
backgroundColor:
|
|
1986
|
+
backgroundColor: import_core14.ada.paper
|
|
1890
1987
|
},
|
|
1891
1988
|
bar: {
|
|
1892
1989
|
flexDirection: "row",
|
|
@@ -1894,8 +1991,8 @@ var styles11 = import_react_native12.StyleSheet.create({
|
|
|
1894
1991
|
paddingHorizontal: 14,
|
|
1895
1992
|
paddingVertical: 12,
|
|
1896
1993
|
borderBottomWidth: 1,
|
|
1897
|
-
borderBottomColor:
|
|
1898
|
-
backgroundColor:
|
|
1994
|
+
borderBottomColor: import_core14.ada.border,
|
|
1995
|
+
backgroundColor: import_core14.ada.paperSoft
|
|
1899
1996
|
},
|
|
1900
1997
|
closeBtn: {
|
|
1901
1998
|
width: 32,
|
|
@@ -1905,7 +2002,7 @@ var styles11 = import_react_native12.StyleSheet.create({
|
|
|
1905
2002
|
},
|
|
1906
2003
|
closeIcon: {
|
|
1907
2004
|
fontSize: 18,
|
|
1908
|
-
color:
|
|
2005
|
+
color: import_core14.ada.ink,
|
|
1909
2006
|
fontWeight: "500"
|
|
1910
2007
|
},
|
|
1911
2008
|
title: {
|
|
@@ -1913,13 +2010,13 @@ var styles11 = import_react_native12.StyleSheet.create({
|
|
|
1913
2010
|
textAlign: "center",
|
|
1914
2011
|
fontSize: 16,
|
|
1915
2012
|
fontWeight: "600",
|
|
1916
|
-
color:
|
|
1917
|
-
fontFamily:
|
|
2013
|
+
color: import_core14.ada.ink,
|
|
2014
|
+
fontFamily: fontFam5,
|
|
1918
2015
|
letterSpacing: -0.2
|
|
1919
2016
|
},
|
|
1920
2017
|
web: {
|
|
1921
2018
|
flex: 1,
|
|
1922
|
-
backgroundColor:
|
|
2019
|
+
backgroundColor: import_core14.ada.paper
|
|
1923
2020
|
},
|
|
1924
2021
|
spinner: {
|
|
1925
2022
|
position: "absolute",
|
|
@@ -1936,31 +2033,31 @@ var styles11 = import_react_native12.StyleSheet.create({
|
|
|
1936
2033
|
},
|
|
1937
2034
|
errorText: {
|
|
1938
2035
|
fontSize: 15,
|
|
1939
|
-
color:
|
|
2036
|
+
color: import_core14.ada.ink,
|
|
1940
2037
|
fontWeight: "600",
|
|
1941
2038
|
marginBottom: 6
|
|
1942
2039
|
},
|
|
1943
2040
|
errorSub: {
|
|
1944
2041
|
fontSize: 13,
|
|
1945
|
-
color:
|
|
2042
|
+
color: import_core14.ada.inkMuted,
|
|
1946
2043
|
textAlign: "center"
|
|
1947
2044
|
}
|
|
1948
2045
|
});
|
|
1949
2046
|
|
|
1950
2047
|
// src/TenantPicker.tsx
|
|
1951
2048
|
var import_react11 = require("react");
|
|
1952
|
-
var
|
|
1953
|
-
var
|
|
1954
|
-
var
|
|
1955
|
-
var
|
|
2049
|
+
var import_react_native14 = require("react-native");
|
|
2050
|
+
var import_core16 = require("@ateam-ai-mobile/core");
|
|
2051
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2052
|
+
var fontFam6 = import_react_native14.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
1956
2053
|
function TenantPicker({ onSwitched, onSelect, currentTenantId }) {
|
|
1957
2054
|
const [tenants, setTenants] = (0, import_react11.useState)(null);
|
|
1958
2055
|
const [error, setError] = (0, import_react11.useState)(null);
|
|
1959
2056
|
const [switching, setSwitching] = (0, import_react11.useState)(null);
|
|
1960
|
-
const active = currentTenantId ?? (0,
|
|
2057
|
+
const active = currentTenantId ?? (0, import_core16.getTenant)();
|
|
1961
2058
|
(0, import_react11.useEffect)(() => {
|
|
1962
2059
|
let cancelled = false;
|
|
1963
|
-
(0,
|
|
2060
|
+
(0, import_core16.listMyTenants)().then((list) => {
|
|
1964
2061
|
if (!cancelled) setTenants(list);
|
|
1965
2062
|
}).catch((e) => {
|
|
1966
2063
|
if (!cancelled) setError(e?.message || "Failed to load teams");
|
|
@@ -1978,7 +2075,7 @@ function TenantPicker({ onSwitched, onSelect, currentTenantId }) {
|
|
|
1978
2075
|
setError(null);
|
|
1979
2076
|
setSwitching(t.id);
|
|
1980
2077
|
try {
|
|
1981
|
-
const session = await (0,
|
|
2078
|
+
const session = await (0, import_core16.switchTenant)(t.id);
|
|
1982
2079
|
onSwitched?.(session);
|
|
1983
2080
|
} catch (e) {
|
|
1984
2081
|
setError(e?.message || "Could not switch team");
|
|
@@ -1986,36 +2083,36 @@ function TenantPicker({ onSwitched, onSelect, currentTenantId }) {
|
|
|
1986
2083
|
setSwitching(null);
|
|
1987
2084
|
}
|
|
1988
2085
|
};
|
|
1989
|
-
if (error) return /* @__PURE__ */ (0,
|
|
2086
|
+
if (error) return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.Text, { style: styles13.error, children: error });
|
|
1990
2087
|
if (!tenants) {
|
|
1991
|
-
return /* @__PURE__ */ (0,
|
|
2088
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.View, { style: styles13.loading, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.ActivityIndicator, { color: import_core16.ada.orange }) });
|
|
1992
2089
|
}
|
|
1993
|
-
if (tenants.length === 0) return /* @__PURE__ */ (0,
|
|
1994
|
-
return /* @__PURE__ */ (0,
|
|
2090
|
+
if (tenants.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.Text, { style: styles13.empty, children: "No teams found for this account." });
|
|
2091
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.View, { style: styles13.list, children: tenants.map((t) => {
|
|
1995
2092
|
const isActive = t.id === active;
|
|
1996
2093
|
const isSwitching = switching === t.id;
|
|
1997
|
-
return /* @__PURE__ */ (0,
|
|
1998
|
-
|
|
2094
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
2095
|
+
import_react_native14.Pressable,
|
|
1999
2096
|
{
|
|
2000
2097
|
accessibilityRole: "button",
|
|
2001
2098
|
accessibilityLabel: `Team ${t.name}${isActive ? ", current" : ""}`,
|
|
2002
2099
|
disabled: !!switching,
|
|
2003
2100
|
onPress: () => handlePress(t),
|
|
2004
|
-
style: [
|
|
2101
|
+
style: [styles13.row, isActive && styles13.rowActive],
|
|
2005
2102
|
children: [
|
|
2006
|
-
/* @__PURE__ */ (0,
|
|
2007
|
-
/* @__PURE__ */ (0,
|
|
2008
|
-
/* @__PURE__ */ (0,
|
|
2009
|
-
/* @__PURE__ */ (0,
|
|
2103
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.View, { style: styles13.dot }),
|
|
2104
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native14.View, { style: styles13.rowText, children: [
|
|
2105
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.Text, { style: styles13.name, children: t.name }),
|
|
2106
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.Text, { style: styles13.slug, children: t.id })
|
|
2010
2107
|
] }),
|
|
2011
|
-
isSwitching ? /* @__PURE__ */ (0,
|
|
2108
|
+
isSwitching ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.ActivityIndicator, { color: import_core16.ada.orange }) : isActive ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.Text, { style: styles13.check, children: "\u2713" }) : null
|
|
2012
2109
|
]
|
|
2013
2110
|
},
|
|
2014
2111
|
t.id
|
|
2015
2112
|
);
|
|
2016
2113
|
}) });
|
|
2017
2114
|
}
|
|
2018
|
-
var
|
|
2115
|
+
var styles13 = import_react_native14.StyleSheet.create({
|
|
2019
2116
|
list: {
|
|
2020
2117
|
gap: 10
|
|
2021
2118
|
},
|
|
@@ -2023,40 +2120,40 @@ var styles12 = import_react_native13.StyleSheet.create({
|
|
|
2023
2120
|
flexDirection: "row",
|
|
2024
2121
|
alignItems: "center",
|
|
2025
2122
|
gap: 12,
|
|
2026
|
-
backgroundColor:
|
|
2027
|
-
borderRadius:
|
|
2123
|
+
backgroundColor: import_core16.ada.paperSoft,
|
|
2124
|
+
borderRadius: import_core16.borderRadius.lg,
|
|
2028
2125
|
borderWidth: 1,
|
|
2029
2126
|
borderColor: "transparent",
|
|
2030
2127
|
paddingHorizontal: 16,
|
|
2031
2128
|
paddingVertical: 14
|
|
2032
2129
|
},
|
|
2033
2130
|
rowActive: {
|
|
2034
|
-
backgroundColor:
|
|
2035
|
-
borderColor:
|
|
2131
|
+
backgroundColor: import_core16.ada.orangeSoft,
|
|
2132
|
+
borderColor: import_core16.ada.orange
|
|
2036
2133
|
},
|
|
2037
2134
|
dot: {
|
|
2038
2135
|
width: 10,
|
|
2039
2136
|
height: 10,
|
|
2040
2137
|
borderRadius: 5,
|
|
2041
|
-
backgroundColor:
|
|
2138
|
+
backgroundColor: import_core16.ada.orange
|
|
2042
2139
|
},
|
|
2043
2140
|
rowText: {
|
|
2044
2141
|
flex: 1
|
|
2045
2142
|
},
|
|
2046
2143
|
name: {
|
|
2047
|
-
color:
|
|
2048
|
-
fontSize:
|
|
2144
|
+
color: import_core16.ada.ink,
|
|
2145
|
+
fontSize: import_core16.fontSize.lg,
|
|
2049
2146
|
fontWeight: "600",
|
|
2050
|
-
fontFamily:
|
|
2147
|
+
fontFamily: fontFam6
|
|
2051
2148
|
},
|
|
2052
2149
|
slug: {
|
|
2053
|
-
color:
|
|
2054
|
-
fontSize:
|
|
2150
|
+
color: import_core16.ada.inkMuted,
|
|
2151
|
+
fontSize: import_core16.fontSize.sm,
|
|
2055
2152
|
fontFamily: "monospace"
|
|
2056
2153
|
},
|
|
2057
2154
|
check: {
|
|
2058
|
-
color:
|
|
2059
|
-
fontSize:
|
|
2155
|
+
color: import_core16.ada.orangeDeep,
|
|
2156
|
+
fontSize: import_core16.fontSize.lg,
|
|
2060
2157
|
fontWeight: "700"
|
|
2061
2158
|
},
|
|
2062
2159
|
loading: {
|
|
@@ -2064,30 +2161,535 @@ var styles12 = import_react_native13.StyleSheet.create({
|
|
|
2064
2161
|
alignItems: "center"
|
|
2065
2162
|
},
|
|
2066
2163
|
empty: {
|
|
2067
|
-
color:
|
|
2068
|
-
fontSize:
|
|
2164
|
+
color: import_core16.ada.inkMuted,
|
|
2165
|
+
fontSize: import_core16.fontSize.md,
|
|
2069
2166
|
textAlign: "center",
|
|
2070
2167
|
paddingVertical: 16
|
|
2071
2168
|
},
|
|
2072
2169
|
error: {
|
|
2073
2170
|
color: "#C15545",
|
|
2074
|
-
fontSize:
|
|
2171
|
+
fontSize: import_core16.fontSize.md,
|
|
2075
2172
|
textAlign: "center",
|
|
2076
2173
|
paddingVertical: 16
|
|
2077
2174
|
}
|
|
2078
2175
|
});
|
|
2079
2176
|
|
|
2080
|
-
// src/
|
|
2081
|
-
var
|
|
2082
|
-
var import_react_native14 = require("react-native");
|
|
2083
|
-
var import_react_native_svg2 = __toESM(require("react-native-svg"));
|
|
2084
|
-
var import_react_native_webview3 = require("react-native-webview");
|
|
2177
|
+
// src/WorkspaceBanner.tsx
|
|
2178
|
+
var import_react_native15 = require("react-native");
|
|
2085
2179
|
var import_core17 = require("@ateam-ai-mobile/core");
|
|
2180
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
2181
|
+
var WARM_AMBER2 = "#D49A4E";
|
|
2182
|
+
var WARM_AMBER_SOFT2 = "rgba(212, 154, 78, 0.16)";
|
|
2183
|
+
var WARM_AMBER_BORDER = "rgba(212, 154, 78, 0.4)";
|
|
2184
|
+
function WorkspaceBanner({ topInset = 0 }) {
|
|
2185
|
+
const snapshot = (0, import_core17.useWorkspaceStore)((s) => s.snapshot);
|
|
2186
|
+
if (!snapshot) return null;
|
|
2187
|
+
if (snapshot.state === "active" || snapshot.state === "unknown") return null;
|
|
2188
|
+
if (!snapshot.message) return null;
|
|
2189
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
2190
|
+
import_react_native15.View,
|
|
2191
|
+
{
|
|
2192
|
+
style: [styles14.container, { paddingTop: import_core17.spacing.sm + topInset }],
|
|
2193
|
+
accessibilityRole: "alert",
|
|
2194
|
+
accessibilityLabel: snapshot.message,
|
|
2195
|
+
children: [
|
|
2196
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native15.View, { style: styles14.dot }),
|
|
2197
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native15.Text, { style: styles14.message, children: snapshot.message })
|
|
2198
|
+
]
|
|
2199
|
+
}
|
|
2200
|
+
);
|
|
2201
|
+
}
|
|
2202
|
+
var styles14 = import_react_native15.StyleSheet.create({
|
|
2203
|
+
container: {
|
|
2204
|
+
flexDirection: "row",
|
|
2205
|
+
alignItems: "flex-start",
|
|
2206
|
+
gap: import_core17.spacing.sm,
|
|
2207
|
+
paddingHorizontal: import_core17.spacing.md,
|
|
2208
|
+
paddingBottom: import_core17.spacing.sm,
|
|
2209
|
+
backgroundColor: WARM_AMBER_SOFT2,
|
|
2210
|
+
borderBottomWidth: import_react_native15.StyleSheet.hairlineWidth,
|
|
2211
|
+
borderBottomColor: WARM_AMBER_BORDER
|
|
2212
|
+
},
|
|
2213
|
+
dot: {
|
|
2214
|
+
width: 8,
|
|
2215
|
+
height: 8,
|
|
2216
|
+
borderRadius: 4,
|
|
2217
|
+
marginTop: 5,
|
|
2218
|
+
backgroundColor: WARM_AMBER2
|
|
2219
|
+
},
|
|
2220
|
+
message: {
|
|
2221
|
+
flex: 1,
|
|
2222
|
+
color: import_core17.ada.ink,
|
|
2223
|
+
fontSize: import_core17.fontSize.sm,
|
|
2224
|
+
lineHeight: import_core17.fontSize.sm * 1.35
|
|
2225
|
+
}
|
|
2226
|
+
});
|
|
2227
|
+
|
|
2228
|
+
// src/auth/HandoffScreen.tsx
|
|
2229
|
+
var import_react12 = require("react");
|
|
2230
|
+
var import_react_native16 = require("react-native");
|
|
2231
|
+
var import_core18 = require("@ateam-ai-mobile/core");
|
|
2086
2232
|
var import_plugin_runtime9 = require("@ateam-ai-mobile/plugin-runtime");
|
|
2087
2233
|
|
|
2234
|
+
// src/auth/handoffExchange.ts
|
|
2235
|
+
async function runHandoffExchange(code, deps) {
|
|
2236
|
+
const res = await deps.exchange(code);
|
|
2237
|
+
if (res.tenant) await deps.onAdoptTenant(res.tenant);
|
|
2238
|
+
await deps.onSignedIn(res.jwt);
|
|
2239
|
+
deps.onDone();
|
|
2240
|
+
}
|
|
2241
|
+
function handoffErrorMessage(msg) {
|
|
2242
|
+
const m = (msg || "").toLowerCase();
|
|
2243
|
+
if (m.includes("429") || m.includes("rate") || m.includes("too many")) {
|
|
2244
|
+
return "Too many attempts \u2014 wait a moment, then get a new sign-in link on the web.";
|
|
2245
|
+
}
|
|
2246
|
+
return "This sign-in link is no longer valid. Get a new one on the web and try again.";
|
|
2247
|
+
}
|
|
2248
|
+
|
|
2249
|
+
// src/auth/HandoffScreen.tsx
|
|
2250
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
2251
|
+
var fontFam7 = import_react_native16.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
2252
|
+
function HandoffScreen({ code, onAdoptTenant, onSignedIn, onDone, onCancel }) {
|
|
2253
|
+
const [err, setErr] = (0, import_react12.useState)(null);
|
|
2254
|
+
const startedForRef = (0, import_react12.useRef)(null);
|
|
2255
|
+
(0, import_react12.useEffect)(() => {
|
|
2256
|
+
if (!code || startedForRef.current === code) return;
|
|
2257
|
+
startedForRef.current = code;
|
|
2258
|
+
runHandoffExchange(code, { exchange: import_core18.exchangeHandoff, onAdoptTenant, onSignedIn, onDone }).catch((e) => setErr(handoffErrorMessage(e?.message)));
|
|
2259
|
+
}, [code, onAdoptTenant, onSignedIn, onDone]);
|
|
2260
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native16.View, { style: styles15.container, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_react_native16.View, { style: styles15.center, children: [
|
|
2261
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_plugin_runtime9.AdaOrb, { size: 72, state: err ? "idle" : "thinking" }),
|
|
2262
|
+
!err ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
2263
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native16.Text, { style: styles15.title, children: "Signing you in\u2026" }),
|
|
2264
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native16.ActivityIndicator, { color: import_core18.ada.ink, style: { marginTop: 6 } })
|
|
2265
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
2266
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native16.Text, { style: styles15.title, children: "Couldn\u2019t finish sign-in" }),
|
|
2267
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native16.Text, { style: styles15.sub, children: err }),
|
|
2268
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native16.Pressable, { onPress: onCancel, hitSlop: 8, style: styles15.back, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native16.Text, { style: styles15.backText, children: "Back to sign in" }) })
|
|
2269
|
+
] })
|
|
2270
|
+
] }) });
|
|
2271
|
+
}
|
|
2272
|
+
var styles15 = import_react_native16.StyleSheet.create({
|
|
2273
|
+
container: { flex: 1, backgroundColor: import_core18.ada.paper },
|
|
2274
|
+
center: { flex: 1, alignItems: "center", justifyContent: "center", gap: 14, paddingHorizontal: 32 },
|
|
2275
|
+
title: { fontSize: 20, fontWeight: "600", color: import_core18.ada.ink, fontFamily: fontFam7, marginTop: 8 },
|
|
2276
|
+
sub: { fontSize: 14, lineHeight: 20, color: import_core18.ada.inkSoft, textAlign: "center", fontFamily: fontFam7 },
|
|
2277
|
+
back: { marginTop: 10, paddingVertical: 10 },
|
|
2278
|
+
backText: { fontSize: 15, fontWeight: "600", color: import_core18.ada.orangeDeep, fontFamily: fontFam7 }
|
|
2279
|
+
});
|
|
2280
|
+
|
|
2281
|
+
// src/auth/OpenJoinScreen.tsx
|
|
2282
|
+
var import_react13 = require("react");
|
|
2283
|
+
var import_react_native17 = require("react-native");
|
|
2284
|
+
var import_core19 = require("@ateam-ai-mobile/core");
|
|
2285
|
+
var import_plugin_runtime10 = require("@ateam-ai-mobile/plugin-runtime");
|
|
2286
|
+
|
|
2287
|
+
// src/auth/openJoin.ts
|
|
2288
|
+
async function completeOpenJoin(slug, idToken, deps) {
|
|
2289
|
+
if (!idToken) return false;
|
|
2290
|
+
const consumer = await deps.join(slug, idToken);
|
|
2291
|
+
await deps.onAdoptTenant(slug);
|
|
2292
|
+
await deps.onSignedIn(consumer.jwt);
|
|
2293
|
+
return true;
|
|
2294
|
+
}
|
|
2295
|
+
function openJoinErrorMessage(msg) {
|
|
2296
|
+
const m = (msg || "").toLowerCase();
|
|
2297
|
+
if (m.includes("invite-only") || m.includes("invite only")) {
|
|
2298
|
+
return "This team is invite-only \u2014 ask an admin for an invite link.";
|
|
2299
|
+
}
|
|
2300
|
+
if (m.includes("not found") || m.includes("unknown tenant")) {
|
|
2301
|
+
return "No team with that handle.";
|
|
2302
|
+
}
|
|
2303
|
+
return msg || "Could not join";
|
|
2304
|
+
}
|
|
2305
|
+
|
|
2306
|
+
// src/auth/OpenJoinScreen.tsx
|
|
2307
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
2308
|
+
var fontFam8 = import_react_native17.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
2309
|
+
function OpenJoinScreen({ onAdoptTenant, onSignedIn, onBack }) {
|
|
2310
|
+
const [team, setTeam] = (0, import_react13.useState)("");
|
|
2311
|
+
const [busy, setBusy] = (0, import_react13.useState)(false);
|
|
2312
|
+
const [err, setErr] = (0, import_react13.useState)(null);
|
|
2313
|
+
const [appleAvailable, setAppleAvailable] = (0, import_react13.useState)(false);
|
|
2314
|
+
(0, import_react13.useEffect)(() => {
|
|
2315
|
+
getOAuthProvider()?.isAppleAvailable().then(setAppleAvailable).catch(() => setAppleAvailable(false));
|
|
2316
|
+
}, []);
|
|
2317
|
+
const slug = team.trim().toLowerCase();
|
|
2318
|
+
const canSubmit = slug.length > 0 && !busy;
|
|
2319
|
+
async function run(acquire, join) {
|
|
2320
|
+
if (!slug) return;
|
|
2321
|
+
const oauth = getOAuthProvider();
|
|
2322
|
+
if (!oauth) {
|
|
2323
|
+
setErr("Sign-in is unavailable on this device.");
|
|
2324
|
+
return;
|
|
2325
|
+
}
|
|
2326
|
+
setErr(null);
|
|
2327
|
+
setBusy(true);
|
|
2328
|
+
try {
|
|
2329
|
+
const idToken = await acquire(oauth);
|
|
2330
|
+
await completeOpenJoin(slug, idToken, { join, onAdoptTenant, onSignedIn });
|
|
2331
|
+
} catch (e) {
|
|
2332
|
+
setErr(openJoinErrorMessage(e?.message));
|
|
2333
|
+
} finally {
|
|
2334
|
+
setBusy(false);
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2337
|
+
const handleGoogle = () => run((oauth) => oauth.signInWithGoogle(), import_core19.openJoinWithGoogle);
|
|
2338
|
+
const handleApple = () => run((oauth) => oauth.signInWithApple(), import_core19.openJoinWithApple);
|
|
2339
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native17.View, { style: styles16.container, children: [
|
|
2340
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native17.View, { style: styles16.hero, children: [
|
|
2341
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_plugin_runtime10.AdaOrb, { size: 110 }),
|
|
2342
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native17.Text, { style: styles16.wordmark, children: "Join a team" }),
|
|
2343
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native17.Text, { style: styles16.tagline, children: "Enter the team's handle. If it's open to join, you're in." })
|
|
2344
|
+
] }),
|
|
2345
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native17.View, { style: styles16.form, children: [
|
|
2346
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2347
|
+
import_react_native17.TextInput,
|
|
2348
|
+
{
|
|
2349
|
+
style: styles16.input,
|
|
2350
|
+
value: team,
|
|
2351
|
+
onChangeText: setTeam,
|
|
2352
|
+
placeholder: "team handle (e.g. acme)",
|
|
2353
|
+
placeholderTextColor: import_core19.ada.inkMuted,
|
|
2354
|
+
autoCapitalize: "none",
|
|
2355
|
+
autoCorrect: false,
|
|
2356
|
+
returnKeyType: "done"
|
|
2357
|
+
}
|
|
2358
|
+
),
|
|
2359
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
2360
|
+
import_react_native17.Pressable,
|
|
2361
|
+
{
|
|
2362
|
+
style: [styles16.googleBtn, !canSubmit && styles16.btnDisabled],
|
|
2363
|
+
onPress: handleGoogle,
|
|
2364
|
+
disabled: !canSubmit,
|
|
2365
|
+
children: [
|
|
2366
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native17.Text, { style: styles16.googleGlyph, children: "G" }),
|
|
2367
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native17.Text, { style: styles16.googleText, children: "Continue with Google" })
|
|
2368
|
+
]
|
|
2369
|
+
}
|
|
2370
|
+
),
|
|
2371
|
+
appleAvailable && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native17.View, { style: { opacity: canSubmit ? 1 : 0.5 }, pointerEvents: canSubmit ? "auto" : "none", children: getOAuthProvider()?.renderAppleButton({ onPress: handleApple, disabled: !canSubmit, style: styles16.appleBtn }) }),
|
|
2372
|
+
busy && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native17.ActivityIndicator, { color: import_core19.ada.ink, style: { marginTop: 10 } }),
|
|
2373
|
+
!!err && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native17.Text, { style: styles16.err, children: err }),
|
|
2374
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native17.Pressable, { onPress: onBack, hitSlop: 8, style: styles16.back, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native17.Text, { style: styles16.backText, children: "Back to sign in" }) })
|
|
2375
|
+
] })
|
|
2376
|
+
] });
|
|
2377
|
+
}
|
|
2378
|
+
var styles16 = import_react_native17.StyleSheet.create({
|
|
2379
|
+
container: { flex: 1, backgroundColor: import_core19.ada.paper, justifyContent: "space-between" },
|
|
2380
|
+
hero: { alignItems: "center", marginTop: import_core19.spacing.xxl },
|
|
2381
|
+
wordmark: { fontSize: 26, fontWeight: "800", color: import_core19.ada.ink, marginTop: 14, fontFamily: fontFam8 },
|
|
2382
|
+
tagline: { fontSize: 15, color: import_core19.ada.inkSoft, marginTop: 8, textAlign: "center", paddingHorizontal: 28, fontFamily: fontFam8 },
|
|
2383
|
+
form: { paddingHorizontal: 24, paddingBottom: 40, gap: 12 },
|
|
2384
|
+
input: {
|
|
2385
|
+
backgroundColor: import_core19.ada.paperSoft,
|
|
2386
|
+
borderWidth: 1,
|
|
2387
|
+
borderColor: import_core19.ada.border,
|
|
2388
|
+
borderRadius: 14,
|
|
2389
|
+
paddingHorizontal: 16,
|
|
2390
|
+
paddingVertical: 14,
|
|
2391
|
+
fontSize: 16,
|
|
2392
|
+
color: import_core19.ada.ink
|
|
2393
|
+
},
|
|
2394
|
+
googleBtn: {
|
|
2395
|
+
flexDirection: "row",
|
|
2396
|
+
alignItems: "center",
|
|
2397
|
+
justifyContent: "center",
|
|
2398
|
+
gap: 10,
|
|
2399
|
+
backgroundColor: import_core19.ada.ink,
|
|
2400
|
+
paddingVertical: 15,
|
|
2401
|
+
borderRadius: 999
|
|
2402
|
+
},
|
|
2403
|
+
btnDisabled: { opacity: 0.5 },
|
|
2404
|
+
googleGlyph: { color: "#fff", fontSize: 18, fontWeight: "800" },
|
|
2405
|
+
googleText: { color: "#fff", fontSize: 16, fontWeight: "600", fontFamily: fontFam8 },
|
|
2406
|
+
appleBtn: { height: 52, width: "100%" },
|
|
2407
|
+
err: { color: "#C15545", fontSize: 13, textAlign: "center", paddingHorizontal: 16, marginTop: 4 },
|
|
2408
|
+
back: { alignItems: "center", paddingVertical: 10 },
|
|
2409
|
+
backText: { color: import_core19.ada.inkMuted, fontSize: 15, fontWeight: "500" }
|
|
2410
|
+
});
|
|
2411
|
+
|
|
2412
|
+
// src/auth/JoinScreen.tsx
|
|
2413
|
+
var import_react14 = require("react");
|
|
2414
|
+
var import_react_native18 = require("react-native");
|
|
2415
|
+
var import_core20 = require("@ateam-ai-mobile/core");
|
|
2416
|
+
var import_plugin_runtime11 = require("@ateam-ai-mobile/plugin-runtime");
|
|
2417
|
+
|
|
2418
|
+
// src/auth/inviteJoin.ts
|
|
2419
|
+
async function completeInviteJoin(code, idToken, deps) {
|
|
2420
|
+
if (!idToken) return false;
|
|
2421
|
+
const consumer = await deps.join(code, idToken);
|
|
2422
|
+
deps.onDone();
|
|
2423
|
+
await deps.onSignedIn(consumer.jwt);
|
|
2424
|
+
return true;
|
|
2425
|
+
}
|
|
2426
|
+
function inviteHeadline(preview) {
|
|
2427
|
+
if (!preview) return "";
|
|
2428
|
+
return preview.role ? `Join ${preview.org} as ${preview.role}?` : `Join ${preview.org}?`;
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
// src/auth/JoinScreen.tsx
|
|
2432
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
2433
|
+
var fontFam9 = import_react_native18.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
2434
|
+
function JoinScreen({ code, onSignedIn, onDone, onCancel }) {
|
|
2435
|
+
const [preview, setPreview] = (0, import_react14.useState)(null);
|
|
2436
|
+
const [loadErr, setLoadErr] = (0, import_react14.useState)(null);
|
|
2437
|
+
const [busy, setBusy] = (0, import_react14.useState)(false);
|
|
2438
|
+
const [err, setErr] = (0, import_react14.useState)(null);
|
|
2439
|
+
const [appleAvailable, setAppleAvailable] = (0, import_react14.useState)(false);
|
|
2440
|
+
(0, import_react14.useEffect)(() => {
|
|
2441
|
+
if (!code) return;
|
|
2442
|
+
setPreview(null);
|
|
2443
|
+
setLoadErr(null);
|
|
2444
|
+
(0, import_core20.previewInvite)(code).then(setPreview).catch((e) => setLoadErr(e?.message || "Could not load invite"));
|
|
2445
|
+
}, [code]);
|
|
2446
|
+
(0, import_react14.useEffect)(() => {
|
|
2447
|
+
getOAuthProvider()?.isAppleAvailable().then(setAppleAvailable).catch(() => setAppleAvailable(false));
|
|
2448
|
+
}, []);
|
|
2449
|
+
const orgLine = (0, import_react14.useMemo)(() => inviteHeadline(preview), [preview]);
|
|
2450
|
+
async function run(acquire, join) {
|
|
2451
|
+
if (!code) return;
|
|
2452
|
+
const oauth = getOAuthProvider();
|
|
2453
|
+
if (!oauth) {
|
|
2454
|
+
setErr("Sign-in is unavailable on this device.");
|
|
2455
|
+
return;
|
|
2456
|
+
}
|
|
2457
|
+
setErr(null);
|
|
2458
|
+
setBusy(true);
|
|
2459
|
+
try {
|
|
2460
|
+
const idToken = await acquire(oauth);
|
|
2461
|
+
await completeInviteJoin(code, idToken, { join, onDone, onSignedIn });
|
|
2462
|
+
} catch (e) {
|
|
2463
|
+
setErr(e?.message || "Sign-in failed");
|
|
2464
|
+
} finally {
|
|
2465
|
+
setBusy(false);
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
const handleGoogle = () => run((oauth) => oauth.signInWithGoogle(), import_core20.joinWithGoogle);
|
|
2469
|
+
const handleApple = () => run((oauth) => oauth.signInWithApple(), import_core20.joinWithApple);
|
|
2470
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_native18.View, { style: styles17.container, children: [
|
|
2471
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_native18.View, { style: styles17.hero, children: [
|
|
2472
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_plugin_runtime11.AdaOrb, { size: 120 }),
|
|
2473
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.Text, { style: styles17.wordmark, children: "ada" }),
|
|
2474
|
+
loadErr ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.Text, { style: styles17.err, children: loadErr }) : preview ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.Text, { style: styles17.tagline, children: orgLine }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.ActivityIndicator, { color: import_core20.ada.ink, style: { marginTop: 12 } })
|
|
2475
|
+
] }),
|
|
2476
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_native18.View, { style: styles17.buttons, children: [
|
|
2477
|
+
preview && !loadErr && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
2478
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
2479
|
+
import_react_native18.Pressable,
|
|
2480
|
+
{
|
|
2481
|
+
style: [styles17.googleBtn, busy && styles17.btnDisabled],
|
|
2482
|
+
onPress: handleGoogle,
|
|
2483
|
+
disabled: busy,
|
|
2484
|
+
children: [
|
|
2485
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.Text, { style: styles17.googleGlyph, children: "G" }),
|
|
2486
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.Text, { style: styles17.googleText, children: "Continue with Google" })
|
|
2487
|
+
]
|
|
2488
|
+
}
|
|
2489
|
+
),
|
|
2490
|
+
appleAvailable && getOAuthProvider()?.renderAppleButton({ onPress: handleApple, disabled: busy, style: styles17.appleBtn })
|
|
2491
|
+
] }),
|
|
2492
|
+
loadErr && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.Pressable, { style: styles17.dismiss, onPress: onCancel, hitSlop: 8, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.Text, { style: styles17.dismissText, children: "Back to sign in" }) }),
|
|
2493
|
+
!!err && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.Text, { style: styles17.err, children: err }),
|
|
2494
|
+
busy && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.ActivityIndicator, { color: import_core20.ada.ink, style: { marginTop: 12 } }),
|
|
2495
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native18.Text, { style: styles17.disclaimer, children: "By continuing you agree to Ada's Terms and Privacy Policy." })
|
|
2496
|
+
] })
|
|
2497
|
+
] });
|
|
2498
|
+
}
|
|
2499
|
+
var styles17 = import_react_native18.StyleSheet.create({
|
|
2500
|
+
container: { flex: 1, backgroundColor: import_core20.ada.paper, justifyContent: "space-between" },
|
|
2501
|
+
hero: { alignItems: "center", marginTop: import_core20.spacing.xxl * 1.4 },
|
|
2502
|
+
wordmark: { fontSize: 34, fontWeight: "800", color: import_core20.ada.ink, letterSpacing: 4, marginTop: 12, fontFamily: fontFam9 },
|
|
2503
|
+
tagline: { fontSize: 17, color: import_core20.ada.inkSoft, marginTop: 10, textAlign: "center", paddingHorizontal: 24, fontFamily: fontFam9 },
|
|
2504
|
+
buttons: { paddingHorizontal: 24, paddingBottom: 40, gap: 12 },
|
|
2505
|
+
googleBtn: {
|
|
2506
|
+
flexDirection: "row",
|
|
2507
|
+
alignItems: "center",
|
|
2508
|
+
justifyContent: "center",
|
|
2509
|
+
gap: 10,
|
|
2510
|
+
backgroundColor: import_core20.ada.ink,
|
|
2511
|
+
paddingVertical: 15,
|
|
2512
|
+
borderRadius: 999
|
|
2513
|
+
},
|
|
2514
|
+
btnDisabled: { opacity: 0.5 },
|
|
2515
|
+
googleGlyph: { color: "#fff", fontSize: 18, fontWeight: "800" },
|
|
2516
|
+
googleText: { color: "#fff", fontSize: 16, fontWeight: "600", fontFamily: fontFam9 },
|
|
2517
|
+
appleBtn: { height: 52, width: "100%" },
|
|
2518
|
+
dismiss: { alignItems: "center", paddingVertical: 10 },
|
|
2519
|
+
dismissText: { color: import_core20.ada.inkMuted, fontSize: 15, fontWeight: "500" },
|
|
2520
|
+
err: { color: "#C15545", fontSize: 13, textAlign: "center", paddingHorizontal: 16, marginTop: 8 },
|
|
2521
|
+
disclaimer: { fontSize: 12, color: import_core20.ada.inkMuted, textAlign: "center", marginTop: 8 }
|
|
2522
|
+
});
|
|
2523
|
+
|
|
2524
|
+
// src/auth/LoginScreen.tsx
|
|
2525
|
+
var import_react15 = require("react");
|
|
2526
|
+
var import_react_native19 = require("react-native");
|
|
2527
|
+
var import_core21 = require("@ateam-ai-mobile/core");
|
|
2528
|
+
var import_plugin_runtime12 = require("@ateam-ai-mobile/plugin-runtime");
|
|
2529
|
+
|
|
2530
|
+
// src/auth/login.ts
|
|
2531
|
+
function googleClientIds(config) {
|
|
2532
|
+
const g = config.providers.google || {};
|
|
2533
|
+
return {
|
|
2534
|
+
webClientId: g.web_client_id || g.client_id || "",
|
|
2535
|
+
iosClientId: g.ios_client_id || ""
|
|
2536
|
+
};
|
|
2537
|
+
}
|
|
2538
|
+
function shouldRecoverToDefaultTenant(errorMsg, currentTenant, defaultTenant) {
|
|
2539
|
+
return /capability not enabled/i.test(errorMsg || "") && currentTenant !== defaultTenant;
|
|
2540
|
+
}
|
|
2541
|
+
async function completeProviderSignIn(idToken, deps) {
|
|
2542
|
+
if (!idToken) return false;
|
|
2543
|
+
const consumer = await deps.exchange(idToken);
|
|
2544
|
+
await deps.onSignedIn(consumer.jwt);
|
|
2545
|
+
return true;
|
|
2546
|
+
}
|
|
2547
|
+
|
|
2548
|
+
// src/auth/LoginScreen.tsx
|
|
2549
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
2550
|
+
var fontFam10 = import_react_native19.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
2551
|
+
function LoginScreen({ activeTenant, defaultTenant, onConsumerDisabled, onSignedIn, onJoinTeam }) {
|
|
2552
|
+
const [config, setConfig] = (0, import_react15.useState)(null);
|
|
2553
|
+
const [error, setError] = (0, import_react15.useState)(null);
|
|
2554
|
+
(0, import_react15.useEffect)(() => {
|
|
2555
|
+
setConfig(null);
|
|
2556
|
+
setError(null);
|
|
2557
|
+
(0, import_core21.fetchConsumerConfig)().then(setConfig).catch(async (err) => {
|
|
2558
|
+
const msg = err?.message || "Failed to load sign-in config";
|
|
2559
|
+
if (shouldRecoverToDefaultTenant(msg, activeTenant, defaultTenant)) {
|
|
2560
|
+
await onConsumerDisabled();
|
|
2561
|
+
return;
|
|
2562
|
+
}
|
|
2563
|
+
setError(msg);
|
|
2564
|
+
});
|
|
2565
|
+
}, [activeTenant, defaultTenant, onConsumerDisabled]);
|
|
2566
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_native19.View, { style: styles18.container, children: [
|
|
2567
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_native19.View, { style: styles18.hero, children: [
|
|
2568
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_plugin_runtime12.AdaOrb, { size: 140 }),
|
|
2569
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.Text, { style: styles18.wordmark, children: "ada" }),
|
|
2570
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.Text, { style: styles18.tagline, children: "Your private personal AI-Team" })
|
|
2571
|
+
] }),
|
|
2572
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_native19.View, { style: styles18.buttonSection, children: [
|
|
2573
|
+
!config && !error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.ActivityIndicator, { color: import_core21.ada.ink }),
|
|
2574
|
+
!!error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.Text, { style: styles18.errorText, children: error }),
|
|
2575
|
+
!!config && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SignInButtons, { config, onSignedIn }),
|
|
2576
|
+
onJoinTeam && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.Pressable, { onPress: onJoinTeam, hitSlop: 8, style: { paddingVertical: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.Text, { style: styles18.joinLink, children: "Join a team by name" }) }),
|
|
2577
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.Text, { style: styles18.disclaimer, children: "By continuing you agree to Ada's Terms and Privacy Policy." })
|
|
2578
|
+
] })
|
|
2579
|
+
] });
|
|
2580
|
+
}
|
|
2581
|
+
function SignInButtons({ config, onSignedIn }) {
|
|
2582
|
+
const [busy, setBusy] = (0, import_react15.useState)(false);
|
|
2583
|
+
const [error, setError] = (0, import_react15.useState)(null);
|
|
2584
|
+
const [appleAvailable, setAppleAvailable] = (0, import_react15.useState)(false);
|
|
2585
|
+
const { webClientId, iosClientId } = (0, import_react15.useMemo)(() => googleClientIds(config), [config]);
|
|
2586
|
+
(0, import_react15.useEffect)(() => {
|
|
2587
|
+
getOAuthProvider()?.isAppleAvailable().then(setAppleAvailable).catch(() => setAppleAvailable(false));
|
|
2588
|
+
}, []);
|
|
2589
|
+
const handleGoogleLogin = async () => {
|
|
2590
|
+
setError(null);
|
|
2591
|
+
if (!webClientId) {
|
|
2592
|
+
setError("Google sign-in is not configured for this tenant");
|
|
2593
|
+
return;
|
|
2594
|
+
}
|
|
2595
|
+
const oauth = getOAuthProvider();
|
|
2596
|
+
if (!oauth) {
|
|
2597
|
+
setError("Sign-in is unavailable on this device.");
|
|
2598
|
+
return;
|
|
2599
|
+
}
|
|
2600
|
+
setBusy(true);
|
|
2601
|
+
try {
|
|
2602
|
+
const idToken = await oauth.signInWithGoogle({ webClientId, iosClientId });
|
|
2603
|
+
await completeProviderSignIn(idToken, { exchange: import_core21.signInWithGoogle, onSignedIn });
|
|
2604
|
+
} catch (err) {
|
|
2605
|
+
setError(err?.message || "Sign-in failed");
|
|
2606
|
+
} finally {
|
|
2607
|
+
setBusy(false);
|
|
2608
|
+
}
|
|
2609
|
+
};
|
|
2610
|
+
const handleAppleLogin = async () => {
|
|
2611
|
+
setError(null);
|
|
2612
|
+
const oauth = getOAuthProvider();
|
|
2613
|
+
if (!oauth) {
|
|
2614
|
+
setError("Sign-in is unavailable on this device.");
|
|
2615
|
+
return;
|
|
2616
|
+
}
|
|
2617
|
+
setBusy(true);
|
|
2618
|
+
try {
|
|
2619
|
+
const idToken = await oauth.signInWithApple();
|
|
2620
|
+
await completeProviderSignIn(idToken, { exchange: import_core21.signInWithApple, onSignedIn });
|
|
2621
|
+
} catch (err) {
|
|
2622
|
+
setError(err?.message || "Apple sign-in failed");
|
|
2623
|
+
} finally {
|
|
2624
|
+
setBusy(false);
|
|
2625
|
+
}
|
|
2626
|
+
};
|
|
2627
|
+
const googleEnabled = !!webClientId && !busy;
|
|
2628
|
+
const appleEnabled = appleAvailable && !!config.providers.apple?.service_id && !busy;
|
|
2629
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
|
|
2630
|
+
!!config.providers.google && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
2631
|
+
import_react_native19.Pressable,
|
|
2632
|
+
{
|
|
2633
|
+
style: [styles18.signInBtn, !googleEnabled && styles18.signInBtnDisabled],
|
|
2634
|
+
onPress: handleGoogleLogin,
|
|
2635
|
+
disabled: !googleEnabled,
|
|
2636
|
+
children: [
|
|
2637
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.Text, { style: styles18.signInGlyph, children: "G" }),
|
|
2638
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.Text, { style: styles18.signInText, children: "Continue with Google" })
|
|
2639
|
+
]
|
|
2640
|
+
}
|
|
2641
|
+
),
|
|
2642
|
+
appleEnabled && getOAuthProvider()?.renderAppleButton({ onPress: handleAppleLogin, disabled: busy, style: styles18.appleBtn }),
|
|
2643
|
+
!!error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.Text, { style: styles18.errorText, children: error }),
|
|
2644
|
+
busy && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native19.ActivityIndicator, { color: import_core21.ada.ink })
|
|
2645
|
+
] });
|
|
2646
|
+
}
|
|
2647
|
+
var styles18 = import_react_native19.StyleSheet.create({
|
|
2648
|
+
container: {
|
|
2649
|
+
flex: 1,
|
|
2650
|
+
backgroundColor: import_core21.ada.paper,
|
|
2651
|
+
justifyContent: "space-between",
|
|
2652
|
+
paddingHorizontal: 32,
|
|
2653
|
+
paddingBottom: 24
|
|
2654
|
+
},
|
|
2655
|
+
hero: { flex: 1, alignItems: "center", justifyContent: "center", gap: 18 },
|
|
2656
|
+
wordmark: { fontSize: 32, fontWeight: "600", color: import_core21.ada.ink, letterSpacing: 4, fontFamily: fontFam10, marginTop: 8 },
|
|
2657
|
+
tagline: { fontSize: 16, fontWeight: "500", color: import_core21.ada.inkSoft, letterSpacing: -0.1, fontFamily: fontFam10 },
|
|
2658
|
+
buttonSection: { alignItems: "center", gap: 12 },
|
|
2659
|
+
signInBtn: {
|
|
2660
|
+
flexDirection: "row",
|
|
2661
|
+
alignItems: "center",
|
|
2662
|
+
justifyContent: "center",
|
|
2663
|
+
backgroundColor: import_core21.ada.ink,
|
|
2664
|
+
paddingVertical: 16,
|
|
2665
|
+
paddingHorizontal: 24,
|
|
2666
|
+
borderRadius: 999,
|
|
2667
|
+
width: "100%",
|
|
2668
|
+
gap: 12
|
|
2669
|
+
},
|
|
2670
|
+
signInBtnDisabled: { opacity: 0.5 },
|
|
2671
|
+
signInGlyph: { fontSize: 18, fontWeight: "700", color: import_core21.ada.paper, fontFamily: fontFam10 },
|
|
2672
|
+
signInText: { fontSize: 16, fontWeight: "600", color: import_core21.ada.paper, letterSpacing: -0.2, fontFamily: fontFam10 },
|
|
2673
|
+
appleBtn: { width: "100%", height: 52 },
|
|
2674
|
+
errorText: { fontSize: 13, color: "#c43d3d", textAlign: "center", paddingHorizontal: 16 },
|
|
2675
|
+
disclaimer: { fontSize: 12, color: import_core21.ada.inkMuted, textAlign: "center", marginTop: 8, lineHeight: 18, fontFamily: fontFam10 },
|
|
2676
|
+
joinLink: { fontSize: 14, fontWeight: "600", color: import_core21.ada.orangeDeep, textAlign: "center", fontFamily: fontFam10 }
|
|
2677
|
+
});
|
|
2678
|
+
|
|
2679
|
+
// src/voice/VoiceCallSheet.tsx
|
|
2680
|
+
var import_react17 = require("react");
|
|
2681
|
+
var import_react_native20 = require("react-native");
|
|
2682
|
+
var import_react_native_svg2 = __toESM(require("react-native-svg"));
|
|
2683
|
+
var import_core23 = require("@ateam-ai-mobile/core");
|
|
2684
|
+
var import_plugin_runtime14 = require("@ateam-ai-mobile/plugin-runtime");
|
|
2685
|
+
|
|
2088
2686
|
// src/voice/useVoiceCall.ts
|
|
2089
|
-
var
|
|
2090
|
-
|
|
2687
|
+
var import_react16 = require("react");
|
|
2688
|
+
|
|
2689
|
+
// src/voice/voiceSession.ts
|
|
2690
|
+
var import_core22 = require("@ateam-ai-mobile/core");
|
|
2691
|
+
var import_plugin_runtime13 = require("@ateam-ai-mobile/plugin-runtime");
|
|
2692
|
+
var CONNECT_TIMEOUT_MS = 3e4;
|
|
2091
2693
|
var TOKEN_REFRESH_SKEW_MS = 9e4;
|
|
2092
2694
|
function tokenNeedsRefresh(token) {
|
|
2093
2695
|
if (!token) return true;
|
|
@@ -2115,7 +2717,6 @@ var INJECT_TRACK_HOOK = `
|
|
|
2115
2717
|
}
|
|
2116
2718
|
}
|
|
2117
2719
|
|
|
2118
|
-
// 1) Hook getUserMedia \u2014 captures mic streams at request time.
|
|
2119
2720
|
try {
|
|
2120
2721
|
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
|
|
2121
2722
|
const origGUM = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);
|
|
@@ -2129,7 +2730,6 @@ var INJECT_TRACK_HOOK = `
|
|
|
2129
2730
|
}
|
|
2130
2731
|
} catch (e) {}
|
|
2131
2732
|
|
|
2132
|
-
// 2) Hook RTCPeerConnection.addTrack \u2014 catches whatever the app sends.
|
|
2133
2733
|
try {
|
|
2134
2734
|
if (window.RTCPeerConnection) {
|
|
2135
2735
|
const origPC = window.RTCPeerConnection;
|
|
@@ -2149,9 +2749,7 @@ var INJECT_TRACK_HOOK = `
|
|
|
2149
2749
|
}
|
|
2150
2750
|
if (origAddTransceiver) {
|
|
2151
2751
|
origPC.prototype.addTransceiver = function(arg) {
|
|
2152
|
-
if (arg && arg.kind === 'audio') {
|
|
2153
|
-
// Transceiver created with kind 'audio' \u2014 sender track set later.
|
|
2154
|
-
} else if (arg && arg.kind === undefined && arg.track && arg.track.kind === 'audio') {
|
|
2752
|
+
if (arg && arg.kind === undefined && arg.track && arg.track.kind === 'audio') {
|
|
2155
2753
|
track(arg.track);
|
|
2156
2754
|
}
|
|
2157
2755
|
const tx = origAddTransceiver.apply(this, arguments);
|
|
@@ -2164,7 +2762,6 @@ var INJECT_TRACK_HOOK = `
|
|
|
2164
2762
|
}
|
|
2165
2763
|
} catch (e) {}
|
|
2166
2764
|
|
|
2167
|
-
// 3) Helper exposed for direct calls.
|
|
2168
2765
|
window._adaSetMuted = function(muted) {
|
|
2169
2766
|
let n = 0;
|
|
2170
2767
|
if (Array.isArray(window._allAudioTracks)) {
|
|
@@ -2183,7 +2780,6 @@ var buildMuteScript = (muted) => `
|
|
|
2183
2780
|
if (typeof window._adaSetMuted === 'function') {
|
|
2184
2781
|
n = window._adaSetMuted(muted);
|
|
2185
2782
|
}
|
|
2186
|
-
// Last-resort scan if hook somehow missed.
|
|
2187
2783
|
if (n === 0 && Array.isArray(window._allAudioTracks)) {
|
|
2188
2784
|
window._allAudioTracks.forEach(function(t) {
|
|
2189
2785
|
try { t.enabled = !muted; n++; } catch (e) {}
|
|
@@ -2192,104 +2788,413 @@ var buildMuteScript = (muted) => `
|
|
|
2192
2788
|
console.log('[ada-mute]', muted ? 'MUTED' : 'UNMUTED', 'tracks=', n);
|
|
2193
2789
|
})(${muted}); true;
|
|
2194
2790
|
`;
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2791
|
+
var buildAgentTurnScript = (input) => `
|
|
2792
|
+
(function(input) {
|
|
2793
|
+
if (typeof window.__adasAgentTurn === 'function') {
|
|
2794
|
+
try { window.__adasAgentTurn(input); }
|
|
2795
|
+
catch (e) {
|
|
2796
|
+
window.ReactNativeWebView && window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
2797
|
+
type: 'agentTurnFailed', message: String(e && e.message || e),
|
|
2798
|
+
}));
|
|
2799
|
+
}
|
|
2800
|
+
} else if (window.ReactNativeWebView) {
|
|
2801
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
2802
|
+
type: 'agentTurnUnsupported',
|
|
2803
|
+
message: 'voice app does not support agent turns (__adasAgentTurn missing) \u2014 update the voice page',
|
|
2804
|
+
}));
|
|
2805
|
+
}
|
|
2806
|
+
})(${JSON.stringify(input)}); true;
|
|
2807
|
+
`;
|
|
2808
|
+
var buildObserveScript = (text) => `
|
|
2809
|
+
(function(text) {
|
|
2810
|
+
if (typeof window.__adasObserve === 'function') {
|
|
2811
|
+
try { window.__adasObserve(text); }
|
|
2812
|
+
catch (e) {
|
|
2813
|
+
window.ReactNativeWebView && window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
2814
|
+
type: 'observeFailed', message: String(e && e.message || e),
|
|
2815
|
+
}));
|
|
2816
|
+
}
|
|
2817
|
+
} else if (window.ReactNativeWebView) {
|
|
2818
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
2819
|
+
type: 'observeUnsupported',
|
|
2820
|
+
message: 'voice app does not support observe (__adasObserve missing) \u2014 update the voice page',
|
|
2821
|
+
}));
|
|
2822
|
+
}
|
|
2823
|
+
})(${JSON.stringify(text)}); true;
|
|
2824
|
+
`;
|
|
2825
|
+
function originOf(url) {
|
|
2826
|
+
if (!url) return null;
|
|
2827
|
+
const m = /^([a-z][a-z0-9+.-]*:\/\/[^/?#]+)/i.exec(url);
|
|
2828
|
+
return m ? m[1].toLowerCase() : null;
|
|
2829
|
+
}
|
|
2830
|
+
var IDLE = {
|
|
2831
|
+
callState: "idle",
|
|
2832
|
+
sessionId: null,
|
|
2833
|
+
error: null,
|
|
2834
|
+
transcript: [],
|
|
2835
|
+
aiPartial: "",
|
|
2836
|
+
userPartial: "",
|
|
2837
|
+
muted: false,
|
|
2838
|
+
userSpeaking: false,
|
|
2839
|
+
lastUserSpeechEndedAt: null,
|
|
2840
|
+
mounted: false,
|
|
2841
|
+
webViewSource: null,
|
|
2842
|
+
skillSlug: void 0
|
|
2843
|
+
};
|
|
2844
|
+
var VoiceSessionManager = class {
|
|
2845
|
+
constructor() {
|
|
2846
|
+
this.state = { ...IDLE };
|
|
2847
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
2848
|
+
this.webView = null;
|
|
2849
|
+
this.pending = [];
|
|
2850
|
+
/**
|
|
2851
|
+
* WHO owns the one physical session. Set to the caller that started it from
|
|
2852
|
+
* idle (a plugin's pluginId, or the PLATFORM symbol for the built-in sheet),
|
|
2853
|
+
* and kept after stop until the next start reassigns it — so a plugin can read
|
|
2854
|
+
* its own just-ended transcript but another plugin never can.
|
|
2855
|
+
*
|
|
2856
|
+
* ISOLATION (GPT blocker on 8881225): every access is scoped through this. A
|
|
2857
|
+
* different plugin must not read, control, or attach to another plugin's live
|
|
2858
|
+
* conversation just because it declared voice.
|
|
2859
|
+
*/
|
|
2860
|
+
this.owner = null;
|
|
2861
|
+
this.injectedTrackHook = INJECT_TRACK_HOOK;
|
|
2862
|
+
}
|
|
2863
|
+
/** The platform (built-in sheet, mic indicator, session host) sees and
|
|
2864
|
+
* controls any session — it is the user's own surface. A plugin caller may
|
|
2865
|
+
* only touch a session it owns. */
|
|
2866
|
+
canAccess(caller) {
|
|
2867
|
+
return caller === import_plugin_runtime13.PLATFORM_VOICE_CALLER || this.owner === caller;
|
|
2868
|
+
}
|
|
2869
|
+
foreignError() {
|
|
2870
|
+
const err = new Error(
|
|
2871
|
+
"voice: another solution is using the microphone \u2014 one live session per device."
|
|
2872
|
+
);
|
|
2873
|
+
err.code = "RESTRICTED";
|
|
2874
|
+
return err;
|
|
2875
|
+
}
|
|
2876
|
+
// ── Host wiring (used only by VoiceSessionHost) ──────────────
|
|
2877
|
+
/** The offscreen WebView sets its ref here so the session can inject into it. */
|
|
2878
|
+
setWebView(ref) {
|
|
2879
|
+
this.webView = ref;
|
|
2880
|
+
}
|
|
2881
|
+
/** Whole state — the host reads `mounted` + `webViewSource` to decide what to
|
|
2882
|
+
* render, and every reader derives its snapshot from this. */
|
|
2883
|
+
getInternal() {
|
|
2884
|
+
return this.state;
|
|
2885
|
+
}
|
|
2886
|
+
// ── VoiceAPI (what props.voice and useVoiceCall call) ────────
|
|
2887
|
+
async start(opts, caller = import_plugin_runtime13.PLATFORM_VOICE_CALLER) {
|
|
2888
|
+
if (this.state.callState === "connected") {
|
|
2889
|
+
if (!this.canAccess(caller)) throw this.foreignError();
|
|
2890
|
+
return this.realSnapshot();
|
|
2891
|
+
}
|
|
2892
|
+
if (this.state.callState === "connecting") {
|
|
2893
|
+
if (!this.canAccess(caller)) throw this.foreignError();
|
|
2894
|
+
return this.waitForConnect();
|
|
2895
|
+
}
|
|
2205
2896
|
try {
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2897
|
+
await (0, import_plugin_runtime13.ensureDeviceToolsLoaded)();
|
|
2898
|
+
} catch (e) {
|
|
2899
|
+
console.warn("[voiceSession] device tool preload failed:", e?.message || String(e));
|
|
2900
|
+
}
|
|
2901
|
+
try {
|
|
2902
|
+
if (tokenNeedsRefresh((0, import_core22.getToken)())) await (0, import_core22.refreshToken)();
|
|
2903
|
+
} catch {
|
|
2904
|
+
}
|
|
2905
|
+
this.owner = caller;
|
|
2906
|
+
const skillSlug = opts?.skillSlug;
|
|
2907
|
+
this.setState({
|
|
2908
|
+
callState: "connecting",
|
|
2909
|
+
error: null,
|
|
2910
|
+
transcript: [],
|
|
2911
|
+
aiPartial: "",
|
|
2912
|
+
userPartial: "",
|
|
2913
|
+
muted: false,
|
|
2914
|
+
mounted: true,
|
|
2915
|
+
skillSlug,
|
|
2916
|
+
webViewSource: { uri: this.buildUri(skillSlug) }
|
|
2917
|
+
});
|
|
2918
|
+
return this.waitForConnect();
|
|
2919
|
+
}
|
|
2920
|
+
stop(caller = import_plugin_runtime13.PLATFORM_VOICE_CALLER) {
|
|
2921
|
+
if (this.state.callState !== "idle" && !this.canAccess(caller)) throw this.foreignError();
|
|
2922
|
+
this.webView?.injectJavaScript?.("window.hangUp && window.hangUp(); true;");
|
|
2923
|
+
this.rejectPending(new Error("voice: session stopped before it connected"));
|
|
2924
|
+
this.setState({
|
|
2925
|
+
...IDLE,
|
|
2926
|
+
// keep the transcript of the call that just ended for any reader still up
|
|
2927
|
+
transcript: this.state.transcript
|
|
2928
|
+
});
|
|
2929
|
+
}
|
|
2930
|
+
setMuted(muted, caller = import_plugin_runtime13.PLATFORM_VOICE_CALLER) {
|
|
2931
|
+
if (this.state.callState !== "idle" && !this.canAccess(caller)) throw this.foreignError();
|
|
2932
|
+
this.webView?.injectJavaScript?.(buildMuteScript(muted));
|
|
2933
|
+
this.setState({ muted });
|
|
2934
|
+
}
|
|
2935
|
+
prompt(input, caller = import_plugin_runtime13.PLATFORM_VOICE_CALLER) {
|
|
2936
|
+
if (this.state.callState !== "connected") {
|
|
2937
|
+
throw new Error("voice: session is not connected \u2014 call start() and await it before prompt().");
|
|
2938
|
+
}
|
|
2939
|
+
if (!this.canAccess(caller)) throw this.foreignError();
|
|
2940
|
+
this.webView?.injectJavaScript?.(buildAgentTurnScript(input));
|
|
2941
|
+
}
|
|
2942
|
+
/**
|
|
2943
|
+
* Stream a silent observation into the live session — tell the model without
|
|
2944
|
+
* asking it to speak. The cheap, high-frequency channel (safe once or twice a
|
|
2945
|
+
* second) behind a future props.voice.observe(); today the host uses it to run
|
|
2946
|
+
* the real-device stream proof (VOICE_RT_STREAM_DEVICE_PROOF) before the gated
|
|
2947
|
+
* plugin API is added. Owner-scoped like every other control.
|
|
2948
|
+
*/
|
|
2949
|
+
observe(text, caller = import_plugin_runtime13.PLATFORM_VOICE_CALLER) {
|
|
2950
|
+
if (this.state.callState !== "connected") {
|
|
2951
|
+
throw new Error("voice: session is not connected \u2014 observe() needs a live session.");
|
|
2952
|
+
}
|
|
2953
|
+
if (!this.canAccess(caller)) throw this.foreignError();
|
|
2954
|
+
this.webView?.injectJavaScript?.(buildObserveScript(text));
|
|
2955
|
+
}
|
|
2956
|
+
getSnapshot(caller = import_plugin_runtime13.PLATFORM_VOICE_CALLER) {
|
|
2957
|
+
return this.canAccess(caller) ? this.realSnapshot() : this.foreignSnapshot();
|
|
2958
|
+
}
|
|
2959
|
+
realSnapshot() {
|
|
2960
|
+
const s = this.state;
|
|
2961
|
+
return {
|
|
2962
|
+
state: s.callState,
|
|
2963
|
+
sessionId: s.sessionId,
|
|
2964
|
+
muted: s.muted,
|
|
2965
|
+
speaking: !!s.aiPartial,
|
|
2966
|
+
listening: !!s.userPartial,
|
|
2967
|
+
userSpeaking: s.userSpeaking,
|
|
2968
|
+
lastUserSpeechEndedAt: s.lastUserSpeechEndedAt,
|
|
2969
|
+
lastError: s.error
|
|
2970
|
+
};
|
|
2971
|
+
}
|
|
2972
|
+
foreignSnapshot() {
|
|
2973
|
+
return {
|
|
2974
|
+
state: "idle",
|
|
2975
|
+
sessionId: null,
|
|
2976
|
+
muted: false,
|
|
2977
|
+
speaking: false,
|
|
2978
|
+
listening: false,
|
|
2979
|
+
userSpeaking: false,
|
|
2980
|
+
lastUserSpeechEndedAt: null,
|
|
2981
|
+
lastError: null
|
|
2982
|
+
};
|
|
2983
|
+
}
|
|
2984
|
+
subscribe(cb, caller = import_plugin_runtime13.PLATFORM_VOICE_CALLER) {
|
|
2985
|
+
const wrapped = (event) => {
|
|
2986
|
+
if (this.canAccess(caller)) cb(event);
|
|
2987
|
+
};
|
|
2988
|
+
this.listeners.add(wrapped);
|
|
2989
|
+
return { unsubscribe: () => {
|
|
2990
|
+
this.listeners.delete(wrapped);
|
|
2991
|
+
} };
|
|
2992
|
+
}
|
|
2993
|
+
transcript(caller = import_plugin_runtime13.PLATFORM_VOICE_CALLER) {
|
|
2994
|
+
return this.canAccess(caller) ? this.state.transcript.slice() : [];
|
|
2995
|
+
}
|
|
2996
|
+
// ── WebView plumbing ─────────────────────────────────────────
|
|
2997
|
+
buildUri(skillSlug) {
|
|
2998
|
+
const token = (0, import_core22.getToken)();
|
|
2999
|
+
const tenant = (0, import_core22.getTenant)();
|
|
3000
|
+
const actorId = (0, import_core22.getUser)()?.actorId || "";
|
|
3001
|
+
const skillParam = skillSlug ? `&skillSlug=${encodeURIComponent(skillSlug)}` : "";
|
|
3002
|
+
return `${(0, import_core22.getVoiceApiUrl)()}/app?mode=mini&embedded=rn&authToken=${encodeURIComponent(token || "")}&tenant=${encodeURIComponent(tenant)}&actorId=${encodeURIComponent(actorId)}${skillParam}`;
|
|
3003
|
+
}
|
|
3004
|
+
/** Handle a postMessage from the WebView. `event` is the RN WebView event. */
|
|
3005
|
+
handleMessage(event) {
|
|
3006
|
+
let data;
|
|
3007
|
+
try {
|
|
3008
|
+
data = JSON.parse(event.nativeEvent.data);
|
|
3009
|
+
} catch {
|
|
3010
|
+
return;
|
|
3011
|
+
}
|
|
3012
|
+
switch (data.type) {
|
|
3013
|
+
case "callState":
|
|
3014
|
+
case "call-state":
|
|
3015
|
+
if (data.state) this.setState({ callState: data.state });
|
|
3016
|
+
if (data.sessionId) this.setState({ sessionId: data.sessionId });
|
|
3017
|
+
if (data.error) this.setState({ error: data.error });
|
|
3018
|
+
if (data.state === "connected") this.resolvePending();
|
|
3019
|
+
if (data.state === "error") this.rejectPending(new Error(data.error || "voice: connection error"));
|
|
3020
|
+
break;
|
|
3021
|
+
case "transcript":
|
|
3022
|
+
this.appendTranscript({ role: data.role, text: data.text, ts: Date.now() });
|
|
3023
|
+
break;
|
|
3024
|
+
case "aiPartial":
|
|
3025
|
+
this.setState({ aiPartial: data.text });
|
|
3026
|
+
break;
|
|
3027
|
+
case "userPartial":
|
|
3028
|
+
this.setState({ userPartial: data.text });
|
|
3029
|
+
break;
|
|
3030
|
+
case "clearPartials":
|
|
3031
|
+
this.setState({ aiPartial: "", userPartial: "" });
|
|
3032
|
+
break;
|
|
3033
|
+
// User VAD from the mini-app. `at` is when it happened; on speaking:false
|
|
3034
|
+
// we stamp lastUserSpeechEndedAt so a solution can gate "speak after N s of
|
|
3035
|
+
// silence" on the first real stop, never before the user has spoken.
|
|
3036
|
+
case "speechActivity": {
|
|
3037
|
+
const speaking = !!data.speaking;
|
|
3038
|
+
const at = typeof data.at === "number" ? data.at : Date.now();
|
|
3039
|
+
this.setState(
|
|
3040
|
+
speaking ? { userSpeaking: true } : { userSpeaking: false, lastUserSpeechEndedAt: at }
|
|
3041
|
+
);
|
|
3042
|
+
break;
|
|
3043
|
+
}
|
|
3044
|
+
case "error":
|
|
3045
|
+
this.setState({ error: data.message, callState: "error" });
|
|
3046
|
+
this.rejectPending(new Error(data.message || "voice: error"));
|
|
3047
|
+
break;
|
|
3048
|
+
// A proactive turn couldn't run (older voice page / hook threw). NON-FATAL:
|
|
3049
|
+
// the session stays live; we only surface why the guide didn't speak.
|
|
3050
|
+
case "agentTurnUnsupported":
|
|
3051
|
+
case "agentTurnFailed":
|
|
3052
|
+
case "observeUnsupported":
|
|
3053
|
+
case "observeFailed":
|
|
3054
|
+
this.setState({ error: data.message || "voice: channel notice" });
|
|
3055
|
+
break;
|
|
3056
|
+
// Device tools — executed locally, origin-checked. The model's function
|
|
3057
|
+
// call already arrived on this phone; only the voice app's own origin may
|
|
3058
|
+
// drive the camera/GPS.
|
|
3059
|
+
case "device-tool-list": {
|
|
3060
|
+
const listSender = originOf(event?.nativeEvent?.url);
|
|
3061
|
+
const listExpected = originOf((0, import_core22.getVoiceApiUrl)());
|
|
3062
|
+
if (!listSender || !listExpected || listSender !== listExpected) break;
|
|
3063
|
+
this.sendDeviceToolList(data.correlationId);
|
|
3064
|
+
break;
|
|
3065
|
+
}
|
|
3066
|
+
case "device-tool-call": {
|
|
3067
|
+
const sender = originOf(event?.nativeEvent?.url);
|
|
3068
|
+
const expected = originOf((0, import_core22.getVoiceApiUrl)());
|
|
3069
|
+
if (!sender || !expected || sender !== expected) {
|
|
3070
|
+
console.warn(`[voiceSession] REFUSED device tool call from "${sender || "unknown origin"}" (expected "${expected}")`);
|
|
2231
3071
|
break;
|
|
3072
|
+
}
|
|
3073
|
+
void this.runDeviceTool(data);
|
|
3074
|
+
break;
|
|
2232
3075
|
}
|
|
2233
|
-
} catch {
|
|
2234
3076
|
}
|
|
2235
|
-
}
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
3077
|
+
}
|
|
3078
|
+
/** Answer "what device tools do you have?" — the client is the authority. */
|
|
3079
|
+
sendDeviceToolList(correlationId) {
|
|
3080
|
+
const tools = (0, import_plugin_runtime13.listDeviceTools)().map((t) => ({
|
|
3081
|
+
name: t.name,
|
|
3082
|
+
description: t.description,
|
|
3083
|
+
input_schema: t.input_schema
|
|
3084
|
+
}));
|
|
3085
|
+
this.webView?.injectJavaScript?.(
|
|
3086
|
+
`window.__adasDeviceToolResult && window.__adasDeviceToolResult(${JSON.stringify(
|
|
3087
|
+
JSON.stringify({ correlationId, ok: true, tools })
|
|
3088
|
+
)}); true;`
|
|
3089
|
+
);
|
|
3090
|
+
}
|
|
3091
|
+
/** Run a device tool and post the outcome back into the WebView. */
|
|
3092
|
+
async runDeviceTool(data) {
|
|
3093
|
+
const { correlationId, name, args, timeoutMs } = data || {};
|
|
3094
|
+
if (!correlationId || typeof name !== "string") return;
|
|
3095
|
+
let payload;
|
|
2241
3096
|
try {
|
|
2242
|
-
|
|
2243
|
-
|
|
3097
|
+
const outcome = await (0, import_plugin_runtime13.callDeviceTool)(name, args || {}, { timeoutMs });
|
|
3098
|
+
payload = outcome.ok ? { correlationId, ok: true, result: outcome.result } : { correlationId, ok: false, error: outcome.error, reason: outcome.reason };
|
|
3099
|
+
} catch (err) {
|
|
3100
|
+
payload = { correlationId, ok: false, reason: "failed", error: err?.message || String(err) };
|
|
3101
|
+
}
|
|
3102
|
+
this.webView?.injectJavaScript?.(
|
|
3103
|
+
`window.__adasDeviceToolResult && window.__adasDeviceToolResult(${JSON.stringify(
|
|
3104
|
+
JSON.stringify(payload)
|
|
3105
|
+
)}); true;`
|
|
3106
|
+
);
|
|
3107
|
+
}
|
|
3108
|
+
// ── internals ────────────────────────────────────────────────
|
|
3109
|
+
setState(partial) {
|
|
3110
|
+
this.state = { ...this.state, ...partial };
|
|
3111
|
+
this.emit({ type: "state" });
|
|
3112
|
+
}
|
|
3113
|
+
appendTranscript(entry) {
|
|
3114
|
+
this.state = { ...this.state, transcript: [...this.state.transcript, entry] };
|
|
3115
|
+
this.emit({ type: "transcript" });
|
|
3116
|
+
}
|
|
3117
|
+
emit(event) {
|
|
3118
|
+
for (const cb of this.listeners) {
|
|
3119
|
+
try {
|
|
3120
|
+
cb(event);
|
|
3121
|
+
} catch (e) {
|
|
3122
|
+
console.warn("[voiceSession] listener threw", e);
|
|
2244
3123
|
}
|
|
2245
|
-
} catch {
|
|
2246
3124
|
}
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
}, []);
|
|
2256
|
-
const toggleMute = (0, import_react12.useCallback)(() => {
|
|
2257
|
-
setMuted((prev) => {
|
|
2258
|
-
const next = !prev;
|
|
2259
|
-
webViewRef.current?.injectJavaScript?.(buildMuteScript(next));
|
|
2260
|
-
return next;
|
|
3125
|
+
}
|
|
3126
|
+
waitForConnect() {
|
|
3127
|
+
return new Promise((resolve, reject) => {
|
|
3128
|
+
const timer = setTimeout(() => {
|
|
3129
|
+
this.pending = this.pending.filter((p) => p.timer !== timer);
|
|
3130
|
+
reject(new Error("voice: timed out waiting to connect (is VoiceSessionHost mounted?)"));
|
|
3131
|
+
}, CONNECT_TIMEOUT_MS);
|
|
3132
|
+
this.pending.push({ resolve, reject, timer });
|
|
2261
3133
|
});
|
|
3134
|
+
}
|
|
3135
|
+
resolvePending() {
|
|
3136
|
+
const snap = this.realSnapshot();
|
|
3137
|
+
const waiting = this.pending;
|
|
3138
|
+
this.pending = [];
|
|
3139
|
+
for (const p of waiting) {
|
|
3140
|
+
clearTimeout(p.timer);
|
|
3141
|
+
p.resolve(snap);
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
rejectPending(err) {
|
|
3145
|
+
const waiting = this.pending;
|
|
3146
|
+
this.pending = [];
|
|
3147
|
+
for (const p of waiting) {
|
|
3148
|
+
clearTimeout(p.timer);
|
|
3149
|
+
p.reject(err);
|
|
3150
|
+
}
|
|
3151
|
+
}
|
|
3152
|
+
/** TEST ONLY: reset the singleton to a clean idle state (mirrors the
|
|
3153
|
+
* __resetSessionSyncForTest precedent). Not part of any surface. */
|
|
3154
|
+
__resetForTest() {
|
|
3155
|
+
this.rejectPending(new Error("voice: reset"));
|
|
3156
|
+
this.state = { ...IDLE };
|
|
3157
|
+
this.owner = null;
|
|
3158
|
+
this.listeners.clear();
|
|
3159
|
+
this.webView = null;
|
|
3160
|
+
}
|
|
3161
|
+
};
|
|
3162
|
+
var voiceSession = new VoiceSessionManager();
|
|
3163
|
+
|
|
3164
|
+
// src/voice/useVoiceCall.ts
|
|
3165
|
+
function useVoiceCall({ skillSlug } = {}) {
|
|
3166
|
+
const [, force] = (0, import_react16.useReducer)((x) => x + 1, 0);
|
|
3167
|
+
(0, import_react16.useEffect)(() => {
|
|
3168
|
+
const sub = voiceSession.subscribe(() => force());
|
|
3169
|
+
return () => sub.unsubscribe();
|
|
2262
3170
|
}, []);
|
|
2263
|
-
const
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
3171
|
+
const s = voiceSession.getInternal();
|
|
3172
|
+
const startCall = (0, import_react16.useCallback)(
|
|
3173
|
+
(opts) => voiceSession.start(opts ?? { skillSlug }),
|
|
3174
|
+
[skillSlug]
|
|
3175
|
+
);
|
|
3176
|
+
const stopCall = (0, import_react16.useCallback)(() => voiceSession.stop(), []);
|
|
3177
|
+
const toggleMute = (0, import_react16.useCallback)(
|
|
3178
|
+
() => voiceSession.setMuted(!voiceSession.getSnapshot().muted),
|
|
3179
|
+
[]
|
|
3180
|
+
);
|
|
2272
3181
|
return {
|
|
2273
|
-
callState,
|
|
2274
|
-
sessionId,
|
|
2275
|
-
error,
|
|
2276
|
-
transcript,
|
|
2277
|
-
aiPartial,
|
|
2278
|
-
userPartial,
|
|
2279
|
-
muted,
|
|
3182
|
+
callState: s.callState,
|
|
3183
|
+
sessionId: s.sessionId,
|
|
3184
|
+
error: s.error,
|
|
3185
|
+
transcript: s.transcript,
|
|
3186
|
+
aiPartial: s.aiPartial,
|
|
3187
|
+
userPartial: s.userPartial,
|
|
3188
|
+
muted: s.muted,
|
|
2280
3189
|
startCall,
|
|
2281
3190
|
stopCall,
|
|
2282
|
-
toggleMute
|
|
2283
|
-
handleWebViewMessage,
|
|
2284
|
-
getWebViewSource,
|
|
2285
|
-
webViewRef,
|
|
2286
|
-
injectedTrackHook: INJECT_TRACK_HOOK
|
|
3191
|
+
toggleMute
|
|
2287
3192
|
};
|
|
2288
3193
|
}
|
|
2289
3194
|
|
|
2290
3195
|
// src/voice/VoiceCallSheet.tsx
|
|
2291
|
-
var
|
|
2292
|
-
var
|
|
3196
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
3197
|
+
var fontFam11 = import_react_native20.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
2293
3198
|
var HIGHLIGHT_PATTERNS = [
|
|
2294
3199
|
/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g,
|
|
2295
3200
|
/(?:\+?\d[\s\-().]?){7,}\d/g,
|
|
@@ -2332,8 +3237,8 @@ function HighlightedText({
|
|
|
2332
3237
|
baseStyle,
|
|
2333
3238
|
importantStyle
|
|
2334
3239
|
}) {
|
|
2335
|
-
const segments = (0,
|
|
2336
|
-
return /* @__PURE__ */ (0,
|
|
3240
|
+
const segments = (0, import_react17.useMemo)(() => highlightSegments(text), [text]);
|
|
3241
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native20.Text, { style: baseStyle, children: segments.map((seg, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native20.Text, { style: seg.important ? importantStyle : void 0, children: seg.text }, i)) });
|
|
2337
3242
|
}
|
|
2338
3243
|
function VoiceCallSheet({ visible, onClose, skillSlug }) {
|
|
2339
3244
|
const {
|
|
@@ -2345,31 +3250,27 @@ function VoiceCallSheet({ visible, onClose, skillSlug }) {
|
|
|
2345
3250
|
muted,
|
|
2346
3251
|
startCall,
|
|
2347
3252
|
stopCall,
|
|
2348
|
-
toggleMute
|
|
2349
|
-
handleWebViewMessage,
|
|
2350
|
-
getWebViewSource,
|
|
2351
|
-
webViewRef,
|
|
2352
|
-
injectedTrackHook
|
|
3253
|
+
toggleMute
|
|
2353
3254
|
} = useVoiceCall({ skillSlug });
|
|
2354
|
-
const scrollRef = (0,
|
|
2355
|
-
(0,
|
|
3255
|
+
const scrollRef = (0, import_react17.useRef)(null);
|
|
3256
|
+
(0, import_react17.useEffect)(() => {
|
|
2356
3257
|
if (visible && callState === "idle") startCall();
|
|
2357
3258
|
}, [visible]);
|
|
2358
|
-
(0,
|
|
3259
|
+
(0, import_react17.useEffect)(() => {
|
|
2359
3260
|
scrollRef.current?.scrollToEnd?.({ animated: true });
|
|
2360
3261
|
}, [transcript.length, aiPartial, userPartial]);
|
|
2361
3262
|
const handleHangUp = () => {
|
|
2362
3263
|
stopCall();
|
|
2363
3264
|
onClose();
|
|
2364
3265
|
};
|
|
2365
|
-
const orbState = (0,
|
|
3266
|
+
const orbState = (0, import_react17.useMemo)(() => {
|
|
2366
3267
|
if (callState === "connecting") return "thinking";
|
|
2367
3268
|
if (callState === "error") return "idle";
|
|
2368
3269
|
if (aiPartial) return "speaking";
|
|
2369
3270
|
if (userPartial) return "listening";
|
|
2370
3271
|
return "idle";
|
|
2371
3272
|
}, [callState, aiPartial, userPartial]);
|
|
2372
|
-
const statusLabel = (0,
|
|
3273
|
+
const statusLabel = (0, import_react17.useMemo)(() => {
|
|
2373
3274
|
if (callState === "connecting") return "Connecting\u2026";
|
|
2374
3275
|
if (callState === "error") return error || "Couldn\u2019t connect";
|
|
2375
3276
|
if (aiPartial) return "Ada is speaking";
|
|
@@ -2379,92 +3280,76 @@ function VoiceCallSheet({ visible, onClose, skillSlug }) {
|
|
|
2379
3280
|
}, [callState, aiPartial, userPartial, error]);
|
|
2380
3281
|
if (!visible) return null;
|
|
2381
3282
|
const visibleEntries = transcript.filter((e) => e.role === "user" || e.role === "ai");
|
|
2382
|
-
return /* @__PURE__ */ (0,
|
|
2383
|
-
|
|
3283
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
3284
|
+
import_plugin_runtime14.SurfaceFullscreen,
|
|
2384
3285
|
{
|
|
2385
3286
|
visible,
|
|
2386
3287
|
onClose: handleHangUp,
|
|
2387
3288
|
status: statusLabel,
|
|
2388
|
-
hero: /* @__PURE__ */ (0,
|
|
3289
|
+
hero: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_plugin_runtime14.AdaOrb, { size: 180, state: orbState }),
|
|
2389
3290
|
closeIcon: "hangup",
|
|
2390
3291
|
closeLabel: "End",
|
|
2391
3292
|
children: [
|
|
2392
|
-
/* @__PURE__ */ (0,
|
|
2393
|
-
|
|
3293
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
3294
|
+
import_react_native20.ScrollView,
|
|
2394
3295
|
{
|
|
2395
3296
|
ref: scrollRef,
|
|
2396
|
-
style:
|
|
2397
|
-
contentContainerStyle:
|
|
3297
|
+
style: styles19.transcript,
|
|
3298
|
+
contentContainerStyle: styles19.transcriptContent,
|
|
2398
3299
|
showsVerticalScrollIndicator: false,
|
|
2399
3300
|
children: [
|
|
2400
|
-
callState === "error" && error ? /* @__PURE__ */ (0,
|
|
2401
|
-
visibleEntries.map((entry, i) => /* @__PURE__ */ (0,
|
|
2402
|
-
/* @__PURE__ */ (0,
|
|
2403
|
-
/* @__PURE__ */ (0,
|
|
3301
|
+
callState === "error" && error ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native20.View, { style: styles19.errorBox, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native20.Text, { style: styles19.errorText, children: error }) }) : null,
|
|
3302
|
+
visibleEntries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_native20.View, { style: styles19.entry, children: [
|
|
3303
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native20.Text, { style: styles19.role, children: entry.role === "user" ? "YOU" : "ADA" }),
|
|
3304
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2404
3305
|
HighlightedText,
|
|
2405
3306
|
{
|
|
2406
3307
|
text: entry.text,
|
|
2407
|
-
baseStyle:
|
|
2408
|
-
importantStyle:
|
|
3308
|
+
baseStyle: styles19.entryText,
|
|
3309
|
+
importantStyle: styles19.important
|
|
2409
3310
|
}
|
|
2410
3311
|
)
|
|
2411
3312
|
] }, `${entry.ts}-${i}`)),
|
|
2412
|
-
userPartial || aiPartial ? /* @__PURE__ */ (0,
|
|
2413
|
-
/* @__PURE__ */ (0,
|
|
2414
|
-
/* @__PURE__ */ (0,
|
|
3313
|
+
userPartial || aiPartial ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_native20.View, { style: styles19.entry, children: [
|
|
3314
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native20.Text, { style: styles19.role, children: userPartial ? "YOU" : "ADA" }),
|
|
3315
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2415
3316
|
HighlightedText,
|
|
2416
3317
|
{
|
|
2417
3318
|
text: userPartial || aiPartial,
|
|
2418
|
-
baseStyle:
|
|
2419
|
-
importantStyle:
|
|
3319
|
+
baseStyle: styles19.entryTextLive,
|
|
3320
|
+
importantStyle: styles19.important
|
|
2420
3321
|
}
|
|
2421
3322
|
)
|
|
2422
3323
|
] }) : null
|
|
2423
3324
|
]
|
|
2424
3325
|
}
|
|
2425
3326
|
),
|
|
2426
|
-
callState === "connected" || callState === "connecting" ? /* @__PURE__ */ (0,
|
|
2427
|
-
/* @__PURE__ */ (0,
|
|
2428
|
-
|
|
3327
|
+
callState === "connected" || callState === "connecting" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_native20.View, { style: styles19.muteWrap, pointerEvents: "box-none", children: [
|
|
3328
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3329
|
+
import_react_native20.Pressable,
|
|
2429
3330
|
{
|
|
2430
3331
|
onPress: toggleMute,
|
|
2431
3332
|
accessibilityRole: "button",
|
|
2432
3333
|
accessibilityLabel: muted ? "Unmute microphone" : "Mute microphone",
|
|
2433
3334
|
accessibilityState: { selected: muted },
|
|
2434
|
-
style: [
|
|
3335
|
+
style: [styles19.muteBtn, muted && styles19.muteBtnActive],
|
|
2435
3336
|
hitSlop: 12,
|
|
2436
|
-
children: /* @__PURE__ */ (0,
|
|
2437
|
-
/* @__PURE__ */ (0,
|
|
2438
|
-
/* @__PURE__ */ (0,
|
|
2439
|
-
/* @__PURE__ */ (0,
|
|
2440
|
-
/* @__PURE__ */ (0,
|
|
2441
|
-
muted ? /* @__PURE__ */ (0,
|
|
3337
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_native_svg2.default, { width: 22, height: 22, viewBox: "0 0 24 24", fill: "none", stroke: muted ? import_core23.ada.paper : import_core23.ada.ink, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
3338
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_svg2.Path, { d: "M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" }),
|
|
3339
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_svg2.Path, { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
|
|
3340
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_svg2.Line, { x1: "12", y1: "19", x2: "12", y2: "23" }),
|
|
3341
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_svg2.Line, { x1: "8", y1: "23", x2: "16", y2: "23" }),
|
|
3342
|
+
muted ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_svg2.Line, { x1: "3", y1: "3", x2: "21", y2: "21", stroke: import_core23.ada.paper, strokeWidth: 2.4 }) : null
|
|
2442
3343
|
] })
|
|
2443
3344
|
}
|
|
2444
3345
|
),
|
|
2445
|
-
/* @__PURE__ */ (0,
|
|
2446
|
-
] }) : null
|
|
2447
|
-
callState !== "idle" && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native14.View, { style: styles13.hiddenWebView, pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2448
|
-
import_react_native_webview3.WebView,
|
|
2449
|
-
{
|
|
2450
|
-
ref: webViewRef,
|
|
2451
|
-
source: getWebViewSource(),
|
|
2452
|
-
style: { flex: 1, backgroundColor: "transparent" },
|
|
2453
|
-
onMessage: handleWebViewMessage,
|
|
2454
|
-
onError: (e) => console.log("[VoiceWebView] error:", e.nativeEvent?.description),
|
|
2455
|
-
injectedJavaScriptBeforeContentLoaded: injectedTrackHook,
|
|
2456
|
-
mediaPlaybackRequiresUserAction: false,
|
|
2457
|
-
allowsInlineMediaPlayback: true,
|
|
2458
|
-
mediaCapturePermissionGrantType: "grant",
|
|
2459
|
-
javaScriptEnabled: true,
|
|
2460
|
-
originWhitelist: ["*"]
|
|
2461
|
-
}
|
|
2462
|
-
) })
|
|
3346
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native20.Text, { style: styles19.muteLabel, children: muted ? "Muted" : "Mute" })
|
|
3347
|
+
] }) : null
|
|
2463
3348
|
]
|
|
2464
3349
|
}
|
|
2465
3350
|
);
|
|
2466
3351
|
}
|
|
2467
|
-
var
|
|
3352
|
+
var styles19 = import_react_native20.StyleSheet.create({
|
|
2468
3353
|
transcript: {
|
|
2469
3354
|
flex: 1,
|
|
2470
3355
|
paddingHorizontal: 28
|
|
@@ -2481,9 +3366,9 @@ var styles13 = import_react_native14.StyleSheet.create({
|
|
|
2481
3366
|
},
|
|
2482
3367
|
role: {
|
|
2483
3368
|
fontSize: 10,
|
|
2484
|
-
fontFamily:
|
|
3369
|
+
fontFamily: fontFam11,
|
|
2485
3370
|
fontWeight: "700",
|
|
2486
|
-
color:
|
|
3371
|
+
color: import_core23.ada.inkMuted,
|
|
2487
3372
|
letterSpacing: 1.4,
|
|
2488
3373
|
minWidth: 32,
|
|
2489
3374
|
paddingTop: 3,
|
|
@@ -2492,9 +3377,9 @@ var styles13 = import_react_native14.StyleSheet.create({
|
|
|
2492
3377
|
entryText: {
|
|
2493
3378
|
flex: 1,
|
|
2494
3379
|
fontSize: 14,
|
|
2495
|
-
fontFamily:
|
|
3380
|
+
fontFamily: fontFam11,
|
|
2496
3381
|
fontWeight: "400",
|
|
2497
|
-
color:
|
|
3382
|
+
color: import_core23.ada.inkSoft,
|
|
2498
3383
|
lineHeight: 20,
|
|
2499
3384
|
letterSpacing: -0.1,
|
|
2500
3385
|
opacity: 0.42
|
|
@@ -2502,18 +3387,18 @@ var styles13 = import_react_native14.StyleSheet.create({
|
|
|
2502
3387
|
entryTextLive: {
|
|
2503
3388
|
flex: 1,
|
|
2504
3389
|
fontSize: 14,
|
|
2505
|
-
fontFamily:
|
|
3390
|
+
fontFamily: fontFam11,
|
|
2506
3391
|
fontWeight: "400",
|
|
2507
|
-
color:
|
|
3392
|
+
color: import_core23.ada.inkSoft,
|
|
2508
3393
|
lineHeight: 20,
|
|
2509
3394
|
letterSpacing: -0.1,
|
|
2510
3395
|
opacity: 0.7
|
|
2511
3396
|
},
|
|
2512
3397
|
important: {
|
|
2513
3398
|
fontSize: 17,
|
|
2514
|
-
fontFamily:
|
|
3399
|
+
fontFamily: fontFam11,
|
|
2515
3400
|
fontWeight: "700",
|
|
2516
|
-
color:
|
|
3401
|
+
color: import_core23.ada.ink,
|
|
2517
3402
|
letterSpacing: -0.1,
|
|
2518
3403
|
opacity: 1
|
|
2519
3404
|
},
|
|
@@ -2528,14 +3413,14 @@ var styles13 = import_react_native14.StyleSheet.create({
|
|
|
2528
3413
|
},
|
|
2529
3414
|
errorText: {
|
|
2530
3415
|
fontSize: 13,
|
|
2531
|
-
fontFamily:
|
|
3416
|
+
fontFamily: fontFam11,
|
|
2532
3417
|
fontWeight: "500",
|
|
2533
3418
|
color: "#fca5a5",
|
|
2534
3419
|
lineHeight: 18
|
|
2535
3420
|
},
|
|
2536
3421
|
muteWrap: {
|
|
2537
3422
|
position: "absolute",
|
|
2538
|
-
bottom:
|
|
3423
|
+
bottom: import_react_native20.Platform.OS === "ios" ? 56 : 40,
|
|
2539
3424
|
left: 28,
|
|
2540
3425
|
alignItems: "center",
|
|
2541
3426
|
gap: 6
|
|
@@ -2544,9 +3429,9 @@ var styles13 = import_react_native14.StyleSheet.create({
|
|
|
2544
3429
|
width: 56,
|
|
2545
3430
|
height: 56,
|
|
2546
3431
|
borderRadius: 28,
|
|
2547
|
-
backgroundColor:
|
|
3432
|
+
backgroundColor: import_core23.ada.paperSoft,
|
|
2548
3433
|
borderWidth: 1,
|
|
2549
|
-
borderColor:
|
|
3434
|
+
borderColor: import_core23.ada.border,
|
|
2550
3435
|
justifyContent: "center",
|
|
2551
3436
|
alignItems: "center"
|
|
2552
3437
|
},
|
|
@@ -2556,18 +3441,133 @@ var styles13 = import_react_native14.StyleSheet.create({
|
|
|
2556
3441
|
},
|
|
2557
3442
|
muteLabel: {
|
|
2558
3443
|
fontSize: 12,
|
|
2559
|
-
fontFamily:
|
|
3444
|
+
fontFamily: fontFam11,
|
|
2560
3445
|
fontWeight: "500",
|
|
2561
|
-
color:
|
|
3446
|
+
color: import_core23.ada.inkMuted,
|
|
2562
3447
|
letterSpacing: 0.3
|
|
2563
|
-
}
|
|
2564
|
-
|
|
3448
|
+
}
|
|
3449
|
+
});
|
|
3450
|
+
|
|
3451
|
+
// src/voice/VoiceSessionHost.tsx
|
|
3452
|
+
var import_react18 = require("react");
|
|
3453
|
+
var import_react_native21 = require("react-native");
|
|
3454
|
+
var import_react_native_webview3 = require("react-native-webview");
|
|
3455
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
3456
|
+
function VoiceSessionHost() {
|
|
3457
|
+
const [, force] = (0, import_react18.useReducer)((x) => x + 1, 0);
|
|
3458
|
+
const lastSig = (0, import_react18.useRef)("");
|
|
3459
|
+
(0, import_react18.useEffect)(() => {
|
|
3460
|
+
const sub = voiceSession.subscribe(() => {
|
|
3461
|
+
const s2 = voiceSession.getInternal();
|
|
3462
|
+
const sig = `${s2.mounted}|${s2.webViewSource?.uri || ""}`;
|
|
3463
|
+
if (sig !== lastSig.current) {
|
|
3464
|
+
lastSig.current = sig;
|
|
3465
|
+
force();
|
|
3466
|
+
}
|
|
3467
|
+
});
|
|
3468
|
+
return () => sub.unsubscribe();
|
|
3469
|
+
}, []);
|
|
3470
|
+
const setRef = (0, import_react18.useCallback)((r) => {
|
|
3471
|
+
voiceSession.setWebView(r);
|
|
3472
|
+
}, []);
|
|
3473
|
+
const s = voiceSession.getInternal();
|
|
3474
|
+
if (!s.mounted || !s.webViewSource) return null;
|
|
3475
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_native21.View, { style: styles20.hidden, pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
3476
|
+
import_react_native_webview3.WebView,
|
|
3477
|
+
{
|
|
3478
|
+
ref: setRef,
|
|
3479
|
+
source: s.webViewSource,
|
|
3480
|
+
style: styles20.web,
|
|
3481
|
+
onMessage: (e) => voiceSession.handleMessage(e),
|
|
3482
|
+
onError: (e) => console.log("[VoiceSessionHost] error:", e.nativeEvent?.description),
|
|
3483
|
+
injectedJavaScriptBeforeContentLoaded: voiceSession.injectedTrackHook,
|
|
3484
|
+
mediaPlaybackRequiresUserAction: false,
|
|
3485
|
+
allowsInlineMediaPlayback: true,
|
|
3486
|
+
mediaCapturePermissionGrantType: "grant",
|
|
3487
|
+
javaScriptEnabled: true,
|
|
3488
|
+
originWhitelist: ["*"]
|
|
3489
|
+
}
|
|
3490
|
+
) });
|
|
3491
|
+
}
|
|
3492
|
+
var styles20 = import_react_native21.StyleSheet.create({
|
|
3493
|
+
hidden: {
|
|
2565
3494
|
position: "absolute",
|
|
2566
3495
|
width: 1,
|
|
2567
3496
|
height: 1,
|
|
2568
3497
|
top: -100,
|
|
2569
3498
|
left: -100,
|
|
2570
3499
|
opacity: 0
|
|
3500
|
+
},
|
|
3501
|
+
web: { flex: 1, backgroundColor: "transparent" }
|
|
3502
|
+
});
|
|
3503
|
+
|
|
3504
|
+
// src/voice/VoiceMicIndicator.tsx
|
|
3505
|
+
var import_react19 = require("react");
|
|
3506
|
+
var import_react_native22 = require("react-native");
|
|
3507
|
+
var import_core24 = require("@ateam-ai-mobile/core");
|
|
3508
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
3509
|
+
var fontFam12 = import_react_native22.Platform.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
3510
|
+
function VoiceMicIndicator({ topInset = 8 }) {
|
|
3511
|
+
const [, force] = (0, import_react19.useReducer)((x) => x + 1, 0);
|
|
3512
|
+
const pulse = (0, import_react19.useRef)(new import_react_native22.Animated.Value(0.4)).current;
|
|
3513
|
+
(0, import_react19.useEffect)(() => {
|
|
3514
|
+
const sub = voiceSession.subscribe(() => force());
|
|
3515
|
+
return () => sub.unsubscribe();
|
|
3516
|
+
}, []);
|
|
3517
|
+
const snap = voiceSession.getSnapshot();
|
|
3518
|
+
const live = snap.state === "connecting" || snap.state === "connected";
|
|
3519
|
+
(0, import_react19.useEffect)(() => {
|
|
3520
|
+
if (!live) return;
|
|
3521
|
+
const loop = import_react_native22.Animated.loop(
|
|
3522
|
+
import_react_native22.Animated.sequence([
|
|
3523
|
+
import_react_native22.Animated.timing(pulse, { toValue: 1, duration: 700, useNativeDriver: true }),
|
|
3524
|
+
import_react_native22.Animated.timing(pulse, { toValue: 0.4, duration: 700, useNativeDriver: true })
|
|
3525
|
+
])
|
|
3526
|
+
);
|
|
3527
|
+
loop.start();
|
|
3528
|
+
return () => loop.stop();
|
|
3529
|
+
}, [live, pulse]);
|
|
3530
|
+
if (!live) return null;
|
|
3531
|
+
const label = snap.state === "connecting" ? "Connecting\u2026" : snap.muted ? "Mic muted" : "Ada is listening";
|
|
3532
|
+
const dotColor = snap.muted ? import_core24.ada.inkMuted : "#E5484D";
|
|
3533
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_native22.View, { style: [styles21.wrap, { top: topInset }], pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react_native22.View, { style: styles21.pill, children: [
|
|
3534
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_native22.Animated.View, { style: [styles21.dot, { backgroundColor: dotColor, opacity: snap.muted ? 1 : pulse }] }),
|
|
3535
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_native22.Text, { style: styles21.label, children: label })
|
|
3536
|
+
] }) });
|
|
3537
|
+
}
|
|
3538
|
+
var styles21 = import_react_native22.StyleSheet.create({
|
|
3539
|
+
wrap: {
|
|
3540
|
+
position: "absolute",
|
|
3541
|
+
left: 0,
|
|
3542
|
+
right: 0,
|
|
3543
|
+
alignItems: "center",
|
|
3544
|
+
zIndex: 9999,
|
|
3545
|
+
elevation: 9999
|
|
3546
|
+
},
|
|
3547
|
+
pill: {
|
|
3548
|
+
flexDirection: "row",
|
|
3549
|
+
alignItems: "center",
|
|
3550
|
+
gap: 7,
|
|
3551
|
+
paddingHorizontal: 12,
|
|
3552
|
+
paddingVertical: 6,
|
|
3553
|
+
borderRadius: 999,
|
|
3554
|
+
backgroundColor: import_core24.ada.ink,
|
|
3555
|
+
shadowColor: "#000",
|
|
3556
|
+
shadowOpacity: 0.2,
|
|
3557
|
+
shadowRadius: 8,
|
|
3558
|
+
shadowOffset: { width: 0, height: 2 }
|
|
3559
|
+
},
|
|
3560
|
+
dot: {
|
|
3561
|
+
width: 8,
|
|
3562
|
+
height: 8,
|
|
3563
|
+
borderRadius: 4
|
|
3564
|
+
},
|
|
3565
|
+
label: {
|
|
3566
|
+
fontSize: 12,
|
|
3567
|
+
fontFamily: fontFam12,
|
|
3568
|
+
fontWeight: "600",
|
|
3569
|
+
color: import_core24.ada.paper,
|
|
3570
|
+
letterSpacing: 0.2
|
|
2571
3571
|
}
|
|
2572
3572
|
});
|
|
2573
3573
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -2576,9 +3576,13 @@ var styles13 = import_react_native14.StyleSheet.create({
|
|
|
2576
3576
|
ChatInput,
|
|
2577
3577
|
DaySeparator,
|
|
2578
3578
|
EmbeddedPluginWebView,
|
|
3579
|
+
HandoffScreen,
|
|
2579
3580
|
JobProgressBar,
|
|
3581
|
+
JoinScreen,
|
|
2580
3582
|
Lightbox,
|
|
3583
|
+
LoginScreen,
|
|
2581
3584
|
MessageBubble,
|
|
3585
|
+
OpenJoinScreen,
|
|
2582
3586
|
Plugin,
|
|
2583
3587
|
PluginSurface,
|
|
2584
3588
|
TableCardBlock,
|
|
@@ -2586,16 +3590,30 @@ var styles13 = import_react_native14.StyleSheet.create({
|
|
|
2586
3590
|
TypingIndicator,
|
|
2587
3591
|
UIActionsRow,
|
|
2588
3592
|
VoiceCallSheet,
|
|
3593
|
+
VoiceMicIndicator,
|
|
3594
|
+
VoiceSessionHost,
|
|
2589
3595
|
WidgetHost,
|
|
2590
3596
|
WidgetWebView,
|
|
3597
|
+
WorkspaceBanner,
|
|
2591
3598
|
buildPluginBridgeJS,
|
|
3599
|
+
completeInviteJoin,
|
|
3600
|
+
completeOpenJoin,
|
|
3601
|
+
completeProviderSignIn,
|
|
3602
|
+
googleClientIds,
|
|
3603
|
+
handoffErrorMessage,
|
|
3604
|
+
inviteHeadline,
|
|
3605
|
+
openJoinErrorMessage,
|
|
2592
3606
|
openWidget,
|
|
3607
|
+
runHandoffExchange,
|
|
2593
3608
|
setClipboardProvider,
|
|
3609
|
+
setOAuthProvider,
|
|
2594
3610
|
setPluginWebViewExtraHosts,
|
|
2595
3611
|
setUIActionNavigator,
|
|
3612
|
+
shouldRecoverToDefaultTenant,
|
|
2596
3613
|
useLightboxStore,
|
|
2597
3614
|
usePluginBridge,
|
|
2598
3615
|
useVoiceCall,
|
|
2599
|
-
useWidgetHostStore
|
|
3616
|
+
useWidgetHostStore,
|
|
3617
|
+
voiceSession
|
|
2600
3618
|
});
|
|
2601
3619
|
//# sourceMappingURL=index.js.map
|