@umituz/react-native-settings 5.4.25 → 5.4.27
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": "5.4.
|
|
3
|
+
"version": "5.4.27",
|
|
4
4
|
"description": "Complete settings hub for React Native apps - consolidated package with settings, localization, about, legal, appearance, feedback, FAQs, rating, and gamification - expo-store-review and expo-device now lazy loaded",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import React, { useMemo, useCallback } from 'react';
|
|
8
|
-
import { View, StyleSheet, ViewStyle, TextStyle,
|
|
9
|
-
import { getContentMaxWidth } from '@umituz/react-native-design-system/device';
|
|
8
|
+
import { View, StyleSheet, ViewStyle, TextStyle, FlatList } from 'react-native';
|
|
10
9
|
import { ScreenLayout } from '@umituz/react-native-design-system/layouts';
|
|
11
10
|
import { NavigationHeader, useAppNavigation } from '@umituz/react-native-design-system/molecules';
|
|
12
11
|
import { useAppDesignTokens } from '@umituz/react-native-design-system/theme';
|
|
12
|
+
import { useResponsive } from '@umituz/react-native-design-system/responsive';
|
|
13
13
|
import { FAQCategory } from '../../domain/entities/FAQEntity';
|
|
14
14
|
import { useFAQSearch } from '../hooks/useFAQSearch';
|
|
15
15
|
import { useFAQExpansion } from '../hooks/useFAQExpansion';
|
|
@@ -50,8 +50,7 @@ export const FAQScreen: React.FC<FAQScreenProps> = ({
|
|
|
50
50
|
}) => {
|
|
51
51
|
const navigation = useAppNavigation();
|
|
52
52
|
const tokens = useAppDesignTokens();
|
|
53
|
-
const
|
|
54
|
-
const contentMaxWidth = useMemo(() => getContentMaxWidth(windowWidth), [windowWidth]);
|
|
53
|
+
const responsive = useResponsive();
|
|
55
54
|
const { searchQuery, setSearchQuery, filteredCategories, hasResults } = useFAQSearch(categories);
|
|
56
55
|
const { isExpanded, toggleExpansion } = useFAQExpansion();
|
|
57
56
|
|
|
@@ -82,7 +81,7 @@ export const FAQScreen: React.FC<FAQScreenProps> = ({
|
|
|
82
81
|
|
|
83
82
|
// Render search bar as list header
|
|
84
83
|
const ListHeader = useMemo(() => (
|
|
85
|
-
<View style={{ alignSelf: 'center', width: '100%', maxWidth:
|
|
84
|
+
<View style={{ alignSelf: 'center', width: '100%', maxWidth: responsive.maxContentWidth }}>
|
|
86
85
|
<View style={[styles.searchBar, customStyles?.header]}>
|
|
87
86
|
<FAQSearchBar
|
|
88
87
|
value={searchQuery}
|
|
@@ -100,10 +99,10 @@ export const FAQScreen: React.FC<FAQScreenProps> = ({
|
|
|
100
99
|
/>
|
|
101
100
|
)}
|
|
102
101
|
</View>
|
|
103
|
-
), [searchQuery, hasResults, searchPlaceholder, emptySearchTitle, emptySearchMessage, customStyles, tokens,
|
|
102
|
+
), [searchQuery, hasResults, searchPlaceholder, emptySearchTitle, emptySearchMessage, customStyles, tokens, responsive.maxContentWidth]);
|
|
104
103
|
|
|
105
104
|
const renderCategory = useCallback(({ item }: { item: FAQCategory }) => (
|
|
106
|
-
<View style={{ alignSelf: 'center', width: '100%', maxWidth:
|
|
105
|
+
<View style={{ alignSelf: 'center', width: '100%', maxWidth: responsive.maxContentWidth }}>
|
|
107
106
|
<FAQCategoryComponent
|
|
108
107
|
category={item}
|
|
109
108
|
isExpanded={isExpanded}
|
|
@@ -111,7 +110,7 @@ export const FAQScreen: React.FC<FAQScreenProps> = ({
|
|
|
111
110
|
styles={customStyles?.category}
|
|
112
111
|
/>
|
|
113
112
|
</View>
|
|
114
|
-
), [
|
|
113
|
+
), [responsive.maxContentWidth, isExpanded, toggleExpansion, customStyles?.category]);
|
|
115
114
|
|
|
116
115
|
return (
|
|
117
116
|
<ScreenLayout
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
AtomicIcon,
|
|
12
12
|
} from "@umituz/react-native-design-system/atoms";
|
|
13
13
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
14
|
+
import { useResponsive } from "@umituz/react-native-design-system/responsive";
|
|
14
15
|
import { useAppNavigation } from "@umituz/react-native-design-system/molecules";
|
|
15
16
|
import { ScreenLayout } from "@umituz/react-native-design-system/layouts";
|
|
16
17
|
import { ICON_PATHS } from "../../../../utils/iconPaths";
|
|
@@ -28,6 +29,7 @@ interface FeatureRequestScreenProps {
|
|
|
28
29
|
|
|
29
30
|
export const FeatureRequestScreen: React.FC<FeatureRequestScreenProps> = ({ config, texts }) => {
|
|
30
31
|
const tokens = useAppDesignTokens();
|
|
32
|
+
const responsive = useResponsive();
|
|
31
33
|
const navigation = useAppNavigation();
|
|
32
34
|
const { requests, userVotes, isLoading, vote, submitRequest: _submitRequest, userId } = useFeatureRequests();
|
|
33
35
|
|
|
@@ -130,6 +132,41 @@ export const FeatureRequestScreen: React.FC<FeatureRequestScreenProps> = ({ conf
|
|
|
130
132
|
|
|
131
133
|
const tabs = useMemo(() => (['all', 'my', 'roadmap'] as const), []);
|
|
132
134
|
|
|
135
|
+
const styles = useMemo(() => StyleSheet.create({
|
|
136
|
+
container: { padding: responsive.horizontalPadding },
|
|
137
|
+
header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingHorizontal: responsive.horizontalPadding, paddingVertical: responsive.verticalPadding },
|
|
138
|
+
headerTitle: { fontSize: responsive.getFontSize(20), fontWeight: '800' },
|
|
139
|
+
addButton: { width: 36, height: 36, borderRadius: 12, alignItems: 'center', justifyContent: 'center' },
|
|
140
|
+
tabsContainer: { flexDirection: 'row', paddingHorizontal: responsive.horizontalPadding, borderBottomWidth: 1, borderBottomColor: 'rgba(255,255,255,0.05)' },
|
|
141
|
+
tab: { paddingVertical: responsive.verticalPadding, paddingHorizontal: responsive.horizontalPadding, borderBottomWidth: 2, borderBottomColor: 'transparent' },
|
|
142
|
+
tabLabel: { fontSize: responsive.getFontSize(14), fontWeight: '600', color: 'rgba(255,255,255,0.5)' },
|
|
143
|
+
banner: { flexDirection: 'row', alignItems: 'center', padding: responsive.horizontalPadding, borderRadius: 16, borderWidth: 1, gap: 12, marginBottom: responsive.verticalPadding },
|
|
144
|
+
bannerIconContainer: { position: 'relative' },
|
|
145
|
+
pulseDot: { position: 'absolute', top: 0, right: 0, width: 8, height: 8, borderRadius: 4, backgroundColor: '#10b981' },
|
|
146
|
+
bannerTitle: { fontSize: responsive.getFontSize(14), fontWeight: '700' },
|
|
147
|
+
bannerSub: { fontSize: responsive.getFontSize(12) },
|
|
148
|
+
sectionTitle: { fontSize: responsive.getFontSize(18), fontWeight: '700', marginBottom: responsive.horizontalPadding },
|
|
149
|
+
listContent: { gap: responsive.horizontalPadding, paddingBottom: responsive.verticalPadding * 2 },
|
|
150
|
+
card: { flexDirection: 'row', padding: responsive.horizontalPadding, borderRadius: 16, borderWidth: 1, gap: 12 },
|
|
151
|
+
voteColumn: { alignItems: 'center', gap: 4, width: 40 },
|
|
152
|
+
voteCount: { fontSize: responsive.getFontSize(13), fontWeight: '800' },
|
|
153
|
+
cardContent: { flex: 1, gap: 8 },
|
|
154
|
+
cardHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-start', gap: 8 },
|
|
155
|
+
cardTitle: { fontSize: responsive.getFontSize(15), fontWeight: '700', flex: 1 },
|
|
156
|
+
statusBadge: { paddingHorizontal: 8, paddingVertical: 2, borderRadius: 8, borderWidth: 1 },
|
|
157
|
+
statusText: { fontSize: responsive.getFontSize(9), fontWeight: '900' },
|
|
158
|
+
cardDescription: { fontSize: responsive.getFontSize(13), lineHeight: 18 },
|
|
159
|
+
cardFooter: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginTop: 4 },
|
|
160
|
+
platformText: { fontSize: responsive.getFontSize(10), fontWeight: '600' },
|
|
161
|
+
commentCount: { fontSize: responsive.getFontSize(11) },
|
|
162
|
+
floatingHint: { position: 'absolute', bottom: 40, right: responsive.horizontalPadding, zIndex: 100 },
|
|
163
|
+
hintBadge: { paddingHorizontal: 12, paddingVertical: 6, borderRadius: 20, shadowColor: '#000', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.3, shadowRadius: 4, elevation: 8 },
|
|
164
|
+
hintText: { color: '#fff', fontSize: responsive.getFontSize(10), fontWeight: '900', textTransform: 'uppercase' },
|
|
165
|
+
loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', paddingTop: 100 },
|
|
166
|
+
emptyState: { alignItems: 'center', justifyContent: 'center', paddingVertical: 60, gap: 12 },
|
|
167
|
+
emptyText: { fontSize: responsive.getFontSize(14), fontWeight: '500' },
|
|
168
|
+
}), [responsive.horizontalPadding, responsive.verticalPadding, responsive.getFontSize]);
|
|
169
|
+
|
|
133
170
|
const header = useMemo(() => (
|
|
134
171
|
<View style={styles.header}>
|
|
135
172
|
<AtomicText style={styles.headerTitle}>{screenTitle}</AtomicText>
|
|
@@ -236,38 +273,3 @@ export const FeatureRequestScreen: React.FC<FeatureRequestScreenProps> = ({ conf
|
|
|
236
273
|
</ScreenLayout>
|
|
237
274
|
);
|
|
238
275
|
};
|
|
239
|
-
|
|
240
|
-
const styles = StyleSheet.create({
|
|
241
|
-
container: { padding: 16 },
|
|
242
|
-
header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingHorizontal: 16, paddingVertical: 12 },
|
|
243
|
-
headerTitle: { fontSize: 20, fontWeight: '800' },
|
|
244
|
-
addButton: { width: 36, height: 36, borderRadius: 12, alignItems: 'center', justifyContent: 'center' },
|
|
245
|
-
tabsContainer: { flexDirection: 'row', paddingHorizontal: 16, borderBottomWidth: 1, borderBottomColor: 'rgba(255,255,255,0.05)' },
|
|
246
|
-
tab: { paddingVertical: 12, paddingHorizontal: 16, borderBottomWidth: 2, borderBottomColor: 'transparent' },
|
|
247
|
-
tabLabel: { fontSize: 14, fontWeight: '600', color: 'rgba(255,255,255,0.5)' },
|
|
248
|
-
banner: { flexDirection: 'row', alignItems: 'center', padding: 16, borderRadius: 16, borderWidth: 1, gap: 12, marginBottom: 20 },
|
|
249
|
-
bannerIconContainer: { position: 'relative' },
|
|
250
|
-
pulseDot: { position: 'absolute', top: 0, right: 0, width: 8, height: 8, borderRadius: 4, backgroundColor: '#10b981' },
|
|
251
|
-
bannerTitle: { fontSize: 14, fontWeight: '700' },
|
|
252
|
-
bannerSub: { fontSize: 12 },
|
|
253
|
-
sectionTitle: { fontSize: 18, fontWeight: '700', marginBottom: 16 },
|
|
254
|
-
listContent: { gap: 12, paddingBottom: 40 },
|
|
255
|
-
card: { flexDirection: 'row', padding: 16, borderRadius: 16, borderWidth: 1, gap: 12 },
|
|
256
|
-
voteColumn: { alignItems: 'center', gap: 4, width: 40 },
|
|
257
|
-
voteCount: { fontSize: 13, fontWeight: '800' },
|
|
258
|
-
cardContent: { flex: 1, gap: 8 },
|
|
259
|
-
cardHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-start', gap: 8 },
|
|
260
|
-
cardTitle: { fontSize: 15, fontWeight: '700', flex: 1 },
|
|
261
|
-
statusBadge: { paddingHorizontal: 8, paddingVertical: 2, borderRadius: 8, borderWidth: 1 },
|
|
262
|
-
statusText: { fontSize: 9, fontWeight: '900' },
|
|
263
|
-
cardDescription: { fontSize: 13, lineHeight: 18 },
|
|
264
|
-
cardFooter: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginTop: 4 },
|
|
265
|
-
platformText: { fontSize: 10, fontWeight: '600' },
|
|
266
|
-
commentCount: { fontSize: 11 },
|
|
267
|
-
floatingHint: { position: 'absolute', bottom: 40, right: 16, zIndex: 100 },
|
|
268
|
-
hintBadge: { paddingHorizontal: 12, paddingVertical: 6, borderRadius: 20, shadowColor: '#000', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.3, shadowRadius: 4, elevation: 8 },
|
|
269
|
-
hintText: { color: '#fff', fontSize: 10, fontWeight: '900', textTransform: 'uppercase' },
|
|
270
|
-
loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', paddingTop: 100 },
|
|
271
|
-
emptyState: { alignItems: 'center', justifyContent: 'center', paddingVertical: 60, gap: 12 },
|
|
272
|
-
emptyText: { fontSize: 14, fontWeight: '500' },
|
|
273
|
-
});
|
|
@@ -7,6 +7,7 @@ import React, { useMemo } from "react";
|
|
|
7
7
|
import { View, Image, StyleSheet, TouchableOpacity } from "react-native";
|
|
8
8
|
import { AtomicText } from "@umituz/react-native-design-system/atoms";
|
|
9
9
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
10
|
+
import { useResponsive } from "@umituz/react-native-design-system/responsive";
|
|
10
11
|
import type { VideoTutorial } from "../../types";
|
|
11
12
|
|
|
12
13
|
const formatDuration = (seconds: number): string => {
|
|
@@ -27,7 +28,8 @@ export const VideoTutorialCard: React.FC<VideoTutorialCardProps> = React.memo(({
|
|
|
27
28
|
horizontal = false,
|
|
28
29
|
}) => {
|
|
29
30
|
const tokens = useAppDesignTokens();
|
|
30
|
-
const
|
|
31
|
+
const responsive = useResponsive();
|
|
32
|
+
const styles = useMemo(() => getStyles(tokens, responsive, horizontal), [tokens, responsive, horizontal]);
|
|
31
33
|
|
|
32
34
|
return (
|
|
33
35
|
<TouchableOpacity
|
|
@@ -86,22 +88,28 @@ export const VideoTutorialCard: React.FC<VideoTutorialCardProps> = React.memo(({
|
|
|
86
88
|
);
|
|
87
89
|
});
|
|
88
90
|
|
|
89
|
-
const getStyles = (tokens: ReturnType<typeof useAppDesignTokens
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
91
|
+
const getStyles = (tokens: ReturnType<typeof useAppDesignTokens>, responsive: ReturnType<typeof useResponsive>, horizontal: boolean) => {
|
|
92
|
+
const horizontalWidth = responsive.isTabletDevice ? 320 : 280;
|
|
93
|
+
const thumbnailHeight = responsive.isTabletDevice ? 200 : 180;
|
|
94
|
+
const horizontalThumbnailHeight = responsive.isTabletDevice ? 160 : 140;
|
|
95
|
+
|
|
96
|
+
return StyleSheet.create({
|
|
97
|
+
container: { borderRadius: 12, borderWidth: 1, marginBottom: responsive.verticalPadding, overflow: "hidden" },
|
|
98
|
+
horizontalContainer: { width: horizontalWidth, marginRight: responsive.horizontalPadding, marginBottom: 0 },
|
|
99
|
+
imageContainer: { position: "relative" },
|
|
100
|
+
thumbnail: { width: "100%", height: thumbnailHeight },
|
|
101
|
+
horizontalThumbnail: { height: horizontalThumbnailHeight },
|
|
102
|
+
durationBadge: { position: "absolute", bottom: 8, right: 8, paddingHorizontal: 6, paddingVertical: 2, borderRadius: 4, backgroundColor: "rgba(0,0,0,0.7)" },
|
|
103
|
+
durationText: { color: tokens.colors.textInverse },
|
|
104
|
+
featuredBadge: { position: "absolute", top: 8, left: 8, paddingHorizontal: 8, paddingVertical: 4, borderRadius: 4 },
|
|
105
|
+
featuredText: { fontWeight: "600" },
|
|
106
|
+
content: { padding: responsive.horizontalPadding },
|
|
107
|
+
title: { fontWeight: "600", marginBottom: 6, color: tokens.colors.textPrimary },
|
|
108
|
+
horizontalTitle: {},
|
|
109
|
+
description: { marginBottom: 8 },
|
|
110
|
+
horizontalDescription: { marginBottom: 6 },
|
|
111
|
+
metadata: { flexDirection: "row", justifyContent: "space-between", alignItems: "center" },
|
|
112
|
+
category: { textTransform: "capitalize", fontWeight: "500" },
|
|
113
|
+
difficulty: { textTransform: "capitalize", fontWeight: "500" },
|
|
114
|
+
});
|
|
115
|
+
};
|