@umituz/react-native-settings 5.4.17 → 5.4.18

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-settings",
3
- "version": "5.4.17",
3
+ "version": "5.4.18",
4
4
  "description": "Complete settings hub for React Native apps - consolidated package with settings, localization, about, legal, appearance, feedback, FAQs, rating, and gamification - expo-store-review and expo-device now lazy loaded",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./dist/index.d.ts",
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @umituz/react-native-settings - AI Consent Domain
3
+ *
4
+ * AI consent management for React Native apps
5
+ * Required by Apple App Store Guidelines 5.1.1(i) & 5.1.2(i)
6
+ *
7
+ * Displays AI technology disclosure and obtains user consent before
8
+ * using AI generation features.
9
+ *
10
+ * Usage:
11
+ * import {
12
+ * AIConsentScreen,
13
+ * AIConsentModal,
14
+ * AIConsentSetting,
15
+ * useAIConsent
16
+ * } from '@umituz/react-native-settings/ai-consent';
17
+ *
18
+ * // Show modal on app launch
19
+ * const { isConsentModalVisible, handleAcceptConsent, handleDeclineConsent } = useAIConsent();
20
+ *
21
+ * <AIConsentModal
22
+ * visible={isConsentModalVisible}
23
+ * onAccept={handleAcceptConsent}
24
+ * onDecline={handleDeclineConsent}
25
+ * />
26
+ *
27
+ * // Add to settings screen
28
+ * <AIConsentSetting />
29
+ */
30
+
31
+ // =============================================================================
32
+ // PRESENTATION LAYER - Components
33
+ // =============================================================================
34
+
35
+ export { AIConsentModal } from './presentation/components/AIConsentModal';
36
+ export type { AIConsentModalProps } from './presentation/components/AIConsentModal';
37
+
38
+ export { AIConsentSetting } from './presentation/components/AIConsentSetting';
39
+ export type { AIConsentSettingProps } from './presentation/components/AIConsentSetting';
40
+
41
+ // =============================================================================
42
+ // PRESENTATION LAYER - Screens
43
+ // =============================================================================
44
+
45
+ export { AIConsentScreen } from './presentation/screens/AIConsentScreen';
46
+ export type { AIConsentScreenProps, AIConsentScreenParams, AIProvider } from './presentation/screens/AIConsentScreen';
47
+
48
+ // =============================================================================
49
+ // PRESENTATION LAYER - Hooks
50
+ // =============================================================================
51
+
52
+ export { useAIConsent } from './presentation/hooks/useAIConsent';
53
+ export type { UseAIConsentReturn, AIConsentState } from './presentation/hooks/useAIConsent';
@@ -0,0 +1,64 @@
1
+ /**
2
+ * AI Consent Modal
3
+ *
4
+ * Modal wrapper for AI consent screen.
5
+ * Required by Apple App Store Guidelines 5.1.1(i) & 5.1.2(i)
6
+ *
7
+ * Displays on first app launch before any AI features are used.
8
+ * Can also be shown manually from settings.
9
+ *
10
+ * Usage:
11
+ * <AIConsentModal
12
+ * visible={isConsentModalVisible}
13
+ * onAccept={handleAccept}
14
+ * onDecline={handleDecline}
15
+ * />
16
+ */
17
+
18
+ import React, { memo } from 'react';
19
+ import { Modal, View, StyleSheet } from 'react-native';
20
+ import { AIConsentScreen, type AIProvider } from '../screens/AIConsentScreen';
21
+
22
+ export interface AIConsentModalProps {
23
+ visible: boolean;
24
+ onAccept: () => void;
25
+ onDecline: () => void;
26
+ providers?: AIProvider[];
27
+ customMessage?: string;
28
+ }
29
+
30
+ export const AIConsentModal: React.FC<AIConsentModalProps> = memo(({
31
+ visible,
32
+ onAccept,
33
+ onDecline,
34
+ providers,
35
+ customMessage,
36
+ }) => {
37
+ return (
38
+ <Modal
39
+ visible={visible}
40
+ animationType="slide"
41
+ transparent={false}
42
+ onRequestClose={onDecline}
43
+ >
44
+ <View style={styles.container}>
45
+ <AIConsentScreen
46
+ providers={providers}
47
+ customMessage={customMessage}
48
+ onAccept={onAccept}
49
+ onDecline={onDecline}
50
+ standalone={true}
51
+ />
52
+ </View>
53
+ </Modal>
54
+ );
55
+ });
56
+
57
+ AIConsentModal.displayName = 'AIConsentModal';
58
+
59
+ const styles = StyleSheet.create({
60
+ container: {
61
+ flex: 1,
62
+ backgroundColor: '#FFFFFF',
63
+ },
64
+ });
@@ -0,0 +1,106 @@
1
+ /**
2
+ * AIConsentSetting Component
3
+ *
4
+ * Settings list item for AI consent management.
5
+ * Shows current consent status and navigates to full consent screen.
6
+ *
7
+ * Features:
8
+ * - Displays consent status (accepted/declined/pending)
9
+ * - Tappable card that opens AI consent screen
10
+ * - Icon with background color
11
+ * - Internationalized
12
+ * - Universal across iOS, Android, Web
13
+ *
14
+ * Usage:
15
+ * import { AIConsentSetting } from '@umituz/react-native-settings/ai-consent';
16
+ *
17
+ * <AIConsentSetting />
18
+ */
19
+
20
+ import React, { useCallback, memo } from 'react';
21
+ import { View, StyleSheet } from 'react-native';
22
+ import { useAppDesignTokens, withAlpha } from '@umituz/react-native-design-system/theme';
23
+ import { useAppNavigation } from '@umituz/react-native-design-system/molecules';
24
+ import { AtomicText } from '@umituz/react-native-design-system/atoms';
25
+ import { useAIConsent } from '../hooks/useAIConsent';
26
+
27
+ export interface AIConsentSettingProps {
28
+ /** Custom title */
29
+ title?: string;
30
+ /** Custom description when consented */
31
+ consentedDescription?: string;
32
+ /** Custom description when not consented */
33
+ notConsentedDescription?: string;
34
+ }
35
+
36
+ export const AIConsentSetting: React.FC<AIConsentSettingProps> = memo(({
37
+ title = 'AI Technology Consent',
38
+ consentedDescription = 'You have consented to use AI services',
39
+ notConsentedDescription = 'Review AI service disclosure',
40
+ }) => {
41
+ const tokens = useAppDesignTokens();
42
+ const navigation = useAppNavigation();
43
+ const { hasConsented, isLoading } = useAIConsent();
44
+
45
+ const handlePress = useCallback(() => {
46
+ navigation.push('AIConsent' as never);
47
+ }, [navigation]);
48
+
49
+ if (isLoading) {
50
+ return null;
51
+ }
52
+
53
+ const iconColor = hasConsented ? tokens.colors.success : tokens.colors.warning;
54
+ const backgroundColor = withAlpha(iconColor, 0.1);
55
+ const description = hasConsented ? consentedDescription : notConsentedDescription;
56
+
57
+ return (
58
+ <View style={[styles.container, { backgroundColor }]}>
59
+ <View style={[styles.iconContainer, { backgroundColor: iconColor }]}>
60
+ <AtomicText style={styles.icon}>🤖</AtomicText>
61
+ </View>
62
+
63
+ <View style={styles.content}>
64
+ <AtomicText style={styles.title}>{title}</AtomicText>
65
+ <AtomicText style={styles.description}>{description}</AtomicText>
66
+ </View>
67
+ </View>
68
+ );
69
+ });
70
+
71
+ AIConsentSetting.displayName = 'AIConsentSetting';
72
+
73
+ const styles = StyleSheet.create({
74
+ container: {
75
+ flexDirection: 'row',
76
+ alignItems: 'center',
77
+ padding: 16,
78
+ borderRadius: 12,
79
+ marginVertical: 8,
80
+ },
81
+ iconContainer: {
82
+ width: 48,
83
+ height: 48,
84
+ borderRadius: 24,
85
+ alignItems: 'center',
86
+ justifyContent: 'center',
87
+ marginRight: 16,
88
+ },
89
+ icon: {
90
+ fontSize: 24,
91
+ },
92
+ content: {
93
+ flex: 1,
94
+ },
95
+ title: {
96
+ fontSize: 16,
97
+ fontWeight: '600',
98
+ color: '#111827',
99
+ marginBottom: 4,
100
+ },
101
+ description: {
102
+ fontSize: 14,
103
+ color: '#6B7280',
104
+ lineHeight: 20,
105
+ },
106
+ });
@@ -0,0 +1,125 @@
1
+ /**
2
+ * useAIConsent Hook
3
+ * Manages AI consent state and display logic
4
+ * Required by Apple App Store Guidelines 5.1.1(i) & 5.1.2(i)
5
+ *
6
+ * Features:
7
+ * - Checks if user has consented to AI services
8
+ * - Shows modal on first use
9
+ * - Persists consent state
10
+ * - Memoized for performance
11
+ */
12
+
13
+ import { useState, useEffect, useCallback } from 'react';
14
+ import { useStorage } from '@umituz/react-native-design-system/storage';
15
+
16
+ export interface AIConsentState {
17
+ hasConsented: boolean;
18
+ consentTimestamp?: number;
19
+ consentVersion?: string;
20
+ }
21
+
22
+ const CONSENT_STORAGE_KEY = '@app:ai_consent_accepted';
23
+ const CURRENT_CONSENT_VERSION = '1.0';
24
+
25
+ export interface UseAIConsentReturn {
26
+ isLoading: boolean;
27
+ isConsentModalVisible: boolean;
28
+ hasConsented: boolean;
29
+ consentState: AIConsentState | null;
30
+ handleAcceptConsent: () => Promise<void>;
31
+ handleDeclineConsent: () => void;
32
+ showConsentModal: () => void;
33
+ checkConsent: () => Promise<void>;
34
+ }
35
+
36
+ export const useAIConsent = (): UseAIConsentReturn => {
37
+ const { getString, setString } = useStorage();
38
+ const [isConsentModalVisible, setIsConsentModalVisible] = useState(false);
39
+ const [hasConsented, setHasConsented] = useState(false);
40
+ const [consentState, setConsentState] = useState<AIConsentState | null>(null);
41
+ const [isLoading, setIsLoading] = useState(true);
42
+
43
+ /**
44
+ * Check if user has previously consented
45
+ */
46
+ const checkConsent = useCallback(async () => {
47
+ setIsLoading(true);
48
+ try {
49
+ const consentData = await getString(CONSENT_STORAGE_KEY, '');
50
+
51
+ if (consentData) {
52
+ const parsed: AIConsentState = JSON.parse(consentData);
53
+ setConsentState(parsed);
54
+ setHasConsented(parsed.hasConsented);
55
+
56
+ // Show modal if user hasn't consented
57
+ if (!parsed.hasConsented) {
58
+ setIsConsentModalVisible(true);
59
+ }
60
+ } else {
61
+ // No consent found - show modal
62
+ setIsConsentModalVisible(true);
63
+ }
64
+ } catch (error) {
65
+ console.error('[useAIConsent] Failed to check consent:', error);
66
+ // On error, show modal to be safe
67
+ setIsConsentModalVisible(true);
68
+ } finally {
69
+ setIsLoading(false);
70
+ }
71
+ }, [getString]);
72
+
73
+ /**
74
+ * Handle user accepting AI consent
75
+ */
76
+ const handleAcceptConsent = useCallback(async () => {
77
+ try {
78
+ const newState: AIConsentState = {
79
+ hasConsented: true,
80
+ consentTimestamp: Date.now(),
81
+ consentVersion: CURRENT_CONSENT_VERSION,
82
+ };
83
+
84
+ await setString(CONSENT_STORAGE_KEY, JSON.stringify(newState));
85
+ setConsentState(newState);
86
+ setHasConsented(true);
87
+ setIsConsentModalVisible(false);
88
+ } catch (error) {
89
+ console.error('[useAIConsent] Failed to save consent:', error);
90
+ throw error;
91
+ }
92
+ }, [setString]);
93
+
94
+ /**
95
+ * Handle user declining AI consent
96
+ */
97
+ const handleDeclineConsent = useCallback(() => {
98
+ setIsConsentModalVisible(false);
99
+ // User declined - they can still use the app but AI features will be blocked
100
+ // This is handled by the hasConsented flag
101
+ }, []);
102
+
103
+ /**
104
+ * Manually show consent modal (e.g., from settings)
105
+ */
106
+ const showConsentModal = useCallback(() => {
107
+ setIsConsentModalVisible(true);
108
+ }, []);
109
+
110
+ // Check consent on mount
111
+ useEffect(() => {
112
+ void checkConsent();
113
+ }, [checkConsent]);
114
+
115
+ return {
116
+ isLoading,
117
+ isConsentModalVisible,
118
+ hasConsented,
119
+ consentState,
120
+ handleAcceptConsent,
121
+ handleDeclineConsent,
122
+ showConsentModal,
123
+ checkConsent,
124
+ };
125
+ };
@@ -0,0 +1,414 @@
1
+ /**
2
+ * AI Consent Screen
3
+ *
4
+ * Full screen for displaying AI technology disclosure and consent.
5
+ * Required by Apple App Store Guidelines 5.1.1(i) & 5.1.2(i)
6
+ *
7
+ * Features:
8
+ * - Lists all AI providers and their purposes
9
+ * - Explains data sharing practices
10
+ * - Provides privacy policy links
11
+ * - Accept/Decline buttons
12
+ * - Scrollable content
13
+ */
14
+
15
+ import React, { memo } from 'react';
16
+ import {
17
+ View,
18
+ StyleSheet,
19
+ ScrollView,
20
+ TouchableOpacity,
21
+ } from 'react-native';
22
+ import {
23
+ ScreenLayout,
24
+ } from '@umituz/react-native-design-system/layouts';
25
+ import {
26
+ AtomicText,
27
+ AtomicButton,
28
+ AtomicSpinner,
29
+ } from '@umituz/react-native-design-system/atoms';
30
+ import {
31
+ NavigationHeader,
32
+ useAppNavigation,
33
+ } from '@umituz/react-native-design-system/molecules';
34
+ import { useAppDesignTokens } from '@umituz/react-native-design-system/theme';
35
+
36
+ export interface AIProvider {
37
+ name: string;
38
+ purpose: string;
39
+ privacyUrl: string;
40
+ }
41
+
42
+ export interface AIConsentScreenParams {
43
+ providers?: AIProvider[];
44
+ customMessage?: string;
45
+ onAccept?: () => void;
46
+ onDecline?: () => void;
47
+ [key: string]: unknown;
48
+ }
49
+
50
+ export interface AIConsentScreenProps {
51
+ route?: {
52
+ params?: AIConsentScreenParams;
53
+ };
54
+ providers?: AIProvider[];
55
+ customMessage?: string;
56
+ onAccept?: () => void;
57
+ onDecline?: () => void;
58
+ standalone?: boolean;
59
+ }
60
+
61
+ const DEFAULT_PROVIDERS: AIProvider[] = [
62
+ {
63
+ name: 'Pruna AI',
64
+ purpose: 'Image generation & editing',
65
+ privacyUrl: 'https://pruna.ai/privacy',
66
+ },
67
+ {
68
+ name: 'FAL AI',
69
+ purpose: 'Video generation infrastructure',
70
+ privacyUrl: 'https://fal.ai/privacy',
71
+ },
72
+ {
73
+ name: 'Groq AI',
74
+ purpose: 'Text processing & prompts',
75
+ privacyUrl: 'https://groq.com/privacy',
76
+ },
77
+ ];
78
+
79
+ export const AIConsentScreen: React.FC<AIConsentScreenProps> = memo(({
80
+ route,
81
+ providers = DEFAULT_PROVIDERS,
82
+ customMessage,
83
+ onAccept,
84
+ onDecline,
85
+ standalone = false,
86
+ }) => {
87
+ const navigation = useAppNavigation();
88
+ const tokens = useAppDesignTokens();
89
+ const [loading, setLoading] = React.useState(false);
90
+
91
+ // Get params from route or use props
92
+ const params = route?.params || {};
93
+ const finalProviders = params.providers || providers;
94
+ const finalMessage = params.customMessage || customMessage;
95
+ const finalOnAccept = params.onAccept || onAccept;
96
+ const finalOnDecline = params.onDecline || onDecline;
97
+
98
+ const handleAccept = async () => {
99
+ if (finalOnAccept) {
100
+ setLoading(true);
101
+ try {
102
+ await finalOnAccept();
103
+ } catch (error) {
104
+ console.error('[AIConsentScreen] Accept error:', error);
105
+ } finally {
106
+ setLoading(false);
107
+ }
108
+ }
109
+
110
+ if (!standalone) {
111
+ navigation.goBack();
112
+ }
113
+ };
114
+
115
+ const handleDecline = () => {
116
+ if (finalOnDecline) {
117
+ finalOnDecline();
118
+ }
119
+
120
+ if (!standalone) {
121
+ navigation.goBack();
122
+ }
123
+ };
124
+
125
+ const handleLinkPress = (url: string) => {
126
+ // TODO: Implement Linking.openURL
127
+ console.log('[AIConsentScreen] Open URL:', url);
128
+ };
129
+
130
+ return (
131
+ <ScreenLayout
132
+ scrollable={true}
133
+ edges={['top', 'bottom', 'left', 'right']}
134
+ hideScrollIndicator={false}
135
+ >
136
+ {!standalone && (
137
+ <NavigationHeader
138
+ title="AI Technology Disclosure"
139
+ onBackPress={() => navigation.goBack()}
140
+ />
141
+ )}
142
+
143
+ <ScrollView
144
+ style={styles.scrollView}
145
+ contentContainerStyle={styles.scrollContent}
146
+ showsVerticalScrollIndicator={false}
147
+ >
148
+ {finalMessage && (
149
+ <AtomicText style={styles.introText}>
150
+ {finalMessage}
151
+ </AtomicText>
152
+ )}
153
+
154
+ <AtomicText style={styles.introText}>
155
+ Vivoim uses multiple AI services to generate content. Before using
156
+ our AI features, please review how your data is processed.
157
+ </AtomicText>
158
+
159
+ <View style={styles.section}>
160
+ <AtomicText style={styles.sectionTitle}>
161
+ 🤖 AI Services We Use
162
+ </AtomicText>
163
+ <View style={styles.providerList}>
164
+ {finalProviders.map((provider, index) => (
165
+ <View key={index} style={styles.providerItem}>
166
+ <View style={styles.providerHeader}>
167
+ <AtomicText style={styles.providerName}>
168
+ {provider.name}
169
+ </AtomicText>
170
+ <TouchableOpacity
171
+ onPress={() => handleLinkPress(provider.privacyUrl)}
172
+ >
173
+ <AtomicText style={styles.privacyLink}>
174
+ Privacy Policy
175
+ </AtomicText>
176
+ </TouchableOpacity>
177
+ </View>
178
+ <AtomicText style={styles.providerPurpose}>
179
+ {provider.purpose}
180
+ </AtomicText>
181
+ </View>
182
+ ))}
183
+ </View>
184
+ </View>
185
+
186
+ <View style={styles.section}>
187
+ <AtomicText style={styles.sectionTitle}>
188
+ 📸 What We Send to AI Services
189
+ </AtomicText>
190
+ <AtomicText style={styles.bullet}>
191
+ • Photos you select from your gallery
192
+ </AtomicText>
193
+ <AtomicText style={styles.bullet}>
194
+ • Text prompts you enter
195
+ </AtomicText>
196
+ <AtomicText style={styles.bullet}>
197
+ • Generation instructions and settings
198
+ </AtomicText>
199
+ <AtomicText style={styles.note}>
200
+ Note: Your photos are processed to generate content and are NOT
201
+ stored permanently by us or AI providers after processing
202
+ completes.
203
+ </AtomicText>
204
+ </View>
205
+
206
+ <View style={styles.section}>
207
+ <AtomicText style={styles.sectionTitle}>
208
+ 🔒 Data Privacy
209
+ </AtomicText>
210
+ <AtomicText style={styles.bullet}>
211
+ • Original photos are deleted after processing
212
+ </AtomicText>
213
+ <AtomicText style={styles.bullet}>
214
+ • Generated content is stored in your account only
215
+ </AtomicText>
216
+ <AtomicText style={styles.bullet}>
217
+ • You can delete any content at any time
218
+ </AtomicText>
219
+ <AtomicText style={styles.bullet}>
220
+ • Face data is used for generation only
221
+ </AtomicText>
222
+ <AtomicText style={styles.bullet}>
223
+ • No biometric authentication or tracking
224
+ </AtomicText>
225
+ </View>
226
+
227
+ <View style={styles.section}>
228
+ <AtomicText style={styles.sectionTitle}>
229
+ 📄 Legal Documents
230
+ </AtomicText>
231
+ <TouchableOpacity
232
+ style={styles.linkButton}
233
+ onPress={() => handleLinkPress('https://umituz.com/projects/ai-technology/vivoim/privacy')}
234
+ >
235
+ <AtomicText style={styles.linkText}>
236
+ Privacy Policy →
237
+ </AtomicText>
238
+ </TouchableOpacity>
239
+ <TouchableOpacity
240
+ style={styles.linkButton}
241
+ onPress={() => handleLinkPress('https://umituz.com/projects/ai-technology/vivoim/terms')}
242
+ >
243
+ <AtomicText style={styles.linkText}>
244
+ Terms of Use →
245
+ </AtomicText>
246
+ </TouchableOpacity>
247
+ </View>
248
+
249
+ <View style={styles.declarationSection}>
250
+ <View style={styles.checkbox}>
251
+ <View style={styles.checkboxInner}>
252
+ <AtomicText style={styles.checkmark}>✓</AtomicText>
253
+ </View>
254
+ </View>
255
+ <AtomicText style={styles.declarationText}>
256
+ I have read and agree to the Privacy Policy and Terms of Use. I
257
+ understand that my photos will be processed by third-party AI
258
+ services to generate content.
259
+ </AtomicText>
260
+ </View>
261
+ </ScrollView>
262
+
263
+ <View style={styles.footer}>
264
+ <AtomicButton
265
+ variant="secondary"
266
+ onPress={handleDecline}
267
+ style={styles.declineButton}
268
+ fullWidth
269
+ >
270
+ Decline
271
+ </AtomicButton>
272
+ <AtomicButton
273
+ variant="primary"
274
+ onPress={handleAccept}
275
+ disabled={loading}
276
+ style={styles.acceptButton}
277
+ fullWidth
278
+ >
279
+ {loading ? (
280
+ <AtomicSpinner size="sm" color="background" />
281
+ ) : (
282
+ 'I Accept'
283
+ )}
284
+ </AtomicButton>
285
+ </View>
286
+ </ScreenLayout>
287
+ );
288
+ });
289
+
290
+ AIConsentScreen.displayName = 'AIConsentScreen';
291
+
292
+ const styles = StyleSheet.create({
293
+ scrollView: {
294
+ flex: 1,
295
+ },
296
+ scrollContent: {
297
+ paddingBottom: 100,
298
+ },
299
+ introText: {
300
+ fontSize: 15,
301
+ lineHeight: 22,
302
+ marginBottom: 24,
303
+ color: '#374151',
304
+ },
305
+ section: {
306
+ marginBottom: 24,
307
+ padding: 16,
308
+ backgroundColor: '#F9FAFB',
309
+ borderRadius: 12,
310
+ },
311
+ sectionTitle: {
312
+ fontSize: 17,
313
+ fontWeight: '600',
314
+ color: '#111827',
315
+ marginBottom: 12,
316
+ },
317
+ providerList: {
318
+ gap: 12,
319
+ },
320
+ providerItem: {
321
+ backgroundColor: '#FFFFFF',
322
+ padding: 12,
323
+ borderRadius: 8,
324
+ borderWidth: 1,
325
+ borderColor: '#E5E7EB',
326
+ },
327
+ providerHeader: {
328
+ flexDirection: 'row',
329
+ justifyContent: 'space-between',
330
+ alignItems: 'center',
331
+ marginBottom: 4,
332
+ },
333
+ providerName: {
334
+ fontSize: 15,
335
+ fontWeight: '600',
336
+ color: '#111827',
337
+ },
338
+ privacyLink: {
339
+ fontSize: 13,
340
+ color: '#3B82F6',
341
+ },
342
+ providerPurpose: {
343
+ fontSize: 14,
344
+ color: '#6B7280',
345
+ },
346
+ bullet: {
347
+ fontSize: 15,
348
+ color: '#374151',
349
+ lineHeight: 22,
350
+ marginLeft: 8,
351
+ },
352
+ note: {
353
+ fontSize: 13,
354
+ color: '#6B7280',
355
+ fontStyle: 'italic',
356
+ marginLeft: 8,
357
+ marginTop: 4,
358
+ },
359
+ linkButton: {
360
+ paddingVertical: 8,
361
+ marginTop: 8,
362
+ },
363
+ linkText: {
364
+ fontSize: 15,
365
+ color: '#3B82F6',
366
+ fontWeight: '500',
367
+ },
368
+ declarationSection: {
369
+ flexDirection: 'row',
370
+ alignItems: 'flex-start',
371
+ marginTop: 8,
372
+ padding: 12,
373
+ backgroundColor: '#EFF6FF',
374
+ borderRadius: 8,
375
+ },
376
+ checkbox: {
377
+ width: 24,
378
+ height: 24,
379
+ marginRight: 12,
380
+ marginTop: 2,
381
+ },
382
+ checkboxInner: {
383
+ width: 24,
384
+ height: 24,
385
+ borderRadius: 4,
386
+ backgroundColor: '#3B82F6',
387
+ alignItems: 'center',
388
+ justifyContent: 'center',
389
+ },
390
+ checkmark: {
391
+ color: '#FFFFFF',
392
+ fontSize: 16,
393
+ fontWeight: '700',
394
+ },
395
+ declarationText: {
396
+ flex: 1,
397
+ fontSize: 14,
398
+ color: '#1E3A8A',
399
+ lineHeight: 20,
400
+ },
401
+ footer: {
402
+ flexDirection: 'row',
403
+ padding: 16,
404
+ borderTopWidth: 1,
405
+ borderTopColor: '#E5E7EB',
406
+ gap: 12,
407
+ },
408
+ declineButton: {
409
+ flex: 1,
410
+ },
411
+ acceptButton: {
412
+ flex: 1,
413
+ },
414
+ });
package/src/index.ts CHANGED
@@ -141,6 +141,9 @@ export * from "./domains/gamification";
141
141
  // Localization Domain - i18n, language selection, translations
