@umituz/react-native-settings 4.23.128 → 4.23.130
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/gamification/components/AchievementCard.tsx +71 -29
- package/src/domains/gamification/components/LevelProgress.tsx +72 -28
- package/src/domains/gamification/components/PointsBadge.tsx +11 -7
- package/src/domains/gamification/components/StatsCard.tsx +58 -19
- package/src/domains/gamification/components/StreakDisplay.tsx +80 -26
- package/src/domains/notifications/infrastructure/services/NotificationManager.ts +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-settings",
|
|
3
|
-
"version": "4.23.
|
|
3
|
+
"version": "4.23.130",
|
|
4
4
|
"description": "Complete settings hub for React Native apps - consolidated package with settings, localization, about, legal, appearance, feedback, FAQs, rating, and gamification",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import React from "react";
|
|
7
7
|
import { View, StyleSheet, type ViewStyle, type TextStyle } from "react-native";
|
|
8
|
-
import { useAppDesignTokens, AtomicText, withAlpha } from "@umituz/react-native-design-system";
|
|
8
|
+
import { useAppDesignTokens, AtomicText, withAlpha, useResponsive } from "@umituz/react-native-design-system";
|
|
9
9
|
|
|
10
10
|
export interface AchievementCardProps {
|
|
11
11
|
title: string;
|
|
@@ -41,24 +41,44 @@ export const AchievementCard: React.FC<AchievementCardProps> = ({
|
|
|
41
41
|
subtextColor,
|
|
42
42
|
}) => {
|
|
43
43
|
const tokens = useAppDesignTokens();
|
|
44
|
-
|
|
44
|
+
const { getFontSize, getIconSize } = useResponsive();
|
|
45
|
+
|
|
45
46
|
const finalUnlockedColor = unlockedColor || tokens.colors.success;
|
|
46
47
|
const finalLockedColor = lockedColor || tokens.colors.textDisabled;
|
|
47
48
|
const finalBackgroundColor = backgroundColor || tokens.colors.surface;
|
|
48
49
|
const finalTextColor = textColor || tokens.colors.textPrimary;
|
|
49
50
|
const finalSubtextColor = subtextColor || tokens.colors.textSecondary;
|
|
50
|
-
|
|
51
|
+
|
|
51
52
|
const accentColor = isUnlocked ? finalUnlockedColor : finalLockedColor;
|
|
53
|
+
const titleFontSize = getFontSize(16);
|
|
54
|
+
const descriptionFontSize = getFontSize(13);
|
|
55
|
+
const checkmarkFontSize = getFontSize(14);
|
|
56
|
+
const iconSize = getIconSize(48);
|
|
57
|
+
const checkmarkSize = getIconSize(24);
|
|
52
58
|
|
|
53
59
|
return (
|
|
54
60
|
<View
|
|
55
61
|
style={[
|
|
56
62
|
styles.container,
|
|
57
|
-
{
|
|
63
|
+
{
|
|
64
|
+
backgroundColor: finalBackgroundColor,
|
|
65
|
+
borderColor: withAlpha(accentColor, 0.4),
|
|
66
|
+
padding: tokens.spacing.md,
|
|
67
|
+
borderRadius: tokens.borders.radius.md,
|
|
68
|
+
gap: tokens.spacing.md,
|
|
69
|
+
},
|
|
58
70
|
containerStyle,
|
|
59
71
|
]}
|
|
60
72
|
>
|
|
61
|
-
<View style={[
|
|
73
|
+
<View style={[
|
|
74
|
+
styles.iconContainer,
|
|
75
|
+
{
|
|
76
|
+
backgroundColor: withAlpha(accentColor, 0.2),
|
|
77
|
+
width: iconSize,
|
|
78
|
+
height: iconSize,
|
|
79
|
+
borderRadius: iconSize / 2,
|
|
80
|
+
}
|
|
81
|
+
]}>
|
|
62
82
|
{icon}
|
|
63
83
|
</View>
|
|
64
84
|
|
|
@@ -66,22 +86,45 @@ export const AchievementCard: React.FC<AchievementCardProps> = ({
|
|
|
66
86
|
<AtomicText
|
|
67
87
|
style={[
|
|
68
88
|
styles.title,
|
|
69
|
-
{
|
|
89
|
+
{
|
|
90
|
+
color: isUnlocked ? finalTextColor : finalSubtextColor,
|
|
91
|
+
fontSize: titleFontSize,
|
|
92
|
+
},
|
|
70
93
|
titleStyle,
|
|
71
94
|
]}
|
|
72
95
|
>
|
|
73
96
|
{title}
|
|
74
97
|
</AtomicText>
|
|
75
|
-
<AtomicText style={[
|
|
98
|
+
<AtomicText style={[
|
|
99
|
+
styles.description,
|
|
100
|
+
{
|
|
101
|
+
color: finalSubtextColor,
|
|
102
|
+
fontSize: descriptionFontSize,
|
|
103
|
+
marginTop: tokens.spacing.xs,
|
|
104
|
+
},
|
|
105
|
+
descriptionStyle
|
|
106
|
+
]}>
|
|
76
107
|
{description}
|
|
77
108
|
</AtomicText>
|
|
78
109
|
|
|
79
110
|
{!isUnlocked && (
|
|
80
|
-
<View style={[
|
|
111
|
+
<View style={[
|
|
112
|
+
styles.progressBar,
|
|
113
|
+
{
|
|
114
|
+
backgroundColor: withAlpha(finalLockedColor, 0.4),
|
|
115
|
+
marginTop: tokens.spacing.sm,
|
|
116
|
+
borderRadius: tokens.borders.radius.xs,
|
|
117
|
+
},
|
|
118
|
+
progressBarStyle
|
|
119
|
+
]}>
|
|
81
120
|
<View
|
|
82
121
|
style={[
|
|
83
122
|
styles.progressFill,
|
|
84
|
-
{
|
|
123
|
+
{
|
|
124
|
+
width: `${progress}%`,
|
|
125
|
+
backgroundColor: accentColor,
|
|
126
|
+
borderRadius: tokens.borders.radius.xs,
|
|
127
|
+
},
|
|
85
128
|
]}
|
|
86
129
|
/>
|
|
87
130
|
</View>
|
|
@@ -89,8 +132,24 @@ export const AchievementCard: React.FC<AchievementCardProps> = ({
|
|
|
89
132
|
</View>
|
|
90
133
|
|
|
91
134
|
{isUnlocked && (
|
|
92
|
-
<View style={[
|
|
93
|
-
|
|
135
|
+
<View style={[
|
|
136
|
+
styles.checkmark,
|
|
137
|
+
{
|
|
138
|
+
backgroundColor: finalUnlockedColor,
|
|
139
|
+
width: checkmarkSize,
|
|
140
|
+
height: checkmarkSize,
|
|
141
|
+
borderRadius: checkmarkSize / 2,
|
|
142
|
+
}
|
|
143
|
+
]}>
|
|
144
|
+
<AtomicText style={[
|
|
145
|
+
styles.checkmarkText,
|
|
146
|
+
{
|
|
147
|
+
color: tokens.colors.onPrimary,
|
|
148
|
+
fontSize: checkmarkFontSize,
|
|
149
|
+
}
|
|
150
|
+
]}>
|
|
151
|
+
✓
|
|
152
|
+
</AtomicText>
|
|
94
153
|
</View>
|
|
95
154
|
)}
|
|
96
155
|
</View>
|
|
@@ -101,15 +160,9 @@ const styles = StyleSheet.create({
|
|
|
101
160
|
container: {
|
|
102
161
|
flexDirection: "row",
|
|
103
162
|
alignItems: "center",
|
|
104
|
-
padding: 12,
|
|
105
|
-
borderRadius: 12,
|
|
106
163
|
borderWidth: 1,
|
|
107
|
-
gap: 12,
|
|
108
164
|
},
|
|
109
165
|
iconContainer: {
|
|
110
|
-
width: 48,
|
|
111
|
-
height: 48,
|
|
112
|
-
borderRadius: 24,
|
|
113
166
|
justifyContent: "center",
|
|
114
167
|
alignItems: "center",
|
|
115
168
|
},
|
|
@@ -117,32 +170,21 @@ const styles = StyleSheet.create({
|
|
|
117
170
|
flex: 1,
|
|
118
171
|
},
|
|
119
172
|
title: {
|
|
120
|
-
fontSize: 16,
|
|
121
173
|
fontWeight: "600",
|
|
122
174
|
},
|
|
123
|
-
description: {
|
|
124
|
-
fontSize: 13,
|
|
125
|
-
marginTop: 2,
|
|
126
|
-
},
|
|
175
|
+
description: {},
|
|
127
176
|
progressBar: {
|
|
128
177
|
height: 4,
|
|
129
|
-
borderRadius: 2,
|
|
130
|
-
marginTop: 8,
|
|
131
178
|
overflow: "hidden",
|
|
132
179
|
},
|
|
133
180
|
progressFill: {
|
|
134
181
|
height: "100%",
|
|
135
|
-
borderRadius: 2,
|
|
136
182
|
},
|
|
137
183
|
checkmark: {
|
|
138
|
-
width: 24,
|
|
139
|
-
height: 24,
|
|
140
|
-
borderRadius: 12,
|
|
141
184
|
justifyContent: "center",
|
|
142
185
|
alignItems: "center",
|
|
143
186
|
},
|
|
144
187
|
checkmarkText: {
|
|
145
|
-
fontSize: 14,
|
|
146
188
|
fontWeight: "bold",
|
|
147
189
|
},
|
|
148
190
|
});
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import React from "react";
|
|
7
7
|
import { View, StyleSheet, type ViewStyle, type TextStyle } from "react-native";
|
|
8
|
-
import { useAppDesignTokens, AtomicText, withAlpha } from "@umituz/react-native-design-system";
|
|
8
|
+
import { useAppDesignTokens, AtomicText, withAlpha, useResponsive } from "@umituz/react-native-design-system";
|
|
9
9
|
|
|
10
10
|
export interface LevelProgressProps {
|
|
11
11
|
level: number;
|
|
@@ -49,39 +49,99 @@ export const LevelProgress: React.FC<LevelProgressProps> = ({
|
|
|
49
49
|
subtextColor,
|
|
50
50
|
}) => {
|
|
51
51
|
const tokens = useAppDesignTokens();
|
|
52
|
-
|
|
52
|
+
const { getFontSize, getIconSize } = useResponsive();
|
|
53
|
+
|
|
53
54
|
const finalPrimaryColor = primaryColor || tokens.colors.primary;
|
|
54
55
|
const finalSecondaryColor = secondaryColor || tokens.colors.surfaceSecondary;
|
|
55
56
|
const finalBackgroundColor = backgroundColor || tokens.colors.surface;
|
|
56
57
|
const finalTextColor = textColor || tokens.colors.textPrimary;
|
|
57
58
|
const finalSubtextColor = subtextColor || tokens.colors.textSecondary;
|
|
58
59
|
|
|
60
|
+
const titleFontSize = getFontSize(18);
|
|
61
|
+
const subtitleFontSize = getFontSize(14);
|
|
62
|
+
const badgeSize = getIconSize(52);
|
|
63
|
+
const badgeFontSize = getFontSize(20);
|
|
64
|
+
const progressBarHeight = getFontSize(10);
|
|
65
|
+
|
|
59
66
|
return (
|
|
60
|
-
<View style={[
|
|
61
|
-
|
|
67
|
+
<View style={[
|
|
68
|
+
styles.container,
|
|
69
|
+
{
|
|
70
|
+
backgroundColor: finalBackgroundColor,
|
|
71
|
+
borderRadius: tokens.borders.radius.lg,
|
|
72
|
+
padding: tokens.spacing.lg,
|
|
73
|
+
},
|
|
74
|
+
containerStyle
|
|
75
|
+
]}>
|
|
76
|
+
<View style={[styles.header, { marginBottom: tokens.spacing.md }]}>
|
|
62
77
|
<View style={styles.titleSection}>
|
|
63
|
-
<AtomicText style={[
|
|
78
|
+
<AtomicText style={[
|
|
79
|
+
styles.levelTitle,
|
|
80
|
+
{
|
|
81
|
+
color: finalTextColor,
|
|
82
|
+
fontSize: titleFontSize,
|
|
83
|
+
},
|
|
84
|
+
titleStyle
|
|
85
|
+
]}>
|
|
64
86
|
{levelTitle}
|
|
65
87
|
</AtomicText>
|
|
66
88
|
{showPoints && (
|
|
67
|
-
<AtomicText style={[
|
|
89
|
+
<AtomicText style={[
|
|
90
|
+
styles.subtitle,
|
|
91
|
+
{
|
|
92
|
+
color: finalSubtextColor,
|
|
93
|
+
fontSize: subtitleFontSize,
|
|
94
|
+
marginTop: tokens.spacing.xs,
|
|
95
|
+
},
|
|
96
|
+
subtitleStyle
|
|
97
|
+
]}>
|
|
68
98
|
{points} / {points + pointsToNext}
|
|
69
99
|
</AtomicText>
|
|
70
100
|
)}
|
|
71
101
|
</View>
|
|
72
102
|
|
|
73
|
-
<View style={[
|
|
74
|
-
|
|
103
|
+
<View style={[
|
|
104
|
+
styles.badge,
|
|
105
|
+
{
|
|
106
|
+
backgroundColor: withAlpha(finalPrimaryColor, 0.2),
|
|
107
|
+
borderColor: withAlpha(finalPrimaryColor, 0.4),
|
|
108
|
+
width: badgeSize,
|
|
109
|
+
height: badgeSize,
|
|
110
|
+
borderRadius: badgeSize / 2,
|
|
111
|
+
borderWidth: 2,
|
|
112
|
+
},
|
|
113
|
+
badgeStyle
|
|
114
|
+
]}>
|
|
115
|
+
<AtomicText style={[
|
|
116
|
+
styles.badgeText,
|
|
117
|
+
{
|
|
118
|
+
color: finalPrimaryColor,
|
|
119
|
+
fontSize: badgeFontSize,
|
|
120
|
+
},
|
|
121
|
+
badgeTextStyle
|
|
122
|
+
]}>
|
|
75
123
|
{level}
|
|
76
124
|
</AtomicText>
|
|
77
125
|
</View>
|
|
78
126
|
</View>
|
|
79
127
|
|
|
80
|
-
<View style={[
|
|
128
|
+
<View style={[
|
|
129
|
+
styles.progressBar,
|
|
130
|
+
{
|
|
131
|
+
backgroundColor: finalSecondaryColor,
|
|
132
|
+
height: progressBarHeight,
|
|
133
|
+
borderRadius: tokens.borders.radius.sm,
|
|
134
|
+
},
|
|
135
|
+
progressBarStyle
|
|
136
|
+
]}>
|
|
81
137
|
<View
|
|
82
138
|
style={[
|
|
83
139
|
styles.progressFill,
|
|
84
|
-
{
|
|
140
|
+
{
|
|
141
|
+
width: `${Math.min(100, progress)}%`,
|
|
142
|
+
backgroundColor: finalPrimaryColor,
|
|
143
|
+
borderRadius: tokens.borders.radius.sm,
|
|
144
|
+
},
|
|
85
145
|
progressFillStyle,
|
|
86
146
|
]}
|
|
87
147
|
/>
|
|
@@ -91,46 +151,30 @@ export const LevelProgress: React.FC<LevelProgressProps> = ({
|
|
|
91
151
|
};
|
|
92
152
|
|
|
93
153
|
const styles = StyleSheet.create({
|
|
94
|
-
container: {
|
|
95
|
-
borderRadius: 16,
|
|
96
|
-
padding: 16,
|
|
97
|
-
},
|
|
154
|
+
container: {},
|
|
98
155
|
header: {
|
|
99
156
|
flexDirection: "row",
|
|
100
157
|
justifyContent: "space-between",
|
|
101
158
|
alignItems: "center",
|
|
102
|
-
marginBottom: 12,
|
|
103
159
|
},
|
|
104
160
|
titleSection: {
|
|
105
161
|
flex: 1,
|
|
106
162
|
},
|
|
107
163
|
levelTitle: {
|
|
108
|
-
fontSize: 18,
|
|
109
164
|
fontWeight: "700",
|
|
110
165
|
},
|
|
111
|
-
subtitle: {
|
|
112
|
-
fontSize: 14,
|
|
113
|
-
marginTop: 2,
|
|
114
|
-
},
|
|
166
|
+
subtitle: {},
|
|
115
167
|
badge: {
|
|
116
|
-
width: 48,
|
|
117
|
-
height: 48,
|
|
118
|
-
borderRadius: 24,
|
|
119
168
|
justifyContent: "center",
|
|
120
169
|
alignItems: "center",
|
|
121
|
-
borderWidth: 2,
|
|
122
170
|
},
|
|
123
171
|
badgeText: {
|
|
124
|
-
fontSize: 18,
|
|
125
172
|
fontWeight: "bold",
|
|
126
173
|
},
|
|
127
174
|
progressBar: {
|
|
128
|
-
height: 8,
|
|
129
|
-
borderRadius: 4,
|
|
130
175
|
overflow: "hidden",
|
|
131
176
|
},
|
|
132
177
|
progressFill: {
|
|
133
178
|
height: "100%",
|
|
134
|
-
borderRadius: 4,
|
|
135
179
|
},
|
|
136
180
|
});
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import React from "react";
|
|
7
7
|
import { View, StyleSheet, type ViewStyle, type TextStyle } from "react-native";
|
|
8
|
-
import { useAppDesignTokens, AtomicText, withAlpha } from "@umituz/react-native-design-system";
|
|
8
|
+
import { useAppDesignTokens, AtomicText, withAlpha, useResponsive } from "@umituz/react-native-design-system";
|
|
9
9
|
|
|
10
10
|
export interface PointsBadgeProps {
|
|
11
11
|
points: number;
|
|
@@ -27,20 +27,28 @@ export const PointsBadge: React.FC<PointsBadgeProps> = ({
|
|
|
27
27
|
borderColor,
|
|
28
28
|
}) => {
|
|
29
29
|
const tokens = useAppDesignTokens();
|
|
30
|
+
const { getFontSize } = useResponsive();
|
|
30
31
|
const finalTextColor = textColor || tokens.colors.primary;
|
|
31
32
|
const finalBackgroundColor = backgroundColor || withAlpha(finalTextColor, 0.1);
|
|
32
33
|
const finalBorderColor = borderColor || withAlpha(finalTextColor, 0.2);
|
|
34
|
+
const fontSize = getFontSize(16);
|
|
33
35
|
|
|
34
36
|
return (
|
|
35
37
|
<View
|
|
36
38
|
style={[
|
|
37
39
|
styles.container,
|
|
38
|
-
{
|
|
40
|
+
{
|
|
41
|
+
backgroundColor: finalBackgroundColor,
|
|
42
|
+
borderColor: finalBorderColor,
|
|
43
|
+
paddingHorizontal: tokens.spacing.md,
|
|
44
|
+
paddingVertical: tokens.spacing.xs,
|
|
45
|
+
borderRadius: tokens.borders.radius.full,
|
|
46
|
+
},
|
|
39
47
|
containerStyle,
|
|
40
48
|
]}
|
|
41
49
|
>
|
|
42
50
|
{icon}
|
|
43
|
-
<AtomicText style={[styles.text, { color: finalTextColor }, textStyle]}>
|
|
51
|
+
<AtomicText style={[styles.text, { color: finalTextColor, fontSize }, textStyle]}>
|
|
44
52
|
{points}
|
|
45
53
|
</AtomicText>
|
|
46
54
|
</View>
|
|
@@ -52,13 +60,9 @@ const styles = StyleSheet.create({
|
|
|
52
60
|
flexDirection: "row",
|
|
53
61
|
alignItems: "center",
|
|
54
62
|
gap: 6,
|
|
55
|
-
paddingHorizontal: 12,
|
|
56
|
-
paddingVertical: 6,
|
|
57
|
-
borderRadius: 20,
|
|
58
63
|
borderWidth: 1,
|
|
59
64
|
},
|
|
60
65
|
text: {
|
|
61
|
-
fontSize: 16,
|
|
62
66
|
fontWeight: "bold",
|
|
63
67
|
},
|
|
64
68
|
});
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import React from "react";
|
|
7
7
|
import { View, StyleSheet, type ViewStyle, type TextStyle } from "react-native";
|
|
8
|
-
import { useAppDesignTokens, AtomicText, AtomicIcon, withAlpha } from "@umituz/react-native-design-system";
|
|
8
|
+
import { useAppDesignTokens, AtomicText, AtomicIcon, withAlpha, useResponsive } from "@umituz/react-native-design-system";
|
|
9
9
|
|
|
10
10
|
export interface StatsCardProps {
|
|
11
11
|
value: number;
|
|
@@ -35,30 +35,77 @@ export const StatsCard: React.FC<StatsCardProps> = ({
|
|
|
35
35
|
subtextColor,
|
|
36
36
|
}) => {
|
|
37
37
|
const tokens = useAppDesignTokens();
|
|
38
|
-
|
|
38
|
+
const { getFontSize, getIconSize } = useResponsive();
|
|
39
|
+
|
|
39
40
|
const finalAccentColor = accentColor || tokens.colors.primary;
|
|
40
41
|
const finalBackgroundColor = backgroundColor || tokens.colors.surface;
|
|
41
42
|
const finalTextColor = textColor || tokens.colors.textPrimary;
|
|
42
43
|
const finalSubtextColor = subtextColor || tokens.colors.textSecondary;
|
|
43
44
|
|
|
44
45
|
const renderedIcon = typeof icon === 'string' ? (
|
|
45
|
-
<AtomicIcon name={icon} size="
|
|
46
|
+
<AtomicIcon name={icon} size="md" customColor={finalAccentColor} />
|
|
46
47
|
) : icon;
|
|
47
48
|
|
|
49
|
+
const valueFontSize = getFontSize(32);
|
|
50
|
+
const suffixFontSize = getFontSize(14);
|
|
51
|
+
const labelFontSize = getFontSize(13);
|
|
52
|
+
const iconSize = getIconSize(44);
|
|
53
|
+
|
|
48
54
|
return (
|
|
49
|
-
<View style={[
|
|
50
|
-
|
|
55
|
+
<View style={[
|
|
56
|
+
styles.container,
|
|
57
|
+
{
|
|
58
|
+
backgroundColor: finalBackgroundColor,
|
|
59
|
+
borderRadius: tokens.borders.radius.lg,
|
|
60
|
+
padding: tokens.spacing.lg,
|
|
61
|
+
},
|
|
62
|
+
containerStyle
|
|
63
|
+
]}>
|
|
64
|
+
<View style={[
|
|
65
|
+
styles.iconContainer,
|
|
66
|
+
{
|
|
67
|
+
backgroundColor: withAlpha(finalAccentColor, 0.15),
|
|
68
|
+
width: iconSize,
|
|
69
|
+
height: iconSize,
|
|
70
|
+
borderRadius: iconSize / 2,
|
|
71
|
+
marginBottom: tokens.spacing.md,
|
|
72
|
+
}
|
|
73
|
+
]}>
|
|
51
74
|
{renderedIcon}
|
|
52
75
|
</View>
|
|
53
|
-
<View style={styles.valueRow}>
|
|
54
|
-
<AtomicText style={[
|
|
76
|
+
<View style={[styles.valueRow, { minHeight: valueFontSize + 4 }]}>
|
|
77
|
+
<AtomicText style={[
|
|
78
|
+
styles.value,
|
|
79
|
+
{
|
|
80
|
+
color: finalTextColor,
|
|
81
|
+
fontSize: valueFontSize,
|
|
82
|
+
lineHeight: valueFontSize + 4,
|
|
83
|
+
},
|
|
84
|
+
valueStyle
|
|
85
|
+
]}>
|
|
55
86
|
{value}
|
|
56
87
|
</AtomicText>
|
|
57
88
|
{suffix && (
|
|
58
|
-
<AtomicText style={[
|
|
89
|
+
<AtomicText style={[
|
|
90
|
+
styles.suffix,
|
|
91
|
+
{
|
|
92
|
+
color: finalSubtextColor,
|
|
93
|
+
fontSize: suffixFontSize,
|
|
94
|
+
}
|
|
95
|
+
]}>
|
|
96
|
+
{suffix}
|
|
97
|
+
</AtomicText>
|
|
59
98
|
)}
|
|
60
99
|
</View>
|
|
61
|
-
<AtomicText style={[
|
|
100
|
+
<AtomicText style={[
|
|
101
|
+
styles.label,
|
|
102
|
+
{
|
|
103
|
+
color: finalSubtextColor,
|
|
104
|
+
fontSize: labelFontSize,
|
|
105
|
+
marginTop: tokens.spacing.xs,
|
|
106
|
+
},
|
|
107
|
+
labelStyle
|
|
108
|
+
]}>
|
|
62
109
|
{label}
|
|
63
110
|
</AtomicText>
|
|
64
111
|
</View>
|
|
@@ -69,16 +116,10 @@ const styles = StyleSheet.create({
|
|
|
69
116
|
container: {
|
|
70
117
|
flex: 1,
|
|
71
118
|
minWidth: "45%",
|
|
72
|
-
borderRadius: 12,
|
|
73
|
-
padding: 12,
|
|
74
119
|
},
|
|
75
120
|
iconContainer: {
|
|
76
|
-
width: 36,
|
|
77
|
-
height: 36,
|
|
78
|
-
borderRadius: 18,
|
|
79
121
|
alignItems: "center",
|
|
80
122
|
justifyContent: "center",
|
|
81
|
-
marginBottom: 8,
|
|
82
123
|
},
|
|
83
124
|
valueRow: {
|
|
84
125
|
flexDirection: "row",
|
|
@@ -86,14 +127,12 @@ const styles = StyleSheet.create({
|
|
|
86
127
|
gap: 4,
|
|
87
128
|
},
|
|
88
129
|
value: {
|
|
89
|
-
fontSize: 24,
|
|
90
130
|
fontWeight: "bold",
|
|
91
131
|
},
|
|
92
132
|
suffix: {
|
|
93
|
-
|
|
133
|
+
fontWeight: "500",
|
|
94
134
|
},
|
|
95
135
|
label: {
|
|
96
|
-
|
|
97
|
-
marginTop: 2,
|
|
136
|
+
fontWeight: "500",
|
|
98
137
|
},
|
|
99
138
|
});
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import React from "react";
|
|
7
7
|
import { View, StyleSheet, type ViewStyle, type TextStyle } from "react-native";
|
|
8
|
-
import { useAppDesignTokens, AtomicText, AtomicIcon, withAlpha } from "@umituz/react-native-design-system";
|
|
8
|
+
import { useAppDesignTokens, AtomicText, AtomicIcon, withAlpha, useResponsive } from "@umituz/react-native-design-system";
|
|
9
9
|
|
|
10
10
|
export interface StreakDisplayProps {
|
|
11
11
|
current: number;
|
|
@@ -39,38 +39,102 @@ export const StreakDisplay: React.FC<StreakDisplayProps> = ({
|
|
|
39
39
|
subtextColor,
|
|
40
40
|
}) => {
|
|
41
41
|
const tokens = useAppDesignTokens();
|
|
42
|
-
|
|
42
|
+
const { getFontSize, iconContainerSize } = useResponsive();
|
|
43
|
+
|
|
43
44
|
const finalPrimaryColor = primaryColor || tokens.colors.primary;
|
|
44
45
|
const finalBackgroundColor = backgroundColor || tokens.colors.surface;
|
|
45
46
|
const finalTextColor = textColor || tokens.colors.textPrimary;
|
|
46
47
|
const finalSubtextColor = subtextColor || tokens.colors.textSecondary;
|
|
47
48
|
|
|
48
49
|
const renderedIcon = typeof icon === 'string' ? (
|
|
49
|
-
<AtomicIcon name={icon} size="
|
|
50
|
-
) : icon || <AtomicIcon name="
|
|
50
|
+
<AtomicIcon name={icon} size="lg" customColor={finalPrimaryColor} />
|
|
51
|
+
) : icon || <AtomicIcon name="trending-up" size="lg" customColor={finalPrimaryColor} />;
|
|
52
|
+
|
|
53
|
+
const numberFontSize = getFontSize(36);
|
|
54
|
+
const labelFontSize = getFontSize(11);
|
|
55
|
+
const currentLabelFontSize = getFontSize(15);
|
|
56
|
+
const bestNumberFontSize = getFontSize(24);
|
|
57
|
+
const bestLabelFontSize = getFontSize(10);
|
|
51
58
|
|
|
52
59
|
return (
|
|
53
|
-
<View style={[
|
|
60
|
+
<View style={[
|
|
61
|
+
styles.container,
|
|
62
|
+
{
|
|
63
|
+
backgroundColor: finalBackgroundColor,
|
|
64
|
+
borderRadius: tokens.borders.radius.lg,
|
|
65
|
+
padding: tokens.spacing.lg,
|
|
66
|
+
},
|
|
67
|
+
containerStyle
|
|
68
|
+
]}>
|
|
54
69
|
<View style={styles.mainStreak}>
|
|
55
|
-
<View style={styles.iconContainer
|
|
56
|
-
|
|
57
|
-
|
|
70
|
+
<View style={[styles.iconContainer, { width: iconContainerSize, height: iconContainerSize }]}>
|
|
71
|
+
{renderedIcon}
|
|
72
|
+
</View>
|
|
73
|
+
<View style={[styles.streakInfo, { minWidth: iconContainerSize + 12 }]}>
|
|
74
|
+
<AtomicText style={[
|
|
75
|
+
styles.number,
|
|
76
|
+
{
|
|
77
|
+
color: finalPrimaryColor,
|
|
78
|
+
fontSize: numberFontSize,
|
|
79
|
+
lineHeight: numberFontSize + 4,
|
|
80
|
+
minHeight: numberFontSize + 4,
|
|
81
|
+
},
|
|
82
|
+
numberStyle
|
|
83
|
+
]}>
|
|
58
84
|
{current}
|
|
59
85
|
</AtomicText>
|
|
60
|
-
<AtomicText style={[
|
|
86
|
+
<AtomicText style={[
|
|
87
|
+
styles.label,
|
|
88
|
+
{
|
|
89
|
+
color: finalSubtextColor,
|
|
90
|
+
fontSize: labelFontSize,
|
|
91
|
+
marginTop: tokens.spacing.xs,
|
|
92
|
+
},
|
|
93
|
+
labelStyle
|
|
94
|
+
]}>
|
|
61
95
|
{daysLabel}
|
|
62
96
|
</AtomicText>
|
|
63
97
|
</View>
|
|
64
|
-
<AtomicText style={[
|
|
98
|
+
<AtomicText style={[
|
|
99
|
+
styles.currentLabel,
|
|
100
|
+
{
|
|
101
|
+
color: finalTextColor,
|
|
102
|
+
fontSize: currentLabelFontSize,
|
|
103
|
+
}
|
|
104
|
+
]}>
|
|
65
105
|
{currentLabel}
|
|
66
106
|
</AtomicText>
|
|
67
107
|
</View>
|
|
68
108
|
|
|
69
|
-
<View style={[
|
|
70
|
-
|
|
109
|
+
<View style={[
|
|
110
|
+
styles.bestStreak,
|
|
111
|
+
{
|
|
112
|
+
backgroundColor: withAlpha(finalPrimaryColor, 0.2),
|
|
113
|
+
paddingHorizontal: tokens.spacing.md,
|
|
114
|
+
paddingVertical: tokens.spacing.sm,
|
|
115
|
+
borderRadius: tokens.borders.radius.md,
|
|
116
|
+
minWidth: 80,
|
|
117
|
+
}
|
|
118
|
+
]}>
|
|
119
|
+
<AtomicText style={[
|
|
120
|
+
styles.bestLabel,
|
|
121
|
+
{
|
|
122
|
+
color: finalSubtextColor,
|
|
123
|
+
fontSize: bestLabelFontSize,
|
|
124
|
+
}
|
|
125
|
+
]}>
|
|
71
126
|
{bestLabel}
|
|
72
127
|
</AtomicText>
|
|
73
|
-
<AtomicText style={[
|
|
128
|
+
<AtomicText style={[
|
|
129
|
+
styles.bestNumber,
|
|
130
|
+
{
|
|
131
|
+
color: finalPrimaryColor,
|
|
132
|
+
fontSize: bestNumberFontSize,
|
|
133
|
+
lineHeight: bestNumberFontSize + 4,
|
|
134
|
+
minHeight: bestNumberFontSize + 4,
|
|
135
|
+
marginTop: tokens.spacing.xs,
|
|
136
|
+
}
|
|
137
|
+
]}>
|
|
74
138
|
{longest}
|
|
75
139
|
</AtomicText>
|
|
76
140
|
</View>
|
|
@@ -80,8 +144,6 @@ export const StreakDisplay: React.FC<StreakDisplayProps> = ({
|
|
|
80
144
|
|
|
81
145
|
const styles = StyleSheet.create({
|
|
82
146
|
container: {
|
|
83
|
-
borderRadius: 16,
|
|
84
|
-
padding: 16,
|
|
85
147
|
flexDirection: "row",
|
|
86
148
|
alignItems: "center",
|
|
87
149
|
justifyContent: "space-between",
|
|
@@ -90,10 +152,9 @@ const styles = StyleSheet.create({
|
|
|
90
152
|
flexDirection: "row",
|
|
91
153
|
alignItems: "center",
|
|
92
154
|
gap: 12,
|
|
155
|
+
flex: 1,
|
|
93
156
|
},
|
|
94
157
|
iconContainer: {
|
|
95
|
-
width: 40,
|
|
96
|
-
height: 40,
|
|
97
158
|
justifyContent: "center",
|
|
98
159
|
alignItems: "center",
|
|
99
160
|
},
|
|
@@ -101,29 +162,22 @@ const styles = StyleSheet.create({
|
|
|
101
162
|
alignItems: "center",
|
|
102
163
|
},
|
|
103
164
|
number: {
|
|
104
|
-
fontSize: 32,
|
|
105
165
|
fontWeight: "bold",
|
|
106
166
|
},
|
|
107
167
|
label: {
|
|
108
|
-
fontSize: 12,
|
|
109
168
|
textTransform: "uppercase",
|
|
110
169
|
},
|
|
111
170
|
currentLabel: {
|
|
112
|
-
|
|
113
|
-
fontWeight: "500",
|
|
171
|
+
fontWeight: "600",
|
|
114
172
|
},
|
|
115
173
|
bestStreak: {
|
|
116
|
-
paddingHorizontal: 12,
|
|
117
|
-
paddingVertical: 8,
|
|
118
|
-
borderRadius: 12,
|
|
119
174
|
alignItems: "center",
|
|
120
175
|
},
|
|
121
176
|
bestLabel: {
|
|
122
|
-
fontSize: 11,
|
|
123
177
|
textTransform: "uppercase",
|
|
178
|
+
fontWeight: "600",
|
|
124
179
|
},
|
|
125
180
|
bestNumber: {
|
|
126
|
-
fontSize: 18,
|
|
127
181
|
fontWeight: "bold",
|
|
128
182
|
},
|
|
129
183
|
});
|