@umituz/react-native-settings 4.20.3 → 4.20.5
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 +1 -1
- package/src/domains/appearance/presentation/screens/AppearanceScreen.tsx +9 -74
- package/src/domains/legal/presentation/components/LegalDocumentsList.tsx +115 -0
- package/src/domains/legal/presentation/components/LegalScreenHeader.tsx +45 -0
- package/src/domains/legal/presentation/components/index.ts +5 -0
- package/src/domains/legal/presentation/screens/LegalScreen.tsx +35 -205
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-settings",
|
|
3
|
-
"version": "4.20.
|
|
3
|
+
"version": "4.20.5",
|
|
4
4
|
"description": "Complete settings hub for React Native apps - consolidated package with settings, about, legal, appearance, feedback, FAQs, and rating",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Appearance Screen
|
|
3
3
|
*
|
|
4
|
-
* Screen for managing appearance settings including theme mode and custom colors
|
|
5
|
-
*
|
|
4
|
+
* Screen for managing appearance settings including theme mode and custom colors.
|
|
5
|
+
* Uses ScreenLayout from design system for consistent UI.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import React, { useMemo, useCallback } from "react";
|
|
9
|
-
import {
|
|
9
|
+
import { ScreenLayout } from "@umituz/react-native-design-system";
|
|
10
10
|
import { useAppDesignTokens } from "@umituz/react-native-design-system";
|
|
11
11
|
import { useAppearance, useAppearanceActions } from "../../hooks";
|
|
12
12
|
import {
|
|
@@ -16,42 +16,14 @@ import {
|
|
|
16
16
|
AppearancePreview,
|
|
17
17
|
type ThemeOptionConfig,
|
|
18
18
|
} from "../components";
|
|
19
|
-
|
|
20
19
|
import type { AppearanceTexts } from "../../types";
|
|
21
20
|
|
|
22
21
|
export interface AppearanceScreenProps {
|
|
23
|
-
/** Texts for localization */
|
|
24
22
|
texts?: AppearanceTexts;
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Custom header component to override default header
|
|
28
|
-
*/
|
|
29
23
|
headerComponent?: React.ReactNode;
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Show/hide theme mode section
|
|
33
|
-
*/
|
|
34
24
|
showThemeSection?: boolean;
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Show/hide custom colors section
|
|
38
|
-
*/
|
|
39
25
|
showColorsSection?: boolean;
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Show/hide preview section
|
|
43
|
-
*/
|
|
44
26
|
showPreviewSection?: boolean;
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Custom container style
|
|
48
|
-
*/
|
|
49
|
-
containerStyle?: any;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Custom content container style
|
|
53
|
-
*/
|
|
54
|
-
contentContainerStyle?: any;
|
|
55
27
|
}
|
|
56
28
|
|
|
57
29
|
export const AppearanceScreen: React.FC<AppearanceScreenProps> = ({
|
|
@@ -60,8 +32,6 @@ export const AppearanceScreen: React.FC<AppearanceScreenProps> = ({
|
|
|
60
32
|
showThemeSection = true,
|
|
61
33
|
showColorsSection = true,
|
|
62
34
|
showPreviewSection = true,
|
|
63
|
-
containerStyle,
|
|
64
|
-
contentContainerStyle,
|
|
65
35
|
}) => {
|
|
66
36
|
const tokens = useAppDesignTokens();
|
|
67
37
|
const { themeMode } = useAppearance();
|
|
@@ -72,10 +42,6 @@ export const AppearanceScreen: React.FC<AppearanceScreenProps> = ({
|
|
|
72
42
|
handleResetColors,
|
|
73
43
|
} = useAppearanceActions();
|
|
74
44
|
|
|
75
|
-
// Memoize styles to prevent unnecessary re-creation
|
|
76
|
-
const styles = useMemo(() => getStyles(tokens), [tokens]);
|
|
77
|
-
|
|
78
|
-
// Memoize header to prevent unnecessary re-renders
|
|
79
45
|
const headerComponentMemo = useMemo(() => {
|
|
80
46
|
return (
|
|
81
47
|
headerComponent || (
|
|
@@ -88,7 +54,6 @@ export const AppearanceScreen: React.FC<AppearanceScreenProps> = ({
|
|
|
88
54
|
);
|
|
89
55
|
}, [headerComponent, tokens, texts?.title, texts?.subtitle]);
|
|
90
56
|
|
|
91
|
-
// Stable callback for color change to prevent infinite re-renders
|
|
92
57
|
const stableHandleColorChange = useCallback(
|
|
93
58
|
(key: keyof typeof localCustomColors, color: string) => {
|
|
94
59
|
handleColorChange(key, color);
|
|
@@ -96,15 +61,11 @@ export const AppearanceScreen: React.FC<AppearanceScreenProps> = ({
|
|
|
96
61
|
[handleColorChange]
|
|
97
62
|
);
|
|
98
63
|
|
|
99
|
-
// Memoize sections to prevent unnecessary re-renders
|
|
100
64
|
const themeSectionMemo = useMemo(() => {
|
|
101
65
|
if (!showThemeSection) return null;
|
|
102
66
|
|
|
103
|
-
// Construct themes from texts prop
|
|
104
|
-
// This adheres to "Package Driven Design" where content is driven by the consumer (App)
|
|
105
67
|
const themes: ThemeOptionConfig[] = [];
|
|
106
68
|
|
|
107
|
-
// We only add the theme option if the corresponding text config is provided
|
|
108
69
|
if (texts?.lightMode) {
|
|
109
70
|
themes.push({
|
|
110
71
|
mode: 'light' as const,
|
|
@@ -125,9 +86,6 @@ export const AppearanceScreen: React.FC<AppearanceScreenProps> = ({
|
|
|
125
86
|
});
|
|
126
87
|
}
|
|
127
88
|
|
|
128
|
-
// If no texts provided, themes array is empty, section will return null.
|
|
129
|
-
// This forces the consuming app to provide the texts.
|
|
130
|
-
|
|
131
89
|
return (
|
|
132
90
|
<ThemeModeSection
|
|
133
91
|
tokens={tokens}
|
|
@@ -194,34 +152,11 @@ export const AppearanceScreen: React.FC<AppearanceScreenProps> = ({
|
|
|
194
152
|
]);
|
|
195
153
|
|
|
196
154
|
return (
|
|
197
|
-
<
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
scrollEventThrottle={16} // 60fps throttling
|
|
204
|
-
>
|
|
205
|
-
{headerComponentMemo}
|
|
206
|
-
{themeSectionMemo}
|
|
207
|
-
{colorsSectionMemo}
|
|
208
|
-
{previewSectionMemo}
|
|
209
|
-
</ScrollView>
|
|
210
|
-
</View>
|
|
155
|
+
<ScreenLayout hideScrollIndicator>
|
|
156
|
+
{headerComponentMemo}
|
|
157
|
+
{themeSectionMemo}
|
|
158
|
+
{colorsSectionMemo}
|
|
159
|
+
{previewSectionMemo}
|
|
160
|
+
</ScreenLayout>
|
|
211
161
|
);
|
|
212
162
|
};
|
|
213
|
-
|
|
214
|
-
const getStyles = (tokens: ReturnType<typeof useAppDesignTokens>) =>
|
|
215
|
-
StyleSheet.create({
|
|
216
|
-
container: {
|
|
217
|
-
flex: 1,
|
|
218
|
-
backgroundColor: tokens.colors.backgroundPrimary,
|
|
219
|
-
},
|
|
220
|
-
scrollView: {
|
|
221
|
-
flex: 1,
|
|
222
|
-
},
|
|
223
|
-
scrollContent: {
|
|
224
|
-
padding: tokens.spacing.md,
|
|
225
|
-
paddingBottom: tokens.spacing.xl,
|
|
226
|
-
},
|
|
227
|
-
});
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Legal Documents List Component
|
|
3
|
+
*
|
|
4
|
+
* Displays list of legal documents (Privacy, Terms, EULA).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React from "react";
|
|
8
|
+
import { View, StyleSheet } from "react-native";
|
|
9
|
+
import { AtomicText, useAppDesignTokens } from "@umituz/react-native-design-system";
|
|
10
|
+
import { LegalItem } from "./LegalItem";
|
|
11
|
+
import { UrlHandlerService } from "../../domain/services/UrlHandlerService";
|
|
12
|
+
|
|
13
|
+
interface LegalDocumentsListProps {
|
|
14
|
+
documentsHeader?: string;
|
|
15
|
+
privacyTitle?: string;
|
|
16
|
+
privacyDescription?: string;
|
|
17
|
+
termsTitle?: string;
|
|
18
|
+
termsDescription?: string;
|
|
19
|
+
eulaTitle?: string;
|
|
20
|
+
eulaDescription?: string;
|
|
21
|
+
onPrivacyPress?: () => void;
|
|
22
|
+
onTermsPress?: () => void;
|
|
23
|
+
onEulaPress?: () => void;
|
|
24
|
+
eulaUrl?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const LegalDocumentsList: React.FC<LegalDocumentsListProps> = React.memo(({
|
|
28
|
+
documentsHeader,
|
|
29
|
+
privacyTitle,
|
|
30
|
+
privacyDescription,
|
|
31
|
+
termsTitle,
|
|
32
|
+
termsDescription,
|
|
33
|
+
eulaTitle,
|
|
34
|
+
eulaDescription,
|
|
35
|
+
onPrivacyPress,
|
|
36
|
+
onTermsPress,
|
|
37
|
+
onEulaPress,
|
|
38
|
+
eulaUrl,
|
|
39
|
+
}) => {
|
|
40
|
+
const tokens = useAppDesignTokens();
|
|
41
|
+
|
|
42
|
+
const handleEulaPress = React.useCallback(async () => {
|
|
43
|
+
if (__DEV__) {
|
|
44
|
+
console.log('LegalDocumentsList: EULA pressed', { eulaUrl });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (onEulaPress) {
|
|
48
|
+
onEulaPress();
|
|
49
|
+
} else if (eulaUrl) {
|
|
50
|
+
try {
|
|
51
|
+
await UrlHandlerService.openUrl(eulaUrl);
|
|
52
|
+
} catch (error) {
|
|
53
|
+
if (__DEV__) {
|
|
54
|
+
console.error('LegalDocumentsList: Error opening EULA URL', error);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}, [onEulaPress, eulaUrl]);
|
|
59
|
+
|
|
60
|
+
const showPrivacy = !!(onPrivacyPress && privacyTitle);
|
|
61
|
+
const showTerms = !!(onTermsPress && termsTitle);
|
|
62
|
+
const showEula = !!((onEulaPress || eulaUrl) && eulaTitle);
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<View style={[styles.section, { marginTop: tokens.spacing.md }]}>
|
|
66
|
+
{documentsHeader && (
|
|
67
|
+
<AtomicText
|
|
68
|
+
type="labelLarge"
|
|
69
|
+
color="textSecondary"
|
|
70
|
+
style={[styles.sectionHeader, {
|
|
71
|
+
marginBottom: tokens.spacing.sm,
|
|
72
|
+
paddingHorizontal: tokens.spacing.md,
|
|
73
|
+
}]}
|
|
74
|
+
>
|
|
75
|
+
{documentsHeader}
|
|
76
|
+
</AtomicText>
|
|
77
|
+
)}
|
|
78
|
+
|
|
79
|
+
{showPrivacy && (
|
|
80
|
+
<LegalItem
|
|
81
|
+
iconName="shield"
|
|
82
|
+
title={privacyTitle!}
|
|
83
|
+
description={privacyDescription}
|
|
84
|
+
onPress={onPrivacyPress}
|
|
85
|
+
testID="privacy-policy-item"
|
|
86
|
+
/>
|
|
87
|
+
)}
|
|
88
|
+
|
|
89
|
+
{showTerms && (
|
|
90
|
+
<LegalItem
|
|
91
|
+
iconName="document-text"
|
|
92
|
+
title={termsTitle!}
|
|
93
|
+
description={termsDescription}
|
|
94
|
+
onPress={onTermsPress}
|
|
95
|
+
testID="terms-of-service-item"
|
|
96
|
+
/>
|
|
97
|
+
)}
|
|
98
|
+
|
|
99
|
+
{showEula && (
|
|
100
|
+
<LegalItem
|
|
101
|
+
iconName="document"
|
|
102
|
+
title={eulaTitle!}
|
|
103
|
+
description={eulaDescription}
|
|
104
|
+
onPress={handleEulaPress}
|
|
105
|
+
testID="eula-item"
|
|
106
|
+
/>
|
|
107
|
+
)}
|
|
108
|
+
</View>
|
|
109
|
+
);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const styles = StyleSheet.create({
|
|
113
|
+
section: {},
|
|
114
|
+
sectionHeader: {},
|
|
115
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Legal Screen Header Component
|
|
3
|
+
*
|
|
4
|
+
* Displays title and description for legal screen.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React from "react";
|
|
8
|
+
import { View, StyleSheet } from "react-native";
|
|
9
|
+
import { AtomicText, useAppDesignTokens } from "@umituz/react-native-design-system";
|
|
10
|
+
|
|
11
|
+
interface LegalScreenHeaderProps {
|
|
12
|
+
title?: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const LegalScreenHeader: React.FC<LegalScreenHeaderProps> = React.memo(({
|
|
17
|
+
title,
|
|
18
|
+
description,
|
|
19
|
+
}) => {
|
|
20
|
+
const tokens = useAppDesignTokens();
|
|
21
|
+
|
|
22
|
+
if (!title) return null;
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<View style={[styles.header, { paddingBottom: tokens.spacing.lg, paddingTop: tokens.spacing.md }]}>
|
|
26
|
+
<AtomicText type="headlineLarge" color="textPrimary">
|
|
27
|
+
{title}
|
|
28
|
+
</AtomicText>
|
|
29
|
+
{description && (
|
|
30
|
+
<AtomicText
|
|
31
|
+
type="bodyMedium"
|
|
32
|
+
color="textSecondary"
|
|
33
|
+
style={[styles.subtitle, { marginTop: tokens.spacing.xs }]}
|
|
34
|
+
>
|
|
35
|
+
{description}
|
|
36
|
+
</AtomicText>
|
|
37
|
+
)}
|
|
38
|
+
</View>
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const styles = StyleSheet.create({
|
|
43
|
+
header: {},
|
|
44
|
+
subtitle: {},
|
|
45
|
+
});
|
|
@@ -2,236 +2,66 @@
|
|
|
2
2
|
* Legal Screen Component
|
|
3
3
|
*
|
|
4
4
|
* Single Responsibility: Layout and orchestration of legal documents list
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* All text content is passed as props (no localization dependency).
|
|
5
|
+
* Uses ScreenLayout from design system for consistent UI.
|
|
8
6
|
*/
|
|
9
7
|
|
|
10
8
|
import React from "react";
|
|
11
|
-
import { View, StyleSheet } from "react-native";
|
|
12
|
-
import { useAppDesignTokens, type DesignTokens } from "@umituz/react-native-design-system";
|
|
13
|
-
import { AtomicText } from "@umituz/react-native-design-system";
|
|
14
9
|
import { ScreenLayout } from "@umituz/react-native-design-system";
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import { ContentValidationService } from "../../domain/services/ContentValidationService";
|
|
18
|
-
import { StyleCacheService } from "../../domain/services/StyleCacheService";
|
|
10
|
+
import { LegalScreenHeader } from "../components/LegalScreenHeader";
|
|
11
|
+
import { LegalDocumentsList } from "../components/LegalDocumentsList";
|
|
19
12
|
|
|
20
13
|
export interface LegalScreenProps {
|
|
21
|
-
/**
|
|
22
|
-
* Title of the screen
|
|
23
|
-
*/
|
|
24
14
|
title?: string;
|
|
25
|
-
/**
|
|
26
|
-
* Description/subtitle text
|
|
27
|
-
*/
|
|
28
15
|
description?: string;
|
|
29
|
-
/**
|
|
30
|
-
* Header text for documents section
|
|
31
|
-
*/
|
|
32
16
|
documentsHeader?: string;
|
|
33
|
-
/**
|
|
34
|
-
* Privacy Policy button text
|
|
35
|
-
*/
|
|
36
17
|
privacyTitle?: string;
|
|
37
|
-
/**
|
|
38
|
-
* Privacy Policy description
|
|
39
|
-
*/
|
|
40
18
|
privacyDescription?: string;
|
|
41
|
-
/**
|
|
42
|
-
* Terms of Service button text
|
|
43
|
-
*/
|
|
44
19
|
termsTitle?: string;
|
|
45
|
-
/**
|
|
46
|
-
* Terms of Service description
|
|
47
|
-
*/
|
|
48
20
|
termsDescription?: string;
|
|
49
|
-
/**
|
|
50
|
-
* EULA button text
|
|
51
|
-
*/
|
|
52
21
|
eulaTitle?: string;
|
|
53
|
-
/**
|
|
54
|
-
* EULA description
|
|
55
|
-
*/
|
|
56
22
|
eulaDescription?: string;
|
|
57
|
-
/**
|
|
58
|
-
* Callback when Privacy Policy is pressed
|
|
59
|
-
*/
|
|
60
23
|
onPrivacyPress?: () => void;
|
|
61
|
-
/**
|
|
62
|
-
* Callback when Terms of Service is pressed
|
|
63
|
-
*/
|
|
64
24
|
onTermsPress?: () => void;
|
|
65
|
-
/**
|
|
66
|
-
* Callback when EULA is pressed
|
|
67
|
-
* Icon name from Feather library (e.g., "shield", "file-text", "file") EULA URL
|
|
68
|
-
*/
|
|
69
25
|
onEulaPress?: () => void;
|
|
70
|
-
/**
|
|
71
|
-
* EULA URL (defaults to Apple's standard EULA)
|
|
72
|
-
*/
|
|
73
26
|
eulaUrl?: string;
|
|
74
|
-
/**
|
|
75
|
-
* Test ID for E2E testing
|
|
76
|
-
*/
|
|
77
27
|
testID?: string;
|
|
78
28
|
}
|
|
79
29
|
|
|
80
|
-
export const LegalScreen: React.FC<LegalScreenProps> = React.memo(({
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// Memoize styles to prevent recreation on every render
|
|
99
|
-
const styles = React.useMemo(() => {
|
|
100
|
-
const cacheKey = StyleCacheService.createTokenCacheKey(tokens);
|
|
101
|
-
return StyleCacheService.getCachedStyles(
|
|
102
|
-
'LegalScreen',
|
|
103
|
-
cacheKey,
|
|
104
|
-
() => createLegalScreenStyles(tokens)
|
|
105
|
-
);
|
|
106
|
-
}, [tokens]);
|
|
107
|
-
|
|
108
|
-
// Memoize EULA press handler to prevent child re-renders
|
|
109
|
-
const handleEulaPress = React.useCallback(async () => {
|
|
110
|
-
if (__DEV__) {
|
|
111
|
-
console.log('LegalScreen: EULA pressed', { eulaUrl });
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (onEulaPress) {
|
|
115
|
-
onEulaPress();
|
|
116
|
-
} else if (eulaUrl) {
|
|
117
|
-
try {
|
|
118
|
-
await UrlHandlerService.openUrl(eulaUrl);
|
|
119
|
-
} catch (error) {
|
|
120
|
-
if (__DEV__) {
|
|
121
|
-
console.error('LegalScreen: Error opening EULA URL', error);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}, [onEulaPress, eulaUrl]);
|
|
126
|
-
|
|
127
|
-
// Memoize conditional rendering to prevent unnecessary re-renders
|
|
128
|
-
const showHeader = React.useMemo(() => !!(title), [title]);
|
|
129
|
-
const showDescription = React.useMemo(() => !!(description), [description]);
|
|
130
|
-
const showSectionHeader = React.useMemo(() => !!(documentsHeader), [documentsHeader]);
|
|
131
|
-
const showPrivacy = React.useMemo(() =>
|
|
132
|
-
ContentValidationService.shouldShowLegalItem(onPrivacyPress, privacyTitle),
|
|
133
|
-
[onPrivacyPress, privacyTitle]
|
|
134
|
-
);
|
|
135
|
-
const showTerms = React.useMemo(() =>
|
|
136
|
-
ContentValidationService.shouldShowLegalItem(onTermsPress, termsTitle),
|
|
137
|
-
[onTermsPress, termsTitle]
|
|
138
|
-
);
|
|
139
|
-
const showEula = React.useMemo(() =>
|
|
140
|
-
!!((onEulaPress || eulaUrl) && eulaTitle),
|
|
141
|
-
[onEulaPress, eulaUrl, eulaTitle]
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
// Memoize header content
|
|
145
|
-
const headerContent = React.useMemo(() => {
|
|
146
|
-
if (!showHeader) return null;
|
|
147
|
-
|
|
148
|
-
return (
|
|
149
|
-
<View style={styles.header}>
|
|
150
|
-
<AtomicText type="headlineLarge" color="textPrimary">
|
|
151
|
-
{title}
|
|
152
|
-
</AtomicText>
|
|
153
|
-
{showDescription && (
|
|
154
|
-
<AtomicText
|
|
155
|
-
type="bodyMedium"
|
|
156
|
-
color="textSecondary"
|
|
157
|
-
style={styles.headerSubtitle}
|
|
158
|
-
>
|
|
159
|
-
{description}
|
|
160
|
-
</AtomicText>
|
|
161
|
-
)}
|
|
162
|
-
</View>
|
|
163
|
-
);
|
|
164
|
-
}, [showHeader, showDescription, styles.header, styles.headerSubtitle, title, description]);
|
|
30
|
+
export const LegalScreen: React.FC<LegalScreenProps> = React.memo((props) => {
|
|
31
|
+
const {
|
|
32
|
+
title,
|
|
33
|
+
description,
|
|
34
|
+
documentsHeader,
|
|
35
|
+
privacyTitle,
|
|
36
|
+
privacyDescription,
|
|
37
|
+
termsTitle,
|
|
38
|
+
termsDescription,
|
|
39
|
+
eulaTitle,
|
|
40
|
+
eulaDescription,
|
|
41
|
+
onPrivacyPress,
|
|
42
|
+
onTermsPress,
|
|
43
|
+
onEulaPress,
|
|
44
|
+
eulaUrl,
|
|
45
|
+
testID = "legal-screen",
|
|
46
|
+
} = props;
|
|
165
47
|
|
|
166
48
|
return (
|
|
167
49
|
<ScreenLayout testID={testID} hideScrollIndicator>
|
|
168
|
-
{
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
{
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
{/* Privacy Policy */}
|
|
184
|
-
{showPrivacy && (
|
|
185
|
-
<LegalItem
|
|
186
|
-
iconName="shield"
|
|
187
|
-
title={privacyTitle!}
|
|
188
|
-
description={privacyDescription}
|
|
189
|
-
onPress={onPrivacyPress}
|
|
190
|
-
testID="privacy-policy-item"
|
|
191
|
-
/>
|
|
192
|
-
)}
|
|
193
|
-
|
|
194
|
-
{/* Terms of Service */}
|
|
195
|
-
{showTerms && (
|
|
196
|
-
<LegalItem
|
|
197
|
-
iconName="document-text"
|
|
198
|
-
title={termsTitle!}
|
|
199
|
-
description={termsDescription}
|
|
200
|
-
onPress={onTermsPress}
|
|
201
|
-
testID="terms-of-service-item"
|
|
202
|
-
/>
|
|
203
|
-
)}
|
|
204
|
-
|
|
205
|
-
{/* EULA */}
|
|
206
|
-
{showEula && (
|
|
207
|
-
<LegalItem
|
|
208
|
-
iconName="document"
|
|
209
|
-
title={eulaTitle!}
|
|
210
|
-
description={eulaDescription}
|
|
211
|
-
onPress={handleEulaPress}
|
|
212
|
-
testID="eula-item"
|
|
213
|
-
/>
|
|
214
|
-
)}
|
|
215
|
-
</View>
|
|
50
|
+
<LegalScreenHeader title={title} description={description} />
|
|
51
|
+
|
|
52
|
+
<LegalDocumentsList
|
|
53
|
+
documentsHeader={documentsHeader}
|
|
54
|
+
privacyTitle={privacyTitle}
|
|
55
|
+
privacyDescription={privacyDescription}
|
|
56
|
+
termsTitle={termsTitle}
|
|
57
|
+
termsDescription={termsDescription}
|
|
58
|
+
eulaTitle={eulaTitle}
|
|
59
|
+
eulaDescription={eulaDescription}
|
|
60
|
+
onPrivacyPress={onPrivacyPress}
|
|
61
|
+
onTermsPress={onTermsPress}
|
|
62
|
+
onEulaPress={onEulaPress}
|
|
63
|
+
eulaUrl={eulaUrl}
|
|
64
|
+
/>
|
|
216
65
|
</ScreenLayout>
|
|
217
66
|
);
|
|
218
67
|
});
|
|
219
|
-
|
|
220
|
-
const createLegalScreenStyles = (tokens: DesignTokens) => {
|
|
221
|
-
return StyleSheet.create({
|
|
222
|
-
header: {
|
|
223
|
-
paddingBottom: tokens.spacing.lg,
|
|
224
|
-
paddingTop: tokens.spacing.md,
|
|
225
|
-
},
|
|
226
|
-
headerSubtitle: {
|
|
227
|
-
marginTop: tokens.spacing.xs,
|
|
228
|
-
},
|
|
229
|
-
section: {
|
|
230
|
-
marginTop: tokens.spacing.md,
|
|
231
|
-
},
|
|
232
|
-
sectionHeader: {
|
|
233
|
-
marginBottom: tokens.spacing.sm,
|
|
234
|
-
paddingHorizontal: tokens.spacing.md,
|
|
235
|
-
},
|
|
236
|
-
});
|
|
237
|
-
};
|