@umituz/react-native-settings 4.20.53 → 4.20.54
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/about/presentation/components/AboutSettingItem.tsx +39 -86
- package/src/domains/about/presentation/hooks/useAboutInfo.ts +39 -101
- package/src/domains/about/presentation/hooks/useAboutInfo.types.ts +32 -0
- package/src/domains/about/utils/AppInfoFactory.ts +19 -0
- package/src/domains/about/utils/index.ts +2 -0
- package/src/domains/legal/index.ts +1 -0
- package/src/domains/legal/presentation/screens/LegalContentScreen.tsx +140 -0
- package/src/domains/legal/presentation/screens/PrivacyPolicyScreen.tsx +17 -155
- package/src/domains/legal/presentation/screens/TermsOfServiceScreen.tsx +17 -155
- package/src/presentation/components/SettingsItemCard.tsx +2 -2
- package/src/presentation/navigation/SettingsStackNavigator.tsx +50 -129
- package/src/presentation/navigation/components/wrappers/AboutScreenWrapper.tsx +13 -0
- package/src/presentation/navigation/components/wrappers/LegalScreenWrapper.tsx +50 -0
- package/src/presentation/navigation/components/wrappers/SettingsScreenWrapper.tsx +32 -0
- package/src/presentation/navigation/components/wrappers/index.ts +9 -0
- package/src/presentation/navigation/utils/index.ts +5 -0
- package/src/presentation/navigation/utils/navigationScreenOptions.ts +56 -0
- package/src/presentation/navigation/utils/navigationTranslations.ts +46 -0
- package/src/presentation/screens/components/SettingsHeader.tsx +1 -1
- package/src/presentation/screens/types/BaseTypes.ts +12 -0
- package/src/presentation/screens/types/ContentConfig.ts +82 -0
- package/src/presentation/screens/types/SettingsConfig.ts +6 -4
- package/src/presentation/screens/types/UserFeatureConfig.ts +137 -0
- package/src/presentation/screens/types/index.ts +10 -8
- package/src/presentation/screens/types/FeatureConfig.ts +0 -263
|
@@ -2,46 +2,17 @@
|
|
|
2
2
|
* Privacy Policy Screen Component
|
|
3
3
|
* Display Privacy Policy content
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
5
|
import React from "react";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { useAppDesignTokens } from "@umituz/react-native-design-system";
|
|
10
|
-
import { AtomicText, AtomicButton } from "@umituz/react-native-design-system";
|
|
11
|
-
import { UrlHandlerService } from "../../domain/services/UrlHandlerService";
|
|
12
|
-
import { ContentValidationService } from "../../domain/services/ContentValidationService";
|
|
13
|
-
import { StyleCacheService } from "../../domain/services/StyleCacheService";
|
|
6
|
+
import { StyleSheet } from "react-native";
|
|
7
|
+
import { LegalContentScreen } from "./LegalContentScreen";
|
|
14
8
|
|
|
15
9
|
export interface PrivacyPolicyScreenProps {
|
|
16
|
-
/**
|
|
17
|
-
* Privacy Policy content (HTML or plain text)
|
|
18
|
-
* Either content or url must be provided
|
|
19
|
-
*/
|
|
20
10
|
content?: string;
|
|
21
|
-
/**
|
|
22
|
-
* Privacy Policy URL (if content is not provided, will open URL)
|
|
23
|
-
* Either content or url must be provided
|
|
24
|
-
*/
|
|
25
11
|
url?: string;
|
|
26
|
-
/**
|
|
27
|
-
* Custom title
|
|
28
|
-
*/
|
|
29
12
|
title: string;
|
|
30
|
-
/**
|
|
31
|
-
* Text for viewing online button (required when url is provided)
|
|
32
|
-
*/
|
|
33
13
|
viewOnlineText?: string;
|
|
34
|
-
/**
|
|
35
|
-
* Text for open button (required when url is provided)
|
|
36
|
-
*/
|
|
37
14
|
openText?: string;
|
|
38
|
-
/**
|
|
39
|
-
* Callback when URL is pressed (if content is not provided)
|
|
40
|
-
*/
|
|
41
15
|
onUrlPress?: () => void;
|
|
42
|
-
/**
|
|
43
|
-
* Test ID for E2E testing
|
|
44
|
-
*/
|
|
45
16
|
testID?: string;
|
|
46
17
|
}
|
|
47
18
|
|
|
@@ -54,119 +25,7 @@ export const PrivacyPolicyScreen: React.FC<PrivacyPolicyScreenProps> = React.mem
|
|
|
54
25
|
onUrlPress,
|
|
55
26
|
testID = "privacy-policy-screen",
|
|
56
27
|
}) => {
|
|
57
|
-
const
|
|
58
|
-
const insets = useSafeAreaInsets();
|
|
59
|
-
|
|
60
|
-
// Validate required props
|
|
61
|
-
React.useEffect(() => {
|
|
62
|
-
ContentValidationService.validateScreenContent(
|
|
63
|
-
content,
|
|
64
|
-
url,
|
|
65
|
-
title,
|
|
66
|
-
viewOnlineText,
|
|
67
|
-
openText,
|
|
68
|
-
'PrivacyPolicyScreen'
|
|
69
|
-
);
|
|
70
|
-
}, [content, url, title, viewOnlineText, openText]);
|
|
71
|
-
|
|
72
|
-
// Use cached styles
|
|
73
|
-
const styles = React.useMemo(() => {
|
|
74
|
-
const cacheKey = StyleCacheService.createTokenCacheKey(tokens);
|
|
75
|
-
return StyleCacheService.getCachedStyles(
|
|
76
|
-
'PrivacyPolicyScreen',
|
|
77
|
-
cacheKey,
|
|
78
|
-
() => createPrivacyPolicyStyles(tokens)
|
|
79
|
-
);
|
|
80
|
-
}, [tokens]);
|
|
81
|
-
|
|
82
|
-
// Memoize URL press handler to prevent child re-renders
|
|
83
|
-
const handleUrlPress = React.useCallback(async () => {
|
|
84
|
-
if (onUrlPress) {
|
|
85
|
-
onUrlPress();
|
|
86
|
-
} else if (url) {
|
|
87
|
-
try {
|
|
88
|
-
await UrlHandlerService.openUrl(url);
|
|
89
|
-
} catch {
|
|
90
|
-
// Silent error handling
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}, [onUrlPress, url]);
|
|
94
|
-
|
|
95
|
-
// Memoize container style to prevent object creation
|
|
96
|
-
const containerStyle = React.useMemo(() => [
|
|
97
|
-
styles.container,
|
|
98
|
-
{
|
|
99
|
-
backgroundColor: tokens.colors.backgroundPrimary,
|
|
100
|
-
paddingTop: insets.top,
|
|
101
|
-
},
|
|
102
|
-
], [styles.container, tokens.colors.backgroundPrimary, insets.top]);
|
|
103
|
-
|
|
104
|
-
// Memoize conditional rendering
|
|
105
|
-
const showContent = React.useMemo(() => !!(content), [content]);
|
|
106
|
-
const showUrlSection = React.useMemo(() =>
|
|
107
|
-
ContentValidationService.shouldShowUrlSection(url, onUrlPress),
|
|
108
|
-
[url, onUrlPress]
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
// Memoize content section
|
|
112
|
-
const contentSection = React.useMemo(() => {
|
|
113
|
-
if (showContent) {
|
|
114
|
-
return (
|
|
115
|
-
<AtomicText type="bodyMedium" color="onSurface" style={styles.text}>
|
|
116
|
-
{content}
|
|
117
|
-
</AtomicText>
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (showUrlSection) {
|
|
122
|
-
return (
|
|
123
|
-
<View style={styles.urlContainer}>
|
|
124
|
-
<AtomicText
|
|
125
|
-
type="bodyMedium"
|
|
126
|
-
color="secondary"
|
|
127
|
-
style={styles.urlText}
|
|
128
|
-
>
|
|
129
|
-
{viewOnlineText}
|
|
130
|
-
</AtomicText>
|
|
131
|
-
<AtomicButton
|
|
132
|
-
variant="primary"
|
|
133
|
-
onPress={handleUrlPress}
|
|
134
|
-
fullWidth
|
|
135
|
-
style={styles.urlButton}
|
|
136
|
-
>
|
|
137
|
-
{openText}
|
|
138
|
-
</AtomicButton>
|
|
139
|
-
</View>
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return null;
|
|
144
|
-
}, [showContent, showUrlSection, styles.text, styles.urlContainer, styles.urlText, styles.urlButton, content, viewOnlineText, openText, handleUrlPress]);
|
|
145
|
-
|
|
146
|
-
return (
|
|
147
|
-
<View style={containerStyle} testID={testID}>
|
|
148
|
-
<ScrollView
|
|
149
|
-
contentContainerStyle={styles.scrollContent}
|
|
150
|
-
showsVerticalScrollIndicator={false}
|
|
151
|
-
>
|
|
152
|
-
<View style={styles.content}>
|
|
153
|
-
<AtomicText
|
|
154
|
-
type="headlineLarge"
|
|
155
|
-
color="primary"
|
|
156
|
-
style={styles.title}
|
|
157
|
-
>
|
|
158
|
-
{title}
|
|
159
|
-
</AtomicText>
|
|
160
|
-
|
|
161
|
-
{contentSection}
|
|
162
|
-
</View>
|
|
163
|
-
</ScrollView>
|
|
164
|
-
</View>
|
|
165
|
-
);
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
const createPrivacyPolicyStyles = (tokens: any) => {
|
|
169
|
-
return StyleSheet.create({
|
|
28
|
+
const createStyles = (tokens: any) => StyleSheet.create({
|
|
170
29
|
container: {
|
|
171
30
|
flex: 1,
|
|
172
31
|
},
|
|
@@ -197,15 +56,18 @@ const createPrivacyPolicyStyles = (tokens: any) => {
|
|
|
197
56
|
marginTop: 8,
|
|
198
57
|
},
|
|
199
58
|
});
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
59
|
|
|
60
|
+
return (
|
|
61
|
+
<LegalContentScreen
|
|
62
|
+
content={content}
|
|
63
|
+
url={url}
|
|
64
|
+
title={title}
|
|
65
|
+
viewOnlineText={viewOnlineText}
|
|
66
|
+
openText={openText}
|
|
67
|
+
onUrlPress={onUrlPress}
|
|
68
|
+
testID={testID}
|
|
69
|
+
styleCacheKey="PrivacyPolicyScreen"
|
|
70
|
+
createStyles={createStyles}
|
|
71
|
+
/>
|
|
72
|
+
);
|
|
73
|
+
});
|
|
@@ -2,46 +2,17 @@
|
|
|
2
2
|
* Terms of Service Screen Component
|
|
3
3
|
* Display Terms of Service content
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
5
|
import React from "react";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { useAppDesignTokens } from "@umituz/react-native-design-system";
|
|
10
|
-
import { AtomicText, AtomicButton } from "@umituz/react-native-design-system";
|
|
11
|
-
import { UrlHandlerService } from "../../domain/services/UrlHandlerService";
|
|
12
|
-
import { ContentValidationService } from "../../domain/services/ContentValidationService";
|
|
13
|
-
import { StyleCacheService } from "../../domain/services/StyleCacheService";
|
|
6
|
+
import { StyleSheet } from "react-native";
|
|
7
|
+
import { LegalContentScreen } from "./LegalContentScreen";
|
|
14
8
|
|
|
15
9
|
export interface TermsOfServiceScreenProps {
|
|
16
|
-
/**
|
|
17
|
-
* Terms of Service content (HTML or plain text)
|
|
18
|
-
* Either content or url must be provided
|
|
19
|
-
*/
|
|
20
10
|
content?: string;
|
|
21
|
-
/**
|
|
22
|
-
* Terms of Service URL (if content is not provided, will open URL)
|
|
23
|
-
* Either content or url must be provided
|
|
24
|
-
*/
|
|
25
11
|
url?: string;
|
|
26
|
-
/**
|
|
27
|
-
* Custom title
|
|
28
|
-
*/
|
|
29
12
|
title: string;
|
|
30
|
-
/**
|
|
31
|
-
* Text for viewing online button (required when url is provided)
|
|
32
|
-
*/
|
|
33
13
|
viewOnlineText?: string;
|
|
34
|
-
/**
|
|
35
|
-
* Text for open button (required when url is provided)
|
|
36
|
-
*/
|
|
37
14
|
openText?: string;
|
|
38
|
-
/**
|
|
39
|
-
* Callback when URL is pressed (if content is not provided)
|
|
40
|
-
*/
|
|
41
15
|
onUrlPress?: () => void;
|
|
42
|
-
/**
|
|
43
|
-
* Test ID for E2E testing
|
|
44
|
-
*/
|
|
45
16
|
testID?: string;
|
|
46
17
|
}
|
|
47
18
|
|
|
@@ -54,119 +25,7 @@ export const TermsOfServiceScreen: React.FC<TermsOfServiceScreenProps> = React.m
|
|
|
54
25
|
onUrlPress,
|
|
55
26
|
testID = "terms-of-service-screen",
|
|
56
27
|
}) => {
|
|
57
|
-
const
|
|
58
|
-
const insets = useSafeAreaInsets();
|
|
59
|
-
|
|
60
|
-
// Validate required props
|
|
61
|
-
React.useEffect(() => {
|
|
62
|
-
ContentValidationService.validateScreenContent(
|
|
63
|
-
content,
|
|
64
|
-
url,
|
|
65
|
-
title,
|
|
66
|
-
viewOnlineText,
|
|
67
|
-
openText,
|
|
68
|
-
'TermsOfServiceScreen'
|
|
69
|
-
);
|
|
70
|
-
}, [content, url, title, viewOnlineText, openText]);
|
|
71
|
-
|
|
72
|
-
// Use cached styles
|
|
73
|
-
const styles = React.useMemo(() => {
|
|
74
|
-
const cacheKey = StyleCacheService.createTokenCacheKey(tokens);
|
|
75
|
-
return StyleCacheService.getCachedStyles(
|
|
76
|
-
'TermsOfServiceScreen',
|
|
77
|
-
cacheKey,
|
|
78
|
-
() => createTermsOfServiceStyles(tokens)
|
|
79
|
-
);
|
|
80
|
-
}, [tokens]);
|
|
81
|
-
|
|
82
|
-
// Memoize URL press handler to prevent child re-renders
|
|
83
|
-
const handleUrlPress = React.useCallback(async () => {
|
|
84
|
-
if (onUrlPress) {
|
|
85
|
-
onUrlPress();
|
|
86
|
-
} else if (url) {
|
|
87
|
-
try {
|
|
88
|
-
await UrlHandlerService.openUrl(url);
|
|
89
|
-
} catch {
|
|
90
|
-
// Silent error handling
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}, [onUrlPress, url]);
|
|
94
|
-
|
|
95
|
-
// Memoize container style to prevent object creation
|
|
96
|
-
const containerStyle = React.useMemo(() => [
|
|
97
|
-
styles.container,
|
|
98
|
-
{
|
|
99
|
-
backgroundColor: tokens.colors.backgroundPrimary,
|
|
100
|
-
paddingTop: insets.top,
|
|
101
|
-
},
|
|
102
|
-
], [styles.container, tokens.colors.backgroundPrimary, insets.top]);
|
|
103
|
-
|
|
104
|
-
// Memoize conditional rendering
|
|
105
|
-
const showContent = React.useMemo(() => !!(content), [content]);
|
|
106
|
-
const showUrlSection = React.useMemo(() =>
|
|
107
|
-
ContentValidationService.shouldShowUrlSection(url, onUrlPress),
|
|
108
|
-
[url, onUrlPress]
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
// Memoize content section
|
|
112
|
-
const contentSection = React.useMemo(() => {
|
|
113
|
-
if (showContent) {
|
|
114
|
-
return (
|
|
115
|
-
<AtomicText type="bodyMedium" color="onSurface" style={styles.text}>
|
|
116
|
-
{content}
|
|
117
|
-
</AtomicText>
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (showUrlSection) {
|
|
122
|
-
return (
|
|
123
|
-
<View style={styles.urlContainer}>
|
|
124
|
-
<AtomicText
|
|
125
|
-
type="bodyMedium"
|
|
126
|
-
color="secondary"
|
|
127
|
-
style={styles.urlText}
|
|
128
|
-
>
|
|
129
|
-
{viewOnlineText}
|
|
130
|
-
</AtomicText>
|
|
131
|
-
<AtomicButton
|
|
132
|
-
variant="primary"
|
|
133
|
-
onPress={handleUrlPress}
|
|
134
|
-
fullWidth
|
|
135
|
-
style={styles.urlButton}
|
|
136
|
-
>
|
|
137
|
-
{openText}
|
|
138
|
-
</AtomicButton>
|
|
139
|
-
</View>
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return null;
|
|
144
|
-
}, [showContent, showUrlSection, styles.text, styles.urlContainer, styles.urlText, styles.urlButton, content, viewOnlineText, openText, handleUrlPress]);
|
|
145
|
-
|
|
146
|
-
return (
|
|
147
|
-
<View style={containerStyle} testID={testID}>
|
|
148
|
-
<ScrollView
|
|
149
|
-
contentContainerStyle={styles.scrollContent}
|
|
150
|
-
showsVerticalScrollIndicator={false}
|
|
151
|
-
>
|
|
152
|
-
<View style={styles.content}>
|
|
153
|
-
<AtomicText
|
|
154
|
-
type="headlineLarge"
|
|
155
|
-
color="primary"
|
|
156
|
-
style={styles.title}
|
|
157
|
-
>
|
|
158
|
-
{title}
|
|
159
|
-
</AtomicText>
|
|
160
|
-
|
|
161
|
-
{contentSection}
|
|
162
|
-
</View>
|
|
163
|
-
</ScrollView>
|
|
164
|
-
</View>
|
|
165
|
-
);
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
const createTermsOfServiceStyles = (tokens: any) => {
|
|
169
|
-
return StyleSheet.create({
|
|
28
|
+
const createStyles = (tokens: any) => StyleSheet.create({
|
|
170
29
|
container: {
|
|
171
30
|
flex: 1,
|
|
172
31
|
},
|
|
@@ -197,15 +56,18 @@ const createTermsOfServiceStyles = (tokens: any) => {
|
|
|
197
56
|
marginTop: 8,
|
|
198
57
|
},
|
|
199
58
|
});
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
59
|
|
|
60
|
+
return (
|
|
61
|
+
<LegalContentScreen
|
|
62
|
+
content={content}
|
|
63
|
+
url={url}
|
|
64
|
+
title={title}
|
|
65
|
+
viewOnlineText={viewOnlineText}
|
|
66
|
+
openText={openText}
|
|
67
|
+
onUrlPress={onUrlPress}
|
|
68
|
+
testID={testID}
|
|
69
|
+
styleCacheKey="TermsOfServiceScreen"
|
|
70
|
+
createStyles={createStyles}
|
|
71
|
+
/>
|
|
72
|
+
);
|
|
73
|
+
});
|
|
@@ -92,7 +92,7 @@ export const SettingsItemCard: React.FC<SettingsItemCardProps> = ({
|
|
|
92
92
|
|
|
93
93
|
const renderContent = () => (
|
|
94
94
|
<View style={styles.content}>
|
|
95
|
-
<View style={[styles.iconContainer, { backgroundColor: defaultIconBg, borderRadius: tokens.
|
|
95
|
+
<View style={[styles.iconContainer, { backgroundColor: defaultIconBg, borderRadius: tokens.borderRadius.md }]}>
|
|
96
96
|
<AtomicIcon name={icon} size="lg" customColor={defaultIconColor} />
|
|
97
97
|
</View>
|
|
98
98
|
<View style={styles.textContainer}>
|
|
@@ -120,7 +120,7 @@ export const SettingsItemCard: React.FC<SettingsItemCardProps> = ({
|
|
|
120
120
|
styles.sectionContainer,
|
|
121
121
|
{
|
|
122
122
|
backgroundColor: colors.surface,
|
|
123
|
-
borderRadius: tokens.
|
|
123
|
+
borderRadius: tokens.borderRadius.lg,
|
|
124
124
|
},
|
|
125
125
|
containerStyle,
|
|
126
126
|
]}
|
|
@@ -5,17 +5,31 @@
|
|
|
5
5
|
* Receives appInfo and legalUrls from app.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import React
|
|
8
|
+
import React from "react";
|
|
9
9
|
import { createStackNavigator } from "@react-navigation/stack";
|
|
10
|
-
import { useAppDesignTokens } from "@umituz/react-native-design-system";
|
|
11
10
|
import { useLocalization, LanguageSelectionScreen } from "@umituz/react-native-localization";
|
|
12
11
|
import { NotificationSettingsScreen } from "@umituz/react-native-notifications";
|
|
13
|
-
import {
|
|
12
|
+
import { useAppDesignTokens } from "@umituz/react-native-design-system";
|
|
14
13
|
import { AppearanceScreen } from "../screens/AppearanceScreen";
|
|
15
|
-
import { LegalScreen } from "../../domains/legal";
|
|
16
|
-
import { AboutScreen } from "../../domains/about";
|
|
17
14
|
import { FAQScreen } from "../../domains/faqs";
|
|
18
15
|
import { useNavigationHandlers } from "./hooks";
|
|
16
|
+
import {
|
|
17
|
+
SettingsScreenWrapper,
|
|
18
|
+
LegalScreenWrapper,
|
|
19
|
+
AboutScreenWrapper,
|
|
20
|
+
} from "./components/wrappers";
|
|
21
|
+
import {
|
|
22
|
+
createNotificationTranslations,
|
|
23
|
+
createQuietHoursTranslations,
|
|
24
|
+
createLegalScreenProps,
|
|
25
|
+
createScreenOptions,
|
|
26
|
+
createAppearanceScreenOptions,
|
|
27
|
+
createAboutScreenOptions,
|
|
28
|
+
createLegalScreenOptions,
|
|
29
|
+
createNotificationsScreenOptions,
|
|
30
|
+
createFAQScreenOptions,
|
|
31
|
+
createLanguageSelectionScreenOptions,
|
|
32
|
+
} from "./utils";
|
|
19
33
|
import type { SettingsStackParamList, SettingsStackNavigatorProps } from "./types";
|
|
20
34
|
|
|
21
35
|
const Stack = createStackNavigator<SettingsStackParamList>();
|
|
@@ -36,138 +50,55 @@ export const SettingsStackNavigator: React.FC<SettingsStackNavigatorProps> = ({
|
|
|
36
50
|
const { handlePrivacyPress, handleTermsPress, handleEulaPress, aboutConfig } =
|
|
37
51
|
useNavigationHandlers(appInfo, legalUrls);
|
|
38
52
|
|
|
39
|
-
const screenOptions = useMemo(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
},
|
|
46
|
-
headerTitleStyle: {
|
|
47
|
-
fontSize: 18,
|
|
48
|
-
fontWeight: "600" as const,
|
|
49
|
-
color: tokens.colors.textPrimary,
|
|
50
|
-
},
|
|
51
|
-
headerTintColor: tokens.colors.textPrimary,
|
|
52
|
-
}),
|
|
53
|
-
[tokens]
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
const SettingsScreenWrapper = useMemo(() => {
|
|
57
|
-
const Wrapper = () => (
|
|
58
|
-
<SettingsScreen
|
|
59
|
-
config={config}
|
|
60
|
-
appVersion={appInfo.version}
|
|
61
|
-
showUserProfile={showUserProfile}
|
|
62
|
-
userProfile={userProfile}
|
|
63
|
-
devSettings={devSettings}
|
|
64
|
-
customSections={customSections}
|
|
65
|
-
/>
|
|
66
|
-
);
|
|
67
|
-
Wrapper.displayName = "SettingsScreenWrapper";
|
|
68
|
-
return Wrapper;
|
|
69
|
-
}, [config, appInfo.version, showUserProfile, userProfile, devSettings, customSections]);
|
|
70
|
-
|
|
71
|
-
const notificationTranslations = useMemo(
|
|
72
|
-
() => ({
|
|
73
|
-
screenTitle: t("settings.notifications.title"),
|
|
74
|
-
masterToggleTitle: t("settings.notifications.masterToggleTitle"),
|
|
75
|
-
masterToggleDescription: t("settings.notifications.masterToggleDescription"),
|
|
76
|
-
soundTitle: t("settings.notifications.soundTitle"),
|
|
77
|
-
soundDescription: t("settings.notifications.soundDescription"),
|
|
78
|
-
vibrationTitle: t("settings.notifications.vibrationTitle"),
|
|
79
|
-
vibrationDescription: t("settings.notifications.vibrationDescription"),
|
|
80
|
-
remindersTitle: t("settings.notifications.remindersTitle"),
|
|
81
|
-
remindersDescription: t("settings.notifications.remindersDescription"),
|
|
82
|
-
quietHoursTitle: t("settings.notifications.quietHoursTitle"),
|
|
83
|
-
quietHoursDescription: t("settings.notifications.quietHoursDescription"),
|
|
84
|
-
}),
|
|
85
|
-
[t]
|
|
53
|
+
const screenOptions = React.useMemo(() => createScreenOptions(tokens), [tokens]);
|
|
54
|
+
const notificationTranslations = React.useMemo(() => createNotificationTranslations(t), [t]);
|
|
55
|
+
const quietHoursTranslations = React.useMemo(() => createQuietHoursTranslations(t), [t]);
|
|
56
|
+
const legalScreenProps = React.useMemo(
|
|
57
|
+
() => createLegalScreenProps(t, handlePrivacyPress, handleTermsPress, handleEulaPress),
|
|
58
|
+
[t, handlePrivacyPress, handleTermsPress, handleEulaPress]
|
|
86
59
|
);
|
|
87
60
|
|
|
88
|
-
const quietHoursTranslations = useMemo(
|
|
89
|
-
() => ({
|
|
90
|
-
title: t("settings.notifications.quietHours.title"),
|
|
91
|
-
description: t("settings.notifications.quietHours.description"),
|
|
92
|
-
startTimeLabel: t("settings.notifications.quietHours.startTimeLabel"),
|
|
93
|
-
endTimeLabel: t("settings.notifications.quietHours.endTimeLabel"),
|
|
94
|
-
enabledLabel: t("settings.notifications.quietHours.enabledLabel"),
|
|
95
|
-
}),
|
|
96
|
-
[t]
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
const LegalScreenWrapper = useMemo(() => {
|
|
100
|
-
const Wrapper = () => (
|
|
101
|
-
<LegalScreen
|
|
102
|
-
title={t("settings.legal.title")}
|
|
103
|
-
description={t("settings.legal.description")}
|
|
104
|
-
documentsHeader={t("settings.legal.documentsHeader")}
|
|
105
|
-
privacyTitle={t("settings.legal.privacyTitle")}
|
|
106
|
-
privacyDescription={t("settings.legal.privacyDescription")}
|
|
107
|
-
termsTitle={t("settings.legal.termsTitle")}
|
|
108
|
-
termsDescription={t("settings.legal.termsDescription")}
|
|
109
|
-
eulaTitle={t("settings.legal.eulaTitle")}
|
|
110
|
-
eulaDescription={t("settings.legal.eulaDescription")}
|
|
111
|
-
onPrivacyPress={handlePrivacyPress}
|
|
112
|
-
onTermsPress={handleTermsPress}
|
|
113
|
-
onEulaPress={handleEulaPress}
|
|
114
|
-
/>
|
|
115
|
-
);
|
|
116
|
-
Wrapper.displayName = "LegalScreenWrapper";
|
|
117
|
-
return Wrapper;
|
|
118
|
-
}, [t, handlePrivacyPress, handleTermsPress, handleEulaPress]);
|
|
119
|
-
|
|
120
|
-
const AboutScreenWrapper = useMemo(() => {
|
|
121
|
-
const Wrapper = () => <AboutScreen config={aboutConfig} />;
|
|
122
|
-
Wrapper.displayName = "AboutScreenWrapper";
|
|
123
|
-
return Wrapper;
|
|
124
|
-
}, [aboutConfig]);
|
|
125
|
-
|
|
126
61
|
return (
|
|
127
62
|
<Stack.Navigator screenOptions={screenOptions}>
|
|
128
63
|
<Stack.Screen
|
|
129
64
|
name="SettingsMain"
|
|
130
|
-
component={SettingsScreenWrapper}
|
|
131
65
|
options={{ headerShown: false }}
|
|
132
|
-
|
|
66
|
+
>
|
|
67
|
+
{() => (
|
|
68
|
+
<SettingsScreenWrapper
|
|
69
|
+
config={config}
|
|
70
|
+
appVersion={appInfo.version}
|
|
71
|
+
showUserProfile={showUserProfile}
|
|
72
|
+
userProfile={userProfile}
|
|
73
|
+
devSettings={devSettings}
|
|
74
|
+
customSections={customSections}
|
|
75
|
+
/>
|
|
76
|
+
)}
|
|
77
|
+
</Stack.Screen>
|
|
133
78
|
|
|
134
79
|
<Stack.Screen
|
|
135
80
|
name="Appearance"
|
|
136
81
|
component={AppearanceScreen}
|
|
137
|
-
options={
|
|
138
|
-
headerShown: true,
|
|
139
|
-
headerTitle: t("settings.appearance.title"),
|
|
140
|
-
headerTitleAlign: "center",
|
|
141
|
-
}}
|
|
82
|
+
options={createAppearanceScreenOptions(t)}
|
|
142
83
|
/>
|
|
143
84
|
|
|
144
85
|
<Stack.Screen
|
|
145
86
|
name="About"
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
headerTitleAlign: "center",
|
|
151
|
-
}}
|
|
152
|
-
/>
|
|
87
|
+
options={createAboutScreenOptions(t)}
|
|
88
|
+
>
|
|
89
|
+
{() => <AboutScreenWrapper config={aboutConfig} />}
|
|
90
|
+
</Stack.Screen>
|
|
153
91
|
|
|
154
92
|
<Stack.Screen
|
|
155
93
|
name="Legal"
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
headerTitleAlign: "center",
|
|
161
|
-
}}
|
|
162
|
-
/>
|
|
94
|
+
options={createLegalScreenOptions(t)}
|
|
95
|
+
>
|
|
96
|
+
{() => <LegalScreenWrapper {...legalScreenProps} />}
|
|
97
|
+
</Stack.Screen>
|
|
163
98
|
|
|
164
99
|
<Stack.Screen
|
|
165
100
|
name="Notifications"
|
|
166
|
-
options={
|
|
167
|
-
headerShown: true,
|
|
168
|
-
headerTitle: t("settings.notifications.title"),
|
|
169
|
-
headerTitleAlign: "center",
|
|
170
|
-
}}
|
|
101
|
+
options={createNotificationsScreenOptions(t)}
|
|
171
102
|
>
|
|
172
103
|
{() => (
|
|
173
104
|
<NotificationSettingsScreen
|
|
@@ -178,14 +109,7 @@ export const SettingsStackNavigator: React.FC<SettingsStackNavigatorProps> = ({
|
|
|
178
109
|
</Stack.Screen>
|
|
179
110
|
|
|
180
111
|
{faqData && faqData.categories.length > 0 && (
|
|
181
|
-
<Stack.Screen
|
|
182
|
-
name="FAQ"
|
|
183
|
-
options={{
|
|
184
|
-
headerShown: true,
|
|
185
|
-
headerTitle: t("settings.faqs.title"),
|
|
186
|
-
headerTitleAlign: "center",
|
|
187
|
-
}}
|
|
188
|
-
>
|
|
112
|
+
<Stack.Screen name="FAQ" options={createFAQScreenOptions(t)}>
|
|
189
113
|
{() => (
|
|
190
114
|
<FAQScreen
|
|
191
115
|
categories={faqData.categories}
|
|
@@ -216,13 +140,10 @@ export const SettingsStackNavigator: React.FC<SettingsStackNavigatorProps> = ({
|
|
|
216
140
|
/>
|
|
217
141
|
) : null
|
|
218
142
|
)}
|
|
143
|
+
|
|
219
144
|
<Stack.Screen
|
|
220
145
|
name="LanguageSelection"
|
|
221
|
-
options={
|
|
222
|
-
headerShown: true,
|
|
223
|
-
headerTitle: t("settings.language.title"),
|
|
224
|
-
headerTitleAlign: "center",
|
|
225
|
-
}}
|
|
146
|
+
options={createLanguageSelectionScreenOptions(t)}
|
|
226
147
|
>
|
|
227
148
|
{() => (
|
|
228
149
|
<LanguageSelectionScreen
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* About Screen Wrapper Component
|
|
3
|
+
*/
|
|
4
|
+
import React from "react";
|
|
5
|
+
import { AboutScreen } from "../../../../domains/about";
|
|
6
|
+
|
|
7
|
+
export interface AboutScreenWrapperProps {
|
|
8
|
+
config: any;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const AboutScreenWrapper: React.FC<AboutScreenWrapperProps> = ({
|
|
12
|
+
config,
|
|
13
|
+
}) => <AboutScreen config={config} />;
|