@umituz/react-native-settings 4.21.18 → 4.21.20
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/AboutContent.tsx +3 -4
- package/src/domains/about/presentation/components/AboutHeader.tsx +7 -14
- package/src/domains/about/presentation/components/AboutSection.tsx +2 -2
- package/src/domains/about/presentation/components/AboutSettingItem.tsx +16 -16
- package/src/domains/appearance/presentation/components/AppearanceSection.tsx +2 -2
- package/src/domains/appearance/presentation/screens/AppearanceScreen.tsx +3 -4
- package/src/domains/faqs/presentation/components/FAQEmptyState.tsx +2 -2
- package/src/domains/gamification/components/AchievementCard.tsx +26 -19
- package/src/domains/gamification/components/AchievementItem.tsx +27 -25
- package/src/domains/gamification/components/AchievementToast.tsx +16 -12
- package/src/domains/gamification/components/GamificationScreen/AchievementsList.tsx +6 -5
- package/src/domains/gamification/components/GamificationScreen/Header.tsx +4 -3
- package/src/domains/gamification/components/GamificationScreen/StatsGrid.tsx +4 -3
- package/src/domains/gamification/components/GamificationScreen/index.tsx +38 -28
- package/src/domains/gamification/components/LevelProgress.tsx +25 -18
- package/src/domains/gamification/components/PointsBadge.tsx +13 -9
- package/src/domains/gamification/components/StatsCard.tsx +20 -14
- package/src/domains/gamification/components/StreakDisplay.tsx +28 -22
- package/src/domains/legal/presentation/components/LegalSection.tsx +2 -2
- package/src/domains/notifications/presentation/components/NotificationsSection.tsx +2 -4
- package/src/domains/notifications/presentation/screens/NotificationSettingsScreen.tsx +3 -4
- package/src/domains/rating/presentation/components/StarRating.tsx +2 -2
- package/src/domains/video-tutorials/presentation/components/VideoTutorialCard.tsx +35 -127
- package/src/domains/video-tutorials/presentation/screens/VideoTutorialsScreen.tsx +88 -153
- package/src/presentation/components/SettingsItemCard.tsx +3 -22
- package/src/presentation/navigation/SettingsStackNavigator.tsx +112 -100
- package/src/presentation/screens/SettingsScreen.tsx +6 -2
- package/src/presentation/screens/components/GamificationSettingsItem.tsx +48 -0
- package/src/presentation/screens/components/SettingsContent.tsx +17 -41
- package/src/presentation/screens/components/SettingsHeader.tsx +2 -3
- package/src/presentation/screens/components/SubscriptionSettingsItem.tsx +30 -0
- package/src/presentation/screens/components/WalletSettingsItem.tsx +28 -0
- package/src/presentation/screens/components/sections/FeatureSettingsSection.tsx +2 -2
- package/src/presentation/screens/components/sections/ProfileSectionLoader.tsx +2 -2
- package/src/presentation/screens/components/sections/SupportSettingsSection.tsx +2 -2
- package/src/presentation/screens/hooks/useFeatureDetection.ts +2 -0
- package/src/presentation/screens/types/SettingsConfig.ts +7 -0
- package/src/presentation/screens/types/UserFeatureConfig.ts +21 -0
- package/src/presentation/screens/types/index.ts +2 -0
- package/src/presentation/screens/utils/normalizeConfig.ts +6 -0
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import React from "react";
|
|
7
|
-
import { View,
|
|
8
|
-
import { useAppDesignTokens } from "@umituz/react-native-design-system";
|
|
7
|
+
import { View, Image, StyleSheet, TouchableOpacity } from "react-native";
|
|
8
|
+
import { useAppDesignTokens, AtomicText } from "@umituz/react-native-design-system";
|
|
9
9
|
import type { VideoTutorial } from "../../types";
|
|
10
10
|
|
|
11
11
|
interface VideoTutorialCardProps {
|
|
@@ -32,10 +32,7 @@ export const VideoTutorialCard: React.FC<VideoTutorialCardProps> = ({
|
|
|
32
32
|
<TouchableOpacity
|
|
33
33
|
style={[
|
|
34
34
|
styles.container,
|
|
35
|
-
{
|
|
36
|
-
backgroundColor: tokens.colors.surface,
|
|
37
|
-
borderColor: tokens.colors.border,
|
|
38
|
-
},
|
|
35
|
+
{ backgroundColor: tokens.colors.surface, borderColor: tokens.colors.border },
|
|
39
36
|
horizontal && styles.horizontalContainer,
|
|
40
37
|
]}
|
|
41
38
|
onPress={onPress}
|
|
@@ -47,149 +44,60 @@ export const VideoTutorialCard: React.FC<VideoTutorialCardProps> = ({
|
|
|
47
44
|
style={[styles.thumbnail, horizontal && styles.horizontalThumbnail]}
|
|
48
45
|
resizeMode="cover"
|
|
49
46
|
/>
|
|
50
|
-
<View
|
|
51
|
-
style={
|
|
52
|
-
>
|
|
53
|
-
<Text style={styles.durationText}>
|
|
54
|
-
{formatDuration(tutorial.duration)}
|
|
55
|
-
</Text>
|
|
47
|
+
<View style={[styles.durationBadge, { backgroundColor: "rgba(0,0,0,0.7)" }]}>
|
|
48
|
+
<AtomicText style={styles.durationText}>{formatDuration(tutorial.duration)}</AtomicText>
|
|
56
49
|
</View>
|
|
57
50
|
{tutorial.featured && (
|
|
58
|
-
<View
|
|
59
|
-
style={[
|
|
60
|
-
styles.featuredBadge,
|
|
61
|
-
{ backgroundColor: tokens.colors.primary },
|
|
62
|
-
]}
|
|
63
|
-
>
|
|
64
|
-
<Text style={[styles.featuredText, { color: tokens.colors.onPrimary }]}>
|
|
65
|
-
Featured
|
|
66
|
-
</Text>
|
|
51
|
+
<View style={[styles.featuredBadge, { backgroundColor: tokens.colors.primary }]}>
|
|
52
|
+
<AtomicText style={[styles.featuredText, { color: tokens.colors.onPrimary }]}>Featured</AtomicText>
|
|
67
53
|
</View>
|
|
68
54
|
)}
|
|
69
55
|
</View>
|
|
70
56
|
|
|
71
57
|
<View style={styles.content}>
|
|
72
|
-
<
|
|
73
|
-
style={[
|
|
74
|
-
styles.title,
|
|
75
|
-
{ color: tokens.colors.textPrimary },
|
|
76
|
-
horizontal && styles.horizontalTitle,
|
|
77
|
-
]}
|
|
58
|
+
<AtomicText
|
|
59
|
+
style={[styles.title, horizontal && styles.horizontalTitle]}
|
|
78
60
|
numberOfLines={2}
|
|
79
61
|
>
|
|
80
62
|
{tutorial.title}
|
|
81
|
-
</
|
|
63
|
+
</AtomicText>
|
|
82
64
|
|
|
83
|
-
<
|
|
84
|
-
style={[
|
|
85
|
-
styles.description,
|
|
86
|
-
{ color: tokens.colors.textSecondary },
|
|
87
|
-
horizontal && styles.horizontalDescription,
|
|
88
|
-
]}
|
|
65
|
+
<AtomicText
|
|
66
|
+
style={[styles.description, horizontal && styles.horizontalDescription]}
|
|
89
67
|
numberOfLines={horizontal ? 2 : 3}
|
|
90
68
|
>
|
|
91
69
|
{tutorial.description}
|
|
92
|
-
</
|
|
70
|
+
</AtomicText>
|
|
93
71
|
|
|
94
72
|
<View style={styles.metadata}>
|
|
95
|
-
<
|
|
96
|
-
style={[styles.category, { color: tokens.colors.textTertiary }]}
|
|
97
|
-
>
|
|
73
|
+
<AtomicText style={styles.category}>
|
|
98
74
|
{tutorial.category.replace("-", " ")}
|
|
99
|
-
</
|
|
100
|
-
<
|
|
101
|
-
style={[styles.difficulty, { color: tokens.colors.textSecondary }]}
|
|
102
|
-
>
|
|
75
|
+
</AtomicText>
|
|
76
|
+
<AtomicText style={styles.difficulty}>
|
|
103
77
|
{tutorial.difficulty}
|
|
104
|
-
</
|
|
78
|
+
</AtomicText>
|
|
105
79
|
</View>
|
|
106
80
|
</View>
|
|
107
81
|
</TouchableOpacity>
|
|
108
82
|
);
|
|
109
83
|
};
|
|
110
84
|
|
|
111
|
-
const getStyles = (tokens: ReturnType<typeof useAppDesignTokens>) =>
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
},
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
},
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
},
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
height: 180,
|
|
130
|
-
},
|
|
131
|
-
horizontalThumbnail: {
|
|
132
|
-
height: 140,
|
|
133
|
-
},
|
|
134
|
-
durationBadge: {
|
|
135
|
-
position: "absolute",
|
|
136
|
-
bottom: 8,
|
|
137
|
-
right: 8,
|
|
138
|
-
paddingHorizontal: 6,
|
|
139
|
-
paddingVertical: 2,
|
|
140
|
-
borderRadius: 4,
|
|
141
|
-
},
|
|
142
|
-
durationText: {
|
|
143
|
-
color: tokens.colors.textInverse,
|
|
144
|
-
fontSize: 12,
|
|
145
|
-
fontWeight: "500",
|
|
146
|
-
},
|
|
147
|
-
featuredBadge: {
|
|
148
|
-
position: "absolute",
|
|
149
|
-
top: 8,
|
|
150
|
-
left: 8,
|
|
151
|
-
paddingHorizontal: 8,
|
|
152
|
-
paddingVertical: 4,
|
|
153
|
-
borderRadius: 4,
|
|
154
|
-
},
|
|
155
|
-
featuredText: {
|
|
156
|
-
fontSize: 11,
|
|
157
|
-
fontWeight: "600",
|
|
158
|
-
},
|
|
159
|
-
content: {
|
|
160
|
-
padding: 12,
|
|
161
|
-
},
|
|
162
|
-
title: {
|
|
163
|
-
fontSize: tokens.typography.titleMedium.fontSize,
|
|
164
|
-
fontWeight: "600",
|
|
165
|
-
marginBottom: 6,
|
|
166
|
-
},
|
|
167
|
-
horizontalTitle: {
|
|
168
|
-
fontSize: tokens.typography.bodyLarge.fontSize,
|
|
169
|
-
},
|
|
170
|
-
description: {
|
|
171
|
-
fontSize: tokens.typography.bodyMedium.fontSize,
|
|
172
|
-
lineHeight: 20,
|
|
173
|
-
marginBottom: 8,
|
|
174
|
-
},
|
|
175
|
-
horizontalDescription: {
|
|
176
|
-
fontSize: tokens.typography.bodySmall.fontSize,
|
|
177
|
-
lineHeight: 16,
|
|
178
|
-
marginBottom: 6,
|
|
179
|
-
},
|
|
180
|
-
metadata: {
|
|
181
|
-
flexDirection: "row",
|
|
182
|
-
justifyContent: "space-between",
|
|
183
|
-
alignItems: "center",
|
|
184
|
-
},
|
|
185
|
-
category: {
|
|
186
|
-
fontSize: 12,
|
|
187
|
-
textTransform: "capitalize",
|
|
188
|
-
fontWeight: "500",
|
|
189
|
-
},
|
|
190
|
-
difficulty: {
|
|
191
|
-
fontSize: 12,
|
|
192
|
-
textTransform: "capitalize",
|
|
193
|
-
fontWeight: "500",
|
|
194
|
-
},
|
|
85
|
+
const getStyles = (tokens: ReturnType<typeof useAppDesignTokens>) => StyleSheet.create({
|
|
86
|
+
container: { borderRadius: 12, borderWidth: 1, marginBottom: 12, overflow: "hidden" },
|
|
87
|
+
horizontalContainer: { width: 280, marginRight: 12, marginBottom: 0 },
|
|
88
|
+
imageContainer: { position: "relative" },
|
|
89
|
+
thumbnail: { width: "100%", height: 180 },
|
|
90
|
+
horizontalThumbnail: { height: 140 },
|
|
91
|
+
durationBadge: { position: "absolute", bottom: 8, right: 8, paddingHorizontal: 6, paddingVertical: 2, borderRadius: 4 },
|
|
92
|
+
durationText: { color: tokens.colors.textInverse, fontSize: 12, fontWeight: "500" },
|
|
93
|
+
featuredBadge: { position: "absolute", top: 8, left: 8, paddingHorizontal: 8, paddingVertical: 4, borderRadius: 4 },
|
|
94
|
+
featuredText: { fontSize: 11, fontWeight: "600" },
|
|
95
|
+
content: { padding: 12 },
|
|
96
|
+
title: { fontSize: tokens.typography.titleMedium.fontSize, fontWeight: "600", marginBottom: 6, color: tokens.colors.textPrimary },
|
|
97
|
+
horizontalTitle: { fontSize: tokens.typography.bodyLarge.fontSize },
|
|
98
|
+
description: { fontSize: tokens.typography.bodyMedium.fontSize, lineHeight: 20, marginBottom: 8, color: tokens.colors.textSecondary },
|
|
99
|
+
horizontalDescription: { fontSize: tokens.typography.bodySmall.fontSize, lineHeight: 16, marginBottom: 6 },
|
|
100
|
+
metadata: { flexDirection: "row", justifyContent: "space-between", alignItems: "center" },
|
|
101
|
+
category: { fontSize: 12, textTransform: "capitalize", fontWeight: "500", color: tokens.colors.textTertiary },
|
|
102
|
+
difficulty: { fontSize: 12, textTransform: "capitalize", fontWeight: "500", color: tokens.colors.textSecondary },
|
|
195
103
|
});
|
|
@@ -23,176 +23,111 @@ import type { VideoTutorial } from "../../types";
|
|
|
23
23
|
import { VideoTutorialCard } from "../components/VideoTutorialCard";
|
|
24
24
|
|
|
25
25
|
export interface VideoTutorialsScreenProps {
|
|
26
|
-
/**
|
|
27
|
-
* All tutorials to display (required)
|
|
28
|
-
*/
|
|
29
26
|
tutorials: VideoTutorial[];
|
|
30
|
-
/**
|
|
31
|
-
* Featured tutorials to display in horizontal scroll (optional)
|
|
32
|
-
*/
|
|
33
27
|
featuredTutorials?: VideoTutorial[];
|
|
34
|
-
/**
|
|
35
|
-
* Title of the screen
|
|
36
|
-
*/
|
|
37
28
|
title?: string;
|
|
38
|
-
/**
|
|
39
|
-
* Title for the featured tutorials section
|
|
40
|
-
*/
|
|
41
29
|
featuredTitle?: string;
|
|
42
|
-
/**
|
|
43
|
-
* Title for all tutorials section
|
|
44
|
-
*/
|
|
45
30
|
allTutorialsTitle?: string;
|
|
46
|
-
/**
|
|
47
|
-
* Empty state message when no tutorials
|
|
48
|
-
*/
|
|
49
31
|
emptyMessage?: string;
|
|
50
|
-
/**
|
|
51
|
-
* Loading state (optional - defaults to false)
|
|
52
|
-
*/
|
|
53
32
|
isLoading?: boolean;
|
|
54
|
-
/**
|
|
55
|
-
* Callback when a tutorial is pressed
|
|
56
|
-
*/
|
|
57
33
|
onTutorialPress?: (tutorial: VideoTutorial) => void;
|
|
58
34
|
}
|
|
59
35
|
|
|
60
|
-
export const VideoTutorialsScreen: React.FC<VideoTutorialsScreenProps> =
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const styles = getStyles(tokens);
|
|
36
|
+
export const VideoTutorialsScreen: React.FC<VideoTutorialsScreenProps> = React.memo(
|
|
37
|
+
({
|
|
38
|
+
tutorials,
|
|
39
|
+
featuredTutorials,
|
|
40
|
+
title = "Video Tutorials",
|
|
41
|
+
featuredTitle = "Featured",
|
|
42
|
+
allTutorialsTitle = "All Tutorials",
|
|
43
|
+
emptyMessage = "No tutorials available.",
|
|
44
|
+
isLoading = false,
|
|
45
|
+
onTutorialPress,
|
|
46
|
+
}) => {
|
|
47
|
+
const tokens = useAppDesignTokens();
|
|
48
|
+
const styles = getStyles(tokens);
|
|
74
49
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
[onTutorialPress],
|
|
80
|
-
);
|
|
50
|
+
const handleTutorialPress = React.useCallback(
|
|
51
|
+
(tutorial: VideoTutorial) => onTutorialPress?.(tutorial),
|
|
52
|
+
[onTutorialPress]
|
|
53
|
+
);
|
|
81
54
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
),
|
|
89
|
-
[handleTutorialPress],
|
|
90
|
-
);
|
|
55
|
+
const renderTutorialItem = React.useCallback(
|
|
56
|
+
({ item }: { item: VideoTutorial }) => (
|
|
57
|
+
<VideoTutorialCard tutorial={item} onPress={() => handleTutorialPress(item)} />
|
|
58
|
+
),
|
|
59
|
+
[handleTutorialPress]
|
|
60
|
+
);
|
|
91
61
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
/>
|
|
99
|
-
),
|
|
100
|
-
[handleTutorialPress],
|
|
101
|
-
);
|
|
62
|
+
const renderFeaturedItem = React.useCallback(
|
|
63
|
+
({ item }: { item: VideoTutorial }) => (
|
|
64
|
+
<VideoTutorialCard tutorial={item} onPress={() => handleTutorialPress(item)} horizontal />
|
|
65
|
+
),
|
|
66
|
+
[handleTutorialPress]
|
|
67
|
+
);
|
|
102
68
|
|
|
103
|
-
|
|
104
|
-
return <AtomicSpinner size="lg" fullContainer />;
|
|
105
|
-
}
|
|
69
|
+
if (isLoading) return <AtomicSpinner size="lg" fullContainer />;
|
|
106
70
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if (!hasTutorials && !hasFeatured) {
|
|
111
|
-
return (
|
|
112
|
-
<View style={styles.emptyContainer}>
|
|
113
|
-
<AtomicText color="secondary" type="bodyLarge">
|
|
114
|
-
{emptyMessage}
|
|
115
|
-
</AtomicText>
|
|
116
|
-
</View>
|
|
117
|
-
);
|
|
118
|
-
}
|
|
71
|
+
const hasFeatured = featuredTutorials && featuredTutorials.length > 0;
|
|
72
|
+
const hasTutorials = tutorials && tutorials.length > 0;
|
|
119
73
|
|
|
74
|
+
if (!hasTutorials && !hasFeatured) {
|
|
120
75
|
return (
|
|
121
|
-
<
|
|
122
|
-
<
|
|
123
|
-
|
|
124
|
-
|
|
76
|
+
<View style={styles.emptyContainer}>
|
|
77
|
+
<AtomicText color="secondary" type="bodyLarge">{emptyMessage}</AtomicText>
|
|
78
|
+
</View>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
125
81
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
style={[
|
|
130
|
-
styles.sectionTitle,
|
|
131
|
-
{ color: tokens.colors.textSecondary },
|
|
132
|
-
]}
|
|
133
|
-
>
|
|
134
|
-
{featuredTitle}
|
|
135
|
-
</Text>
|
|
136
|
-
<FlatList
|
|
137
|
-
data={featuredTutorials}
|
|
138
|
-
renderItem={renderFeaturedItem}
|
|
139
|
-
keyExtractor={(item: VideoTutorial) => item.id}
|
|
140
|
-
horizontal
|
|
141
|
-
showsHorizontalScrollIndicator={false}
|
|
142
|
-
contentContainerStyle={styles.horizontalList}
|
|
143
|
-
/>
|
|
144
|
-
</View>
|
|
145
|
-
)}
|
|
82
|
+
return (
|
|
83
|
+
<ScreenLayout scrollable={false} edges={["top", "bottom"]}>
|
|
84
|
+
<AtomicText style={styles.title}>{title}</AtomicText>
|
|
146
85
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
86
|
+
{hasFeatured && (
|
|
87
|
+
<View style={styles.section}>
|
|
88
|
+
<AtomicText color="secondary" style={styles.sectionTitle}>{featuredTitle}</AtomicText>
|
|
89
|
+
<FlatList
|
|
90
|
+
data={featuredTutorials}
|
|
91
|
+
renderItem={renderFeaturedItem}
|
|
92
|
+
keyExtractor={(item) => item.id}
|
|
93
|
+
horizontal
|
|
94
|
+
showsHorizontalScrollIndicator={false}
|
|
95
|
+
contentContainerStyle={styles.horizontalList}
|
|
96
|
+
/>
|
|
97
|
+
</View>
|
|
98
|
+
)}
|
|
99
|
+
|
|
100
|
+
{hasTutorials && (
|
|
101
|
+
<View style={styles.section}>
|
|
102
|
+
<AtomicText color="secondary" style={styles.sectionTitle}>{allTutorialsTitle}</AtomicText>
|
|
103
|
+
<FlatList
|
|
104
|
+
data={tutorials}
|
|
105
|
+
renderItem={renderTutorialItem}
|
|
106
|
+
keyExtractor={(item) => item.id}
|
|
107
|
+
showsVerticalScrollIndicator={false}
|
|
108
|
+
contentContainerStyle={styles.verticalList}
|
|
109
|
+
/>
|
|
110
|
+
</View>
|
|
111
|
+
)}
|
|
112
|
+
</ScreenLayout>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
);
|
|
170
116
|
|
|
171
|
-
const getStyles = (tokens:
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
},
|
|
189
|
-
verticalList: {
|
|
190
|
-
paddingBottom: 16,
|
|
191
|
-
},
|
|
192
|
-
emptyContainer: {
|
|
193
|
-
flex: 1,
|
|
194
|
-
justifyContent: "center",
|
|
195
|
-
alignItems: "center",
|
|
196
|
-
padding: 20,
|
|
197
|
-
},
|
|
198
|
-
});
|
|
117
|
+
const getStyles = (tokens: any) => StyleSheet.create({
|
|
118
|
+
title: {
|
|
119
|
+
fontSize: tokens.typography.headlineLarge.fontSize,
|
|
120
|
+
color: tokens.colors.textPrimary,
|
|
121
|
+
fontWeight: "600",
|
|
122
|
+
marginBottom: 24,
|
|
123
|
+
},
|
|
124
|
+
section: { marginBottom: 24 },
|
|
125
|
+
sectionTitle: {
|
|
126
|
+
fontSize: tokens.typography.titleLarge.fontSize,
|
|
127
|
+
fontWeight: "500",
|
|
128
|
+
marginBottom: 12,
|
|
129
|
+
},
|
|
130
|
+
horizontalList: { paddingRight: 16 },
|
|
131
|
+
verticalList: { paddingBottom: 16 },
|
|
132
|
+
emptyContainer: { flex: 1, justifyContent: "center", alignItems: "center", padding: 20 },
|
|
133
|
+
});
|
|
@@ -5,45 +5,26 @@ import {
|
|
|
5
5
|
AtomicIcon,
|
|
6
6
|
AtomicText,
|
|
7
7
|
type IconName,
|
|
8
|
+
withAlpha
|
|
8
9
|
} from "@umituz/react-native-design-system";
|
|
9
10
|
|
|
10
11
|
export interface SettingsItemCardProps {
|
|
11
|
-
/** Item title */
|
|
12
12
|
title: string;
|
|
13
|
-
/** Optional description or current value */
|
|
14
13
|
description?: string;
|
|
15
|
-
/** Icon name from AtomicIcon */
|
|
16
14
|
icon: IconName;
|
|
17
|
-
/** On press handler - if undefined, item is not clickable */
|
|
18
15
|
onPress?: () => void;
|
|
19
|
-
/** Optional container style */
|
|
20
16
|
containerStyle?: ViewStyle;
|
|
21
|
-
/** Optional section title (shows above the card) */
|
|
22
17
|
sectionTitle?: string;
|
|
23
|
-
/** Optional right icon (defaults to chevron-forward, hidden if not clickable) */
|
|
24
18
|
rightIcon?: IconName;
|
|
25
|
-
/** Optional icon background color (defaults to primary with opacity) */
|
|
26
19
|
iconBgColor?: string;
|
|
27
|
-
/** Optional icon color */
|
|
28
20
|
iconColor?: string;
|
|
29
|
-
/** Show chevron even if not clickable */
|
|
30
21
|
showChevron?: boolean;
|
|
31
|
-
/** Show switch instead of chevron */
|
|
32
22
|
showSwitch?: boolean;
|
|
33
|
-
/** Switch value (when showSwitch is true) */
|
|
34
23
|
switchValue?: boolean;
|
|
35
|
-
/** Switch change handler */
|
|
36
24
|
onSwitchChange?: (value: boolean) => void;
|
|
37
|
-
/** Disable the item */
|
|
38
25
|
disabled?: boolean;
|
|
39
26
|
}
|
|
40
27
|
|
|
41
|
-
/**
|
|
42
|
-
* SettingsItemCard
|
|
43
|
-
*
|
|
44
|
-
* A premium, consistent card for settings items used across all apps.
|
|
45
|
-
* Follows the visual style of the Appearance section.
|
|
46
|
-
*/
|
|
47
28
|
export const SettingsItemCard: React.FC<SettingsItemCardProps> = ({
|
|
48
29
|
title,
|
|
49
30
|
description,
|
|
@@ -63,7 +44,7 @@ export const SettingsItemCard: React.FC<SettingsItemCardProps> = ({
|
|
|
63
44
|
const tokens = useAppDesignTokens();
|
|
64
45
|
const colors = tokens.colors;
|
|
65
46
|
|
|
66
|
-
const defaultIconBg = iconBgColor ||
|
|
47
|
+
const defaultIconBg = iconBgColor || withAlpha(colors.primary, 0.15);
|
|
67
48
|
const defaultIconColor = iconColor || colors.primary;
|
|
68
49
|
const isClickable = !!onPress && !showSwitch;
|
|
69
50
|
const shouldShowChevron = !showSwitch && (showChevron ?? isClickable);
|
|
@@ -137,7 +118,7 @@ export const SettingsItemCard: React.FC<SettingsItemCardProps> = ({
|
|
|
137
118
|
style={({ pressed }) => [
|
|
138
119
|
styles.itemContainer,
|
|
139
120
|
{
|
|
140
|
-
backgroundColor: pressed ?
|
|
121
|
+
backgroundColor: pressed ? withAlpha(colors.primary, 0.08) : "transparent",
|
|
141
122
|
},
|
|
142
123
|
]}
|
|
143
124
|
onPress={onPress}
|