142
142
  export * from "./domains/localization";
143
143
 
144
+ // AI Consent Domain - AI technology disclosure and consent
145
+ export * from "./domains/ai-consent";
146
+
144
147
  // =============================================================================
145
148
  // PRESENTATION LAYER - Config Creator Utilities
146
149
  // =============================================================================
@@ -6,6 +6,7 @@ import { SettingsScreen } from "../../screens/SettingsScreen";
6
6
  import { DisclaimerScreen } from "../../../domains/disclaimer/presentation/screens/DisclaimerScreen";
7
7
  import { FeedbackScreen } from "../../../domains/feedback/presentation/screens/FeedbackScreen";
8
8
  import { RatingPromptScreen } from "../../../domains/rating/presentation/screens/RatingPromptScreen";
9
+ import { AIConsentScreen } from "../../../domains/ai-consent/presentation/screens/AIConsentScreen";
9
10
 
10
11
  // AccountScreen is an optional peer — lazy require so the package works without @umituz/react-native-auth
11
12
  // Returns null if @umituz/react-native-auth is not installed
@@ -198,6 +199,12 @@ export const useSettingsScreens = (props: UseSettingsScreensProps): StackScreen[
198
199
  options: { headerShown: false },
199
200
  };
200
201
 
202
+ const aiConsentScreen = {
203
+ name: "AIConsent" as const,
204
+ component: AIConsentScreen,
205
+ options: { headerShown: false },
206
+ };
207
+
201
208
  return combineScreens(
202
209
  baseScreens,
203
210
  faqScreen,
@@ -209,7 +216,8 @@ export const useSettingsScreens = (props: UseSettingsScreensProps): StackScreen[
209
216
  featureRequestScreen,
210
217
  disclaimerScreen,
211
218
  feedbackScreen,
212
- ratingPromptScreen
219
+ ratingPromptScreen,
220
+ aiConsentScreen
213
221
  );
214
222
  }, [
215
223
  translations,
@@ -9,6 +9,7 @@ import type { FAQCategory } from "../../domains/faqs";
9
9
  import type { DisclaimerScreenParams } from "../../domains/disclaimer/presentation/screens/DisclaimerScreen";
10
10
  import type { FeedbackScreenParams } from "../../domains/feedback/presentation/screens/FeedbackScreen";
11
11
  import type { RatingPromptScreenParams } from "../../domains/rating/presentation/screens/RatingPromptScreen";
12
+ import type { AIConsentScreenParams } from "../../domains/ai-consent/presentation/screens/AIConsentScreen";
12
13
 
13
14
  /**
14
15
  * App Info passed from main app (APP_INFO constant)
@@ -54,6 +55,7 @@ export type SettingsStackParamList = {
54
55
  Disclaimer: DisclaimerScreenParams;
55
56
  Feedback: FeedbackScreenParams;
56
57
  RatingPrompt: RatingPromptScreenParams;
58
+ AIConsent: AIConsentScreenParams;
57
59
  PasswordPrompt: {
58
60
  onComplete: (password: string | null) => void;
59
61
  title?: string;