@mobileai/react-native 0.9.18 → 0.9.19
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/LICENSE +28 -20
- package/MobileAIFloatingOverlay.podspec +25 -0
- package/android/build.gradle +61 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/com/mobileai/overlay/FloatingOverlayView.kt +151 -0
- package/android/src/main/java/com/mobileai/overlay/MobileAIOverlayPackage.kt +23 -0
- package/android/src/newarch/com/mobileai/overlay/FloatingOverlayViewManager.kt +45 -0
- package/android/src/oldarch/com/mobileai/overlay/FloatingOverlayViewManager.kt +29 -0
- package/ios/MobileAIFloatingOverlayComponentView.mm +73 -0
- package/lib/module/components/AIAgent.js +902 -136
- package/lib/module/components/AIConsentDialog.js +439 -0
- package/lib/module/components/AgentChatBar.js +828 -134
- package/lib/module/components/AgentOverlay.js +2 -1
- package/lib/module/components/DiscoveryTooltip.js +21 -9
- package/lib/module/components/FloatingOverlayWrapper.js +108 -0
- package/lib/module/components/Icons.js +123 -0
- package/lib/module/config/endpoints.js +12 -2
- package/lib/module/core/AgentRuntime.js +373 -27
- package/lib/module/core/FiberAdapter.js +56 -0
- package/lib/module/core/FiberTreeWalker.js +186 -80
- package/lib/module/core/IdleDetector.js +19 -0
- package/lib/module/core/NativeAlertInterceptor.js +191 -0
- package/lib/module/core/systemPrompt.js +203 -45
- package/lib/module/index.js +3 -0
- package/lib/module/providers/GeminiProvider.js +72 -56
- package/lib/module/providers/ProviderFactory.js +6 -2
- package/lib/module/services/AudioInputService.js +3 -12
- package/lib/module/services/AudioOutputService.js +1 -13
- package/lib/module/services/ConversationService.js +166 -0
- package/lib/module/services/MobileAIKnowledgeRetriever.js +41 -0
- package/lib/module/services/VoiceService.js +29 -8
- package/lib/module/services/telemetry/MobileAI.js +44 -0
- package/lib/module/services/telemetry/TelemetryService.js +13 -1
- package/lib/module/services/telemetry/TouchAutoCapture.js +44 -18
- package/lib/module/specs/FloatingOverlayNativeComponent.ts +19 -0
- package/lib/module/support/CSATSurvey.js +95 -12
- package/lib/module/support/EscalationSocket.js +70 -1
- package/lib/module/support/ReportedIssueEventSource.js +148 -0
- package/lib/module/support/escalateTool.js +4 -2
- package/lib/module/support/index.js +1 -0
- package/lib/module/support/reportIssueTool.js +127 -0
- package/lib/module/support/supportPrompt.js +77 -9
- package/lib/module/tools/guideTool.js +2 -1
- package/lib/module/tools/longPressTool.js +4 -3
- package/lib/module/tools/pickerTool.js +6 -4
- package/lib/module/tools/tapTool.js +12 -3
- package/lib/module/tools/typeTool.js +19 -10
- package/lib/module/utils/logger.js +175 -6
- package/lib/typescript/react-native.config.d.ts +11 -0
- package/lib/typescript/src/components/AIAgent.d.ts +28 -2
- package/lib/typescript/src/components/AIConsentDialog.d.ts +153 -0
- package/lib/typescript/src/components/AgentChatBar.d.ts +15 -2
- package/lib/typescript/src/components/DiscoveryTooltip.d.ts +3 -1
- package/lib/typescript/src/components/FloatingOverlayWrapper.d.ts +51 -0
- package/lib/typescript/src/components/Icons.d.ts +8 -0
- package/lib/typescript/src/config/endpoints.d.ts +5 -3
- package/lib/typescript/src/core/AgentRuntime.d.ts +4 -0
- package/lib/typescript/src/core/FiberAdapter.d.ts +25 -0
- package/lib/typescript/src/core/FiberTreeWalker.d.ts +2 -0
- package/lib/typescript/src/core/IdleDetector.d.ts +11 -0
- package/lib/typescript/src/core/NativeAlertInterceptor.d.ts +55 -0
- package/lib/typescript/src/core/types.d.ts +106 -1
- package/lib/typescript/src/index.d.ts +9 -4
- package/lib/typescript/src/providers/GeminiProvider.d.ts +6 -5
- package/lib/typescript/src/services/ConversationService.d.ts +55 -0
- package/lib/typescript/src/services/MobileAIKnowledgeRetriever.d.ts +9 -0
- package/lib/typescript/src/services/telemetry/MobileAI.d.ts +7 -0
- package/lib/typescript/src/services/telemetry/TelemetryService.d.ts +1 -1
- package/lib/typescript/src/services/telemetry/TouchAutoCapture.d.ts +9 -6
- package/lib/typescript/src/services/telemetry/types.d.ts +3 -1
- package/lib/typescript/src/specs/FloatingOverlayNativeComponent.d.ts +17 -0
- package/lib/typescript/src/support/EscalationSocket.d.ts +17 -0
- package/lib/typescript/src/support/ReportedIssueEventSource.d.ts +24 -0
- package/lib/typescript/src/support/escalateTool.d.ts +5 -0
- package/lib/typescript/src/support/index.d.ts +2 -1
- package/lib/typescript/src/support/reportIssueTool.d.ts +20 -0
- package/lib/typescript/src/support/types.d.ts +56 -1
- package/lib/typescript/src/utils/logger.d.ts +15 -0
- package/package.json +19 -5
- package/react-native.config.js +12 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AIConsentDialog — Apple App Store Guideline 5.1.2(i) compliant consent flow.
|
|
5
|
+
*
|
|
6
|
+
* Displays a modal before the first AI interaction that:
|
|
7
|
+
* 1. Names the specific third-party AI provider (e.g., "Google Gemini")
|
|
8
|
+
* 2. Explains what data is shared (screen content, messages)
|
|
9
|
+
* 3. Collects explicit user consent via affirmative tap
|
|
10
|
+
*
|
|
11
|
+
* Persists consent via AsyncStorage so the dialog is shown once per device.
|
|
12
|
+
* If AsyncStorage is unavailable, consent is session-scoped (per app launch).
|
|
13
|
+
*
|
|
14
|
+
* ## Business rationale
|
|
15
|
+
* Apple rejects apps that silently send personal data to third-party AI services.
|
|
16
|
+
* This component ensures compliance WITHOUT the app developer needing to build
|
|
17
|
+
* their own consent flow — they just set `requireConsent={true}` on <AIAgent>.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import React, { useCallback, useEffect, useState } from 'react';
|
|
21
|
+
import { View, Text, Pressable, Modal, StyleSheet, Linking, Animated } from 'react-native';
|
|
22
|
+
import { isNativeOverlayActive } from "./FloatingOverlayWrapper.js";
|
|
23
|
+
|
|
24
|
+
// ─── AsyncStorage Helper ──────────────────────────────────────
|
|
25
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
26
|
+
const CONSENT_STORAGE_KEY = '@mobileai_ai_consent_granted';
|
|
27
|
+
function getStorage() {
|
|
28
|
+
try {
|
|
29
|
+
const origError = console.error;
|
|
30
|
+
console.error = (...args) => {
|
|
31
|
+
const msg = args[0];
|
|
32
|
+
if (typeof msg === 'string' && msg.includes('AsyncStorage')) return;
|
|
33
|
+
origError.apply(console, args);
|
|
34
|
+
};
|
|
35
|
+
try {
|
|
36
|
+
const mod = require('@react-native-async-storage/async-storage');
|
|
37
|
+
const candidate = mod?.default ?? mod?.AsyncStorage ?? null;
|
|
38
|
+
if (candidate && typeof candidate.getItem === 'function') return candidate;
|
|
39
|
+
return null;
|
|
40
|
+
} finally {
|
|
41
|
+
console.error = origError;
|
|
42
|
+
}
|
|
43
|
+
} catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ─── Provider Display Names ───────────────────────────────────
|
|
49
|
+
|
|
50
|
+
const PROVIDER_INFO = {
|
|
51
|
+
gemini: {
|
|
52
|
+
name: 'Google Gemini',
|
|
53
|
+
company: 'Google',
|
|
54
|
+
url: 'https://ai.google.dev/terms'
|
|
55
|
+
},
|
|
56
|
+
openai: {
|
|
57
|
+
name: 'OpenAI GPT',
|
|
58
|
+
company: 'OpenAI',
|
|
59
|
+
url: 'https://openai.com/policies/terms-of-use'
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const DEFAULT_THEME = {
|
|
63
|
+
backdrop: 'rgba(9, 12, 16, 0.52)',
|
|
64
|
+
cardBackground: '#ffffff',
|
|
65
|
+
cardBorder: 'rgba(15, 23, 42, 0.08)',
|
|
66
|
+
iconBackground: '#eef4ff',
|
|
67
|
+
iconColor: '#3156d3',
|
|
68
|
+
title: '#111827',
|
|
69
|
+
body: '#4b5563',
|
|
70
|
+
muted: '#6b7280',
|
|
71
|
+
sectionBackground: '#f8fafc',
|
|
72
|
+
sectionBorder: 'rgba(148, 163, 184, 0.22)',
|
|
73
|
+
bullet: '#3156d3',
|
|
74
|
+
badgeBackground: '#eef4ff',
|
|
75
|
+
badgeText: '#3156d3',
|
|
76
|
+
secondaryButtonBackground: '#f3f4f6',
|
|
77
|
+
secondaryButtonText: '#374151',
|
|
78
|
+
primaryButtonBackground: '#111827',
|
|
79
|
+
primaryButtonText: '#ffffff',
|
|
80
|
+
link: '#3156d3'
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// ─── Public Types ─────────────────────────────────────────────
|
|
84
|
+
|
|
85
|
+
// ─── Props ────────────────────────────────────────────────────
|
|
86
|
+
|
|
87
|
+
// ─── Component ────────────────────────────────────────────────
|
|
88
|
+
|
|
89
|
+
export function AIConsentDialog({
|
|
90
|
+
visible,
|
|
91
|
+
provider,
|
|
92
|
+
config,
|
|
93
|
+
onConsent,
|
|
94
|
+
onDecline,
|
|
95
|
+
language = 'en'
|
|
96
|
+
}) {
|
|
97
|
+
const fadeAnim = React.useRef(new Animated.Value(0)).current;
|
|
98
|
+
const isArabic = language === 'ar';
|
|
99
|
+
const providerInfo = PROVIDER_INFO[provider] || PROVIDER_INFO.gemini;
|
|
100
|
+
const theme = {
|
|
101
|
+
...DEFAULT_THEME,
|
|
102
|
+
...(config.theme || {})
|
|
103
|
+
};
|
|
104
|
+
const providerLabel = config.providerLabel || (isArabic ? 'خدمة الذكاء الاصطناعي المفعلة في التطبيق' : 'the AI service configured for this app');
|
|
105
|
+
const providerUrl = config.providerUrl || providerInfo.url;
|
|
106
|
+
const showProviderBadge = config.showProviderBadge === true;
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
if (visible) {
|
|
109
|
+
Animated.timing(fadeAnim, {
|
|
110
|
+
toValue: 1,
|
|
111
|
+
duration: 250,
|
|
112
|
+
useNativeDriver: true
|
|
113
|
+
}).start();
|
|
114
|
+
}
|
|
115
|
+
}, [visible, fadeAnim]);
|
|
116
|
+
const title = isArabic ? config.titleAr || 'مساعد الذكاء الاصطناعي' : config.title || 'AI Assistant';
|
|
117
|
+
const sharedDataItems = isArabic ? config.sharedDataItemsAr || ['رسالتك', 'نقدر خصوصيتك، لا نرى شاشتك بأي شكل، نحن ندرك فقط سياق التطبيق الحالي'] : config.sharedDataItems || ['Your message', "We appreciate your privacy, we don't see your screen in any way, we are just aware of current app context"];
|
|
118
|
+
const handlePrivacyPolicy = useCallback(() => {
|
|
119
|
+
if (config.privacyPolicyUrl) {
|
|
120
|
+
Linking.openURL(config.privacyPolicyUrl);
|
|
121
|
+
}
|
|
122
|
+
}, [config.privacyPolicyUrl]);
|
|
123
|
+
const ContentWrapper = isNativeOverlayActive ? View : Modal;
|
|
124
|
+
const wrapperProps = isNativeOverlayActive ? {
|
|
125
|
+
style: [StyleSheet.absoluteFill, {
|
|
126
|
+
zIndex: 99999,
|
|
127
|
+
elevation: 99999
|
|
128
|
+
}],
|
|
129
|
+
pointerEvents: 'auto'
|
|
130
|
+
} : {
|
|
131
|
+
visible,
|
|
132
|
+
transparent: true,
|
|
133
|
+
animationType: "none",
|
|
134
|
+
statusBarTranslucent: true,
|
|
135
|
+
onRequestClose: onDecline
|
|
136
|
+
};
|
|
137
|
+
if (!visible) return null;
|
|
138
|
+
return /*#__PURE__*/_jsx(ContentWrapper, {
|
|
139
|
+
...wrapperProps,
|
|
140
|
+
children: /*#__PURE__*/_jsx(View, {
|
|
141
|
+
style: [dialogStyles.backdrop, {
|
|
142
|
+
backgroundColor: theme.backdrop
|
|
143
|
+
}],
|
|
144
|
+
children: /*#__PURE__*/_jsxs(Animated.View, {
|
|
145
|
+
style: [dialogStyles.card, {
|
|
146
|
+
opacity: fadeAnim,
|
|
147
|
+
backgroundColor: theme.cardBackground,
|
|
148
|
+
borderColor: theme.cardBorder
|
|
149
|
+
}],
|
|
150
|
+
children: [/*#__PURE__*/_jsx(View, {
|
|
151
|
+
style: [dialogStyles.iconWrap, {
|
|
152
|
+
backgroundColor: theme.iconBackground
|
|
153
|
+
}],
|
|
154
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
155
|
+
style: [dialogStyles.iconText, {
|
|
156
|
+
color: theme.iconColor
|
|
157
|
+
}],
|
|
158
|
+
children: "\u25CE"
|
|
159
|
+
})
|
|
160
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
161
|
+
style: [dialogStyles.title, {
|
|
162
|
+
color: theme.title
|
|
163
|
+
}, isArabic && dialogStyles.textRTL],
|
|
164
|
+
children: title
|
|
165
|
+
}), /*#__PURE__*/_jsxs(View, {
|
|
166
|
+
style: [dialogStyles.dataSection, {
|
|
167
|
+
backgroundColor: theme.sectionBackground,
|
|
168
|
+
borderColor: theme.sectionBorder
|
|
169
|
+
}],
|
|
170
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
171
|
+
style: [dialogStyles.dataLabel, {
|
|
172
|
+
color: theme.muted
|
|
173
|
+
}, isArabic && dialogStyles.textRTL],
|
|
174
|
+
children: isArabic ? 'يُشارك مع مساعد الذكاء الاصطناعي:' : 'Shared with the AI agent:'
|
|
175
|
+
}), sharedDataItems.map((item, index) => /*#__PURE__*/_jsxs(View, {
|
|
176
|
+
style: dialogStyles.dataItem,
|
|
177
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
178
|
+
style: [dialogStyles.dataBullet, {
|
|
179
|
+
color: theme.bullet
|
|
180
|
+
}],
|
|
181
|
+
children: "\u2022"
|
|
182
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
183
|
+
style: [dialogStyles.dataText, {
|
|
184
|
+
color: theme.body
|
|
185
|
+
}, isArabic && dialogStyles.textRTL],
|
|
186
|
+
children: item
|
|
187
|
+
})]
|
|
188
|
+
}, `${item}-${index}`))]
|
|
189
|
+
}), showProviderBadge && /*#__PURE__*/_jsx(View, {
|
|
190
|
+
style: [dialogStyles.providerBadge, {
|
|
191
|
+
backgroundColor: theme.badgeBackground
|
|
192
|
+
}],
|
|
193
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
194
|
+
style: [dialogStyles.providerBadgeText, {
|
|
195
|
+
color: theme.badgeText
|
|
196
|
+
}],
|
|
197
|
+
children: config.providerBadgeText || (isArabic ? `تعمل بواسطة ${providerLabel}` : `Uses ${providerLabel}`)
|
|
198
|
+
})
|
|
199
|
+
}), config.privacyPolicyUrl && /*#__PURE__*/_jsx(Pressable, {
|
|
200
|
+
onPress: handlePrivacyPolicy,
|
|
201
|
+
style: dialogStyles.privacyLink,
|
|
202
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
203
|
+
style: [dialogStyles.privacyLinkText, {
|
|
204
|
+
color: theme.link
|
|
205
|
+
}],
|
|
206
|
+
children: isArabic ? 'سياسة الخصوصية' : 'Privacy Policy'
|
|
207
|
+
})
|
|
208
|
+
}), !config.privacyPolicyUrl && providerUrl && showProviderBadge && /*#__PURE__*/_jsx(Pressable, {
|
|
209
|
+
onPress: () => Linking.openURL(providerUrl),
|
|
210
|
+
style: dialogStyles.privacyLink,
|
|
211
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
212
|
+
style: [dialogStyles.privacyLinkText, {
|
|
213
|
+
color: theme.link
|
|
214
|
+
}],
|
|
215
|
+
children: isArabic ? 'معلومات إضافية' : 'Learn more'
|
|
216
|
+
})
|
|
217
|
+
}), /*#__PURE__*/_jsxs(View, {
|
|
218
|
+
style: dialogStyles.buttonRow,
|
|
219
|
+
children: [/*#__PURE__*/_jsx(Pressable, {
|
|
220
|
+
style: [dialogStyles.declineBtn, {
|
|
221
|
+
backgroundColor: theme.secondaryButtonBackground
|
|
222
|
+
}],
|
|
223
|
+
onPress: onDecline,
|
|
224
|
+
accessibilityLabel: isArabic ? 'رفض' : 'Decline',
|
|
225
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
226
|
+
style: [dialogStyles.declineBtnText, {
|
|
227
|
+
color: theme.secondaryButtonText
|
|
228
|
+
}],
|
|
229
|
+
children: isArabic ? 'ليس الآن' : 'Not now'
|
|
230
|
+
})
|
|
231
|
+
}), /*#__PURE__*/_jsx(Pressable, {
|
|
232
|
+
style: [dialogStyles.consentBtn, {
|
|
233
|
+
backgroundColor: theme.primaryButtonBackground
|
|
234
|
+
}],
|
|
235
|
+
onPress: onConsent,
|
|
236
|
+
accessibilityLabel: isArabic ? 'متابعة' : 'Continue',
|
|
237
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
238
|
+
style: [dialogStyles.consentBtnText, {
|
|
239
|
+
color: theme.primaryButtonText
|
|
240
|
+
}],
|
|
241
|
+
children: isArabic ? 'متابعة' : 'Continue'
|
|
242
|
+
})
|
|
243
|
+
})]
|
|
244
|
+
})]
|
|
245
|
+
})
|
|
246
|
+
})
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ─── Hook: useAIConsent ───────────────────────────────────────
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Manages consent state persistence via AsyncStorage.
|
|
254
|
+
* Falls back to session-scoped state if AsyncStorage is unavailable.
|
|
255
|
+
*
|
|
256
|
+
* @returns [hasConsented, grantConsent, revokeConsent, isLoading]
|
|
257
|
+
*/
|
|
258
|
+
export function useAIConsent(persist = false) {
|
|
259
|
+
const [hasConsented, setHasConsented] = useState(false);
|
|
260
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
261
|
+
|
|
262
|
+
// Load persisted consent on mount (ONLY if persist is true)
|
|
263
|
+
useEffect(() => {
|
|
264
|
+
void (async () => {
|
|
265
|
+
try {
|
|
266
|
+
if (!persist) return;
|
|
267
|
+
const AS = getStorage();
|
|
268
|
+
if (AS) {
|
|
269
|
+
const stored = await AS.getItem(CONSENT_STORAGE_KEY);
|
|
270
|
+
if (stored === 'true') {
|
|
271
|
+
setHasConsented(true);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
} catch {
|
|
275
|
+
// No persisted consent — will prompt
|
|
276
|
+
} finally {
|
|
277
|
+
setIsLoading(false);
|
|
278
|
+
}
|
|
279
|
+
})();
|
|
280
|
+
}, [persist]);
|
|
281
|
+
const grantConsent = useCallback(async () => {
|
|
282
|
+
setHasConsented(true);
|
|
283
|
+
try {
|
|
284
|
+
if (!persist) return;
|
|
285
|
+
const AS = getStorage();
|
|
286
|
+
await AS?.setItem(CONSENT_STORAGE_KEY, 'true');
|
|
287
|
+
} catch {
|
|
288
|
+
// Consent granted session-only
|
|
289
|
+
}
|
|
290
|
+
}, [persist]);
|
|
291
|
+
const revokeConsent = useCallback(async () => {
|
|
292
|
+
setHasConsented(false);
|
|
293
|
+
try {
|
|
294
|
+
if (!persist) return;
|
|
295
|
+
const AS = getStorage();
|
|
296
|
+
await AS?.removeItem(CONSENT_STORAGE_KEY);
|
|
297
|
+
} catch {
|
|
298
|
+
// Best effort
|
|
299
|
+
}
|
|
300
|
+
}, [persist]);
|
|
301
|
+
return [hasConsented, grantConsent, revokeConsent, isLoading];
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// ─── Styles ───────────────────────────────────────────────────
|
|
305
|
+
|
|
306
|
+
const dialogStyles = StyleSheet.create({
|
|
307
|
+
backdrop: {
|
|
308
|
+
flex: 1,
|
|
309
|
+
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
|
310
|
+
justifyContent: 'center',
|
|
311
|
+
alignItems: 'center',
|
|
312
|
+
padding: 24
|
|
313
|
+
},
|
|
314
|
+
card: {
|
|
315
|
+
borderRadius: 20,
|
|
316
|
+
padding: 24,
|
|
317
|
+
width: '100%',
|
|
318
|
+
maxWidth: 380,
|
|
319
|
+
alignItems: 'center',
|
|
320
|
+
borderWidth: 1,
|
|
321
|
+
shadowColor: '#0f172a',
|
|
322
|
+
shadowOffset: {
|
|
323
|
+
width: 0,
|
|
324
|
+
height: 4
|
|
325
|
+
},
|
|
326
|
+
shadowOpacity: 0.12,
|
|
327
|
+
shadowRadius: 22,
|
|
328
|
+
elevation: 10
|
|
329
|
+
},
|
|
330
|
+
iconWrap: {
|
|
331
|
+
width: 56,
|
|
332
|
+
height: 56,
|
|
333
|
+
borderRadius: 28,
|
|
334
|
+
backgroundColor: 'rgba(123, 104, 238, 0.15)',
|
|
335
|
+
alignItems: 'center',
|
|
336
|
+
justifyContent: 'center',
|
|
337
|
+
marginBottom: 16
|
|
338
|
+
},
|
|
339
|
+
iconText: {
|
|
340
|
+
fontSize: 26,
|
|
341
|
+
fontWeight: '700'
|
|
342
|
+
},
|
|
343
|
+
title: {
|
|
344
|
+
fontSize: 20,
|
|
345
|
+
fontWeight: '700',
|
|
346
|
+
color: '#ffffff',
|
|
347
|
+
marginBottom: 12,
|
|
348
|
+
textAlign: 'center'
|
|
349
|
+
},
|
|
350
|
+
body: {
|
|
351
|
+
fontSize: 14,
|
|
352
|
+
lineHeight: 20,
|
|
353
|
+
textAlign: 'center',
|
|
354
|
+
marginBottom: 10
|
|
355
|
+
},
|
|
356
|
+
summary: {
|
|
357
|
+
fontSize: 13,
|
|
358
|
+
lineHeight: 19,
|
|
359
|
+
textAlign: 'center',
|
|
360
|
+
marginBottom: 16
|
|
361
|
+
},
|
|
362
|
+
textRTL: {
|
|
363
|
+
textAlign: 'right',
|
|
364
|
+
writingDirection: 'rtl'
|
|
365
|
+
},
|
|
366
|
+
dataSection: {
|
|
367
|
+
width: '100%',
|
|
368
|
+
borderRadius: 12,
|
|
369
|
+
padding: 14,
|
|
370
|
+
marginBottom: 14,
|
|
371
|
+
borderWidth: 1
|
|
372
|
+
},
|
|
373
|
+
dataLabel: {
|
|
374
|
+
fontSize: 12,
|
|
375
|
+
fontWeight: '600',
|
|
376
|
+
color: 'rgba(255, 255, 255, 0.5)',
|
|
377
|
+
textTransform: 'uppercase',
|
|
378
|
+
letterSpacing: 0.5,
|
|
379
|
+
marginBottom: 8
|
|
380
|
+
},
|
|
381
|
+
dataItem: {
|
|
382
|
+
flexDirection: 'row',
|
|
383
|
+
alignItems: 'flex-start',
|
|
384
|
+
marginBottom: 4
|
|
385
|
+
},
|
|
386
|
+
dataBullet: {
|
|
387
|
+
color: '#7B68EE',
|
|
388
|
+
fontSize: 14,
|
|
389
|
+
marginRight: 8,
|
|
390
|
+
marginTop: 1
|
|
391
|
+
},
|
|
392
|
+
dataText: {
|
|
393
|
+
fontSize: 13,
|
|
394
|
+
flex: 1
|
|
395
|
+
},
|
|
396
|
+
providerBadge: {
|
|
397
|
+
borderRadius: 8,
|
|
398
|
+
paddingHorizontal: 12,
|
|
399
|
+
paddingVertical: 6,
|
|
400
|
+
marginBottom: 12
|
|
401
|
+
},
|
|
402
|
+
providerBadgeText: {
|
|
403
|
+
fontSize: 12,
|
|
404
|
+
fontWeight: '600'
|
|
405
|
+
},
|
|
406
|
+
privacyLink: {
|
|
407
|
+
marginBottom: 20
|
|
408
|
+
},
|
|
409
|
+
privacyLinkText: {
|
|
410
|
+
fontSize: 13,
|
|
411
|
+
textDecorationLine: 'underline'
|
|
412
|
+
},
|
|
413
|
+
buttonRow: {
|
|
414
|
+
flexDirection: 'row',
|
|
415
|
+
gap: 12,
|
|
416
|
+
width: '100%'
|
|
417
|
+
},
|
|
418
|
+
declineBtn: {
|
|
419
|
+
flex: 1,
|
|
420
|
+
paddingVertical: 14,
|
|
421
|
+
borderRadius: 12,
|
|
422
|
+
alignItems: 'center'
|
|
423
|
+
},
|
|
424
|
+
declineBtnText: {
|
|
425
|
+
fontSize: 15,
|
|
426
|
+
fontWeight: '600'
|
|
427
|
+
},
|
|
428
|
+
consentBtn: {
|
|
429
|
+
flex: 1,
|
|
430
|
+
paddingVertical: 14,
|
|
431
|
+
borderRadius: 12,
|
|
432
|
+
alignItems: 'center'
|
|
433
|
+
},
|
|
434
|
+
consentBtnText: {
|
|
435
|
+
fontSize: 15,
|
|
436
|
+
fontWeight: '700'
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
//# sourceMappingURL=AIConsentDialog.js.map
|