@umituz/react-native-settings 1.3.7 → 1.4.0
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": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Settings management for React Native apps - user preferences, theme, language, notifications",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -33,7 +33,6 @@
|
|
|
33
33
|
"@umituz/react-native-design-system": "latest",
|
|
34
34
|
"@umituz/react-native-design-system-theme": "latest",
|
|
35
35
|
"@umituz/react-native-localization": "latest",
|
|
36
|
-
"react-native-paper": "^5.12.3",
|
|
37
36
|
"expo-linear-gradient": "~14.0.0"
|
|
38
37
|
},
|
|
39
38
|
"devDependencies": {
|
|
@@ -12,8 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import React from 'react';
|
|
15
|
-
import { View, StyleSheet } from 'react-native';
|
|
16
|
-
import { List } from 'react-native-paper';
|
|
15
|
+
import { View, StyleSheet, TouchableOpacity } from 'react-native';
|
|
17
16
|
import { LinearGradient } from 'expo-linear-gradient';
|
|
18
17
|
import { AtomicText, AtomicIcon } from '@umituz/react-native-design-system';
|
|
19
18
|
import { useAppDesignTokens } from '@umituz/react-native-design-system-theme';
|
|
@@ -63,114 +62,198 @@ export const SettingItem: React.FC<SettingItemProps> = ({
|
|
|
63
62
|
? (iconGradient as unknown as readonly [string, string, ...string[]])
|
|
64
63
|
: [tokens.colors.surface, tokens.colors.surface] as const;
|
|
65
64
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
65
|
+
if (onPress) {
|
|
66
|
+
return (
|
|
67
|
+
<TouchableOpacity
|
|
68
|
+
onPress={onPress}
|
|
69
|
+
disabled={disabled}
|
|
70
|
+
activeOpacity={0.7}
|
|
71
|
+
style={[styles.listItem, disabled && styles.disabled]}
|
|
72
|
+
testID={testID}
|
|
74
73
|
>
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (value) {
|
|
87
|
-
return (
|
|
88
|
-
<View style={styles.rightContainer}>
|
|
89
|
-
<AtomicText type="bodyMedium" color="secondary" style={styles.value} numberOfLines={2}>
|
|
90
|
-
{value}
|
|
91
|
-
</AtomicText>
|
|
74
|
+
{/* Left: Gradient Icon */}
|
|
75
|
+
<View style={styles.leftContainer}>
|
|
76
|
+
<LinearGradient
|
|
77
|
+
colors={gradientColors}
|
|
78
|
+
start={{ x: 0, y: 0 }}
|
|
79
|
+
end={{ x: 1, y: 1 }}
|
|
80
|
+
style={styles.iconContainer}
|
|
81
|
+
>
|
|
82
|
+
<AtomicIcon name={icon} size="md" customColor="#FFFFFF" />
|
|
83
|
+
</LinearGradient>
|
|
92
84
|
</View>
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
85
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
86
|
+
{/* Center: Title and Description */}
|
|
87
|
+
<View style={styles.contentContainer}>
|
|
88
|
+
<AtomicText
|
|
89
|
+
type="bodyLarge"
|
|
90
|
+
color={disabled ? "textDisabled" : "onSurface"}
|
|
91
|
+
style={styles.title}
|
|
92
|
+
numberOfLines={2}
|
|
93
|
+
ellipsizeMode="tail"
|
|
94
|
+
>
|
|
95
|
+
{title}
|
|
96
|
+
</AtomicText>
|
|
97
|
+
{description && (
|
|
98
|
+
<AtomicText
|
|
99
|
+
type="bodySmall"
|
|
100
|
+
color="textSecondary"
|
|
101
|
+
style={styles.description}
|
|
102
|
+
numberOfLines={2}
|
|
103
|
+
ellipsizeMode="tail"
|
|
104
|
+
>
|
|
105
|
+
{description}
|
|
106
|
+
</AtomicText>
|
|
107
|
+
)}
|
|
101
108
|
</View>
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
109
|
|
|
105
|
-
|
|
106
|
-
|
|
110
|
+
{/* Right: Value, Chevron, or Custom Element */}
|
|
111
|
+
{rightElement ? (
|
|
112
|
+
<View style={styles.rightContainer}>{rightElement}</View>
|
|
113
|
+
) : value ? (
|
|
114
|
+
<View style={styles.rightContainer}>
|
|
115
|
+
<AtomicText
|
|
116
|
+
type="bodyMedium"
|
|
117
|
+
color="textSecondary"
|
|
118
|
+
style={styles.value}
|
|
119
|
+
numberOfLines={2}
|
|
120
|
+
textAlign="right"
|
|
121
|
+
>
|
|
122
|
+
{value}
|
|
123
|
+
</AtomicText>
|
|
124
|
+
</View>
|
|
125
|
+
) : (showChevron ?? true) ? (
|
|
126
|
+
<View style={styles.rightContainer}>
|
|
127
|
+
<AtomicIcon
|
|
128
|
+
name="ChevronRight"
|
|
129
|
+
size="sm"
|
|
130
|
+
color="textSecondary"
|
|
131
|
+
style={styles.chevron}
|
|
132
|
+
/>
|
|
133
|
+
</View>
|
|
134
|
+
) : null}
|
|
135
|
+
</TouchableOpacity>
|
|
136
|
+
);
|
|
137
|
+
}
|
|
107
138
|
|
|
108
139
|
return (
|
|
109
|
-
<
|
|
110
|
-
|
|
111
|
-
description={description}
|
|
112
|
-
left={renderLeft}
|
|
113
|
-
right={renderRight}
|
|
114
|
-
onPress={onPress}
|
|
115
|
-
disabled={disabled}
|
|
140
|
+
<View
|
|
141
|
+
style={[styles.listItem, disabled && styles.disabled]}
|
|
116
142
|
testID={testID}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
143
|
+
>
|
|
144
|
+
{/* Left: Gradient Icon */}
|
|
145
|
+
<View style={styles.leftContainer}>
|
|
146
|
+
<LinearGradient
|
|
147
|
+
colors={gradientColors}
|
|
148
|
+
start={{ x: 0, y: 0 }}
|
|
149
|
+
end={{ x: 1, y: 1 }}
|
|
150
|
+
style={styles.iconContainer}
|
|
151
|
+
>
|
|
152
|
+
<AtomicIcon name={icon} size="md" customColor="#FFFFFF" />
|
|
153
|
+
</LinearGradient>
|
|
154
|
+
</View>
|
|
155
|
+
|
|
156
|
+
{/* Center: Title and Description */}
|
|
157
|
+
<View style={styles.contentContainer}>
|
|
158
|
+
<AtomicText
|
|
159
|
+
type="bodyLarge"
|
|
160
|
+
color={disabled ? "textDisabled" : "onSurface"}
|
|
161
|
+
style={styles.title}
|
|
162
|
+
numberOfLines={2}
|
|
163
|
+
ellipsizeMode="tail"
|
|
164
|
+
>
|
|
165
|
+
{title}
|
|
166
|
+
</AtomicText>
|
|
167
|
+
{description && (
|
|
168
|
+
<AtomicText
|
|
169
|
+
type="bodySmall"
|
|
170
|
+
color="textSecondary"
|
|
171
|
+
style={styles.description}
|
|
172
|
+
numberOfLines={2}
|
|
173
|
+
ellipsizeMode="tail"
|
|
174
|
+
>
|
|
175
|
+
{description}
|
|
176
|
+
</AtomicText>
|
|
177
|
+
)}
|
|
178
|
+
</View>
|
|
179
|
+
|
|
180
|
+
{/* Right: Value, Chevron, or Custom Element */}
|
|
181
|
+
{rightElement ? (
|
|
182
|
+
<View style={styles.rightContainer}>{rightElement}</View>
|
|
183
|
+
) : value ? (
|
|
184
|
+
<View style={styles.rightContainer}>
|
|
185
|
+
<AtomicText
|
|
186
|
+
type="bodyMedium"
|
|
187
|
+
color="textSecondary"
|
|
188
|
+
style={styles.value}
|
|
189
|
+
numberOfLines={2}
|
|
190
|
+
textAlign="right"
|
|
191
|
+
>
|
|
192
|
+
{value}
|
|
193
|
+
</AtomicText>
|
|
194
|
+
</View>
|
|
195
|
+
) : null}
|
|
196
|
+
</View>
|
|
125
197
|
);
|
|
126
198
|
};
|
|
127
199
|
|
|
128
200
|
const getStyles = (tokens: DesignTokens) =>
|
|
129
201
|
StyleSheet.create({
|
|
130
202
|
listItem: {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
203
|
+
flexDirection: 'row',
|
|
204
|
+
alignItems: 'center',
|
|
205
|
+
paddingVertical: tokens.spacing.md,
|
|
206
|
+
paddingHorizontal: tokens.spacing.lg,
|
|
207
|
+
minHeight: 72,
|
|
208
|
+
},
|
|
209
|
+
disabled: {
|
|
210
|
+
opacity: 0.5,
|
|
134
211
|
},
|
|
135
212
|
leftContainer: {
|
|
136
213
|
marginRight: tokens.spacing.md,
|
|
137
214
|
justifyContent: 'center',
|
|
138
215
|
},
|
|
139
216
|
iconContainer: {
|
|
140
|
-
width:
|
|
141
|
-
height:
|
|
142
|
-
borderRadius:
|
|
217
|
+
width: 48,
|
|
218
|
+
height: 48,
|
|
219
|
+
borderRadius: 24,
|
|
143
220
|
alignItems: 'center',
|
|
144
221
|
justifyContent: 'center',
|
|
145
222
|
overflow: 'hidden',
|
|
146
223
|
borderWidth: 1,
|
|
147
|
-
borderColor: `${tokens.colors.primary}
|
|
224
|
+
borderColor: `${tokens.colors.primary}15`,
|
|
225
|
+
},
|
|
226
|
+
contentContainer: {
|
|
227
|
+
flex: 1,
|
|
228
|
+
justifyContent: 'center',
|
|
229
|
+
minWidth: 0,
|
|
148
230
|
},
|
|
149
231
|
title: {
|
|
150
232
|
fontSize: tokens.typography.bodyLarge.fontSize,
|
|
151
233
|
fontWeight: '600',
|
|
152
|
-
color: tokens.colors.textPrimary,
|
|
153
234
|
flexShrink: 1,
|
|
235
|
+
lineHeight: tokens.typography.bodyLarge.fontSize * 1.4,
|
|
154
236
|
},
|
|
155
237
|
description: {
|
|
156
238
|
fontSize: tokens.typography.bodySmall.fontSize,
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
opacity: 0.8,
|
|
239
|
+
marginTop: tokens.spacing.xs / 2,
|
|
240
|
+
opacity: 0.7,
|
|
160
241
|
flexShrink: 1,
|
|
242
|
+
lineHeight: tokens.typography.bodySmall.fontSize * 1.4,
|
|
161
243
|
},
|
|
162
244
|
rightContainer: {
|
|
163
245
|
justifyContent: 'center',
|
|
164
246
|
alignItems: 'flex-end',
|
|
247
|
+
marginLeft: tokens.spacing.md,
|
|
165
248
|
maxWidth: '50%',
|
|
166
249
|
flexShrink: 0,
|
|
167
250
|
},
|
|
168
251
|
value: {
|
|
169
252
|
fontWeight: '500',
|
|
170
|
-
|
|
253
|
+
lineHeight: tokens.typography.bodyMedium.fontSize * 1.4,
|
|
171
254
|
},
|
|
172
255
|
chevron: {
|
|
173
|
-
opacity: 0.
|
|
256
|
+
opacity: 0.5,
|
|
174
257
|
},
|
|
175
258
|
});
|
|
176
259
|
|
|
@@ -11,11 +11,10 @@
|
|
|
11
11
|
|
|
12
12
|
import React from 'react';
|
|
13
13
|
import { View, StyleSheet } from 'react-native';
|
|
14
|
-
import { List } from 'react-native-paper';
|
|
15
14
|
|
|
16
15
|
import { useNavigation } from '@react-navigation/native';
|
|
17
16
|
import { useTheme, useAppDesignTokens, type DesignTokens } from '@umituz/react-native-design-system-theme';
|
|
18
|
-
import { AtomicText, ScreenLayout } from '@umituz/react-native-design-system';
|
|
17
|
+
import { AtomicText, ScreenLayout, SectionHeader, SectionContainer } from '@umituz/react-native-design-system';
|
|
19
18
|
import { useLocalization, getLanguageByCode } from '@umituz/react-native-localization';
|
|
20
19
|
import { SettingItem } from '../components/SettingItem';
|
|
21
20
|
|
|
@@ -51,8 +50,8 @@ export const AppearanceScreen: React.FC = () => {
|
|
|
51
50
|
</View>
|
|
52
51
|
|
|
53
52
|
{/* Language Section */}
|
|
54
|
-
<
|
|
55
|
-
<
|
|
53
|
+
<SectionContainer>
|
|
54
|
+
<SectionHeader>{t('settings.language')}</SectionHeader>
|
|
56
55
|
<SettingItem
|
|
57
56
|
icon="Languages"
|
|
58
57
|
iconGradient={((tokens.colors as any).settingGradients?.language as unknown as string[]) || [tokens.colors.primary, tokens.colors.secondary]}
|
|
@@ -61,11 +60,11 @@ export const AppearanceScreen: React.FC = () => {
|
|
|
61
60
|
onPress={handleLanguagePress}
|
|
62
61
|
testID="language-button"
|
|
63
62
|
/>
|
|
64
|
-
</
|
|
63
|
+
</SectionContainer>
|
|
65
64
|
|
|
66
65
|
{/* Theme Section */}
|
|
67
|
-
<
|
|
68
|
-
<
|
|
66
|
+
<SectionContainer>
|
|
67
|
+
<SectionHeader>{t('settings.appearance.darkMode')}</SectionHeader>
|
|
69
68
|
<SettingItem
|
|
70
69
|
icon={themeMode === 'dark' ? 'Moon' : 'Sun'}
|
|
71
70
|
iconGradient={
|
|
@@ -78,7 +77,7 @@ export const AppearanceScreen: React.FC = () => {
|
|
|
78
77
|
onPress={handleThemeToggle}
|
|
79
78
|
testID="theme-button"
|
|
80
79
|
/>
|
|
81
|
-
</
|
|
80
|
+
</SectionContainer>
|
|
82
81
|
</ScreenLayout>
|
|
83
82
|
);
|
|
84
83
|
};
|
|
@@ -12,13 +12,12 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import React, { useMemo } from 'react';
|
|
15
|
-
import { List, Divider } from 'react-native-paper';
|
|
16
15
|
import { DeviceEventEmitter, Alert, View, TouchableOpacity, StyleSheet } from 'react-native';
|
|
17
16
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
18
17
|
|
|
19
18
|
import { useNavigation, CommonActions } from '@react-navigation/native';
|
|
20
19
|
import { useTheme, useAppDesignTokens } from '@umituz/react-native-design-system-theme';
|
|
21
|
-
import { ScreenLayout, AtomicIcon, AtomicText } from '@umituz/react-native-design-system';
|
|
20
|
+
import { ScreenLayout, AtomicIcon, AtomicText, SectionHeader, SectionContainer, AtomicDivider } from '@umituz/react-native-design-system';
|
|
22
21
|
import { SettingItem } from '../components/SettingItem';
|
|
23
22
|
import { getLanguageByCode, useLocalization } from '@umituz/react-native-localization';
|
|
24
23
|
import { SettingsConfig } from './types';
|
|
@@ -261,14 +260,14 @@ export const SettingsScreen: React.FC<SettingsScreenProps> = ({
|
|
|
261
260
|
hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}
|
|
262
261
|
testID="close-settings-button"
|
|
263
262
|
>
|
|
264
|
-
<AtomicIcon name="X" size="lg" color="
|
|
263
|
+
<AtomicIcon name="X" size="lg" color="primary" />
|
|
265
264
|
</TouchableOpacity>
|
|
266
265
|
</View>
|
|
267
266
|
|
|
268
267
|
{/* Appearance Section */}
|
|
269
268
|
{features.appearance && (
|
|
270
|
-
<
|
|
271
|
-
<
|
|
269
|
+
<SectionContainer>
|
|
270
|
+
<SectionHeader>{t('settings.sections.appearance')}</SectionHeader>
|
|
272
271
|
<SettingItem
|
|
273
272
|
icon="Palette"
|
|
274
273
|
iconGradient={theme.colors.settingGradients.themeLight as unknown as string[]}
|
|
@@ -277,13 +276,13 @@ export const SettingsScreen: React.FC<SettingsScreenProps> = ({
|
|
|
277
276
|
onPress={handleAppearancePress}
|
|
278
277
|
testID="appearance-button"
|
|
279
278
|
/>
|
|
280
|
-
</
|
|
279
|
+
</SectionContainer>
|
|
281
280
|
)}
|
|
282
281
|
|
|
283
282
|
{/* General Section - Notifications */}
|
|
284
283
|
{features.notifications && (
|
|
285
|
-
<
|
|
286
|
-
<
|
|
284
|
+
<SectionContainer>
|
|
285
|
+
<SectionHeader>{t('settings.sections.general')}</SectionHeader>
|
|
287
286
|
<SettingItem
|
|
288
287
|
icon="Bell"
|
|
289
288
|
iconGradient={theme.colors.settingGradients.notifications as unknown as string[]}
|
|
@@ -292,13 +291,13 @@ export const SettingsScreen: React.FC<SettingsScreenProps> = ({
|
|
|
292
291
|
onPress={handleNotificationsPress}
|
|
293
292
|
testID="notifications-button"
|
|
294
293
|
/>
|
|
295
|
-
</
|
|
294
|
+
</SectionContainer>
|
|
296
295
|
)}
|
|
297
296
|
|
|
298
297
|
{/* Development/Test: Show Onboarding */}
|
|
299
298
|
{__DEV__ && useOnboardingStore && (
|
|
300
|
-
<
|
|
301
|
-
<
|
|
299
|
+
<SectionContainer>
|
|
300
|
+
<SectionHeader>Development</SectionHeader>
|
|
302
301
|
<SettingItem
|
|
303
302
|
icon="Play"
|
|
304
303
|
iconGradient={theme.colors.settingGradients.info as unknown as string[]}
|
|
@@ -307,13 +306,13 @@ export const SettingsScreen: React.FC<SettingsScreenProps> = ({
|
|
|
307
306
|
onPress={handleShowOnboarding}
|
|
308
307
|
testID="show-onboarding-button"
|
|
309
308
|
/>
|
|
310
|
-
</
|
|
309
|
+
</SectionContainer>
|
|
311
310
|
)}
|
|
312
311
|
|
|
313
312
|
{/* About & Legal Section */}
|
|
314
313
|
{(features.about || features.legal) && (
|
|
315
|
-
<
|
|
316
|
-
<
|
|
314
|
+
<SectionContainer>
|
|
315
|
+
<SectionHeader>{t('settings.sections.about')}</SectionHeader>
|
|
317
316
|
{features.about && (
|
|
318
317
|
<SettingItem
|
|
319
318
|
icon="Info"
|
|
@@ -324,7 +323,7 @@ export const SettingsScreen: React.FC<SettingsScreenProps> = ({
|
|
|
324
323
|
testID="about-button"
|
|
325
324
|
/>
|
|
326
325
|
)}
|
|
327
|
-
{features.about && features.legal && <
|
|
326
|
+
{features.about && features.legal && <AtomicDivider />}
|
|
328
327
|
{features.legal && (
|
|
329
328
|
<SettingItem
|
|
330
329
|
icon="FileText"
|
|
@@ -335,16 +334,16 @@ export const SettingsScreen: React.FC<SettingsScreenProps> = ({
|
|
|
335
334
|
testID="legal-button"
|
|
336
335
|
/>
|
|
337
336
|
)}
|
|
338
|
-
</
|
|
337
|
+
</SectionContainer>
|
|
339
338
|
)}
|
|
340
339
|
|
|
341
340
|
{/* Fallback: Show message if no features are enabled */}
|
|
342
341
|
{!hasAnyFeatures && (
|
|
343
|
-
<
|
|
344
|
-
<
|
|
342
|
+
<SectionContainer>
|
|
343
|
+
<SectionHeader>
|
|
345
344
|
{t('settings.noOptionsAvailable') || 'No settings available'}
|
|
346
|
-
</
|
|
347
|
-
</
|
|
345
|
+
</SectionHeader>
|
|
346
|
+
</SectionContainer>
|
|
348
347
|
)}
|
|
349
348
|
</ScreenLayout>
|
|
350
349
|
);
|