|
1 | | -import { Image } from 'expo-image'; |
2 | | -import { Platform, StyleSheet } from 'react-native'; |
| 1 | +import { ScrollView, StyleSheet, TouchableOpacity, Switch, View } from 'react-native'; |
3 | 2 |
|
4 | | -import { Collapsible } from '@/components/ui/collapsible'; |
5 | | -import { ExternalLink } from '@/components/external-link'; |
6 | | -import ParallaxScrollView from '@/components/parallax-scroll-view'; |
7 | 3 | import { ThemedText } from '@/components/themed-text'; |
8 | 4 | import { ThemedView } from '@/components/themed-view'; |
9 | 5 | import { IconSymbol } from '@/components/ui/icon-symbol'; |
10 | | -import { Fonts } from '@/constants/theme'; |
| 6 | +import { useThemeColor } from '@/hooks/use-theme-color'; |
| 7 | + |
| 8 | +interface ProfileItem { |
| 9 | + id: string; |
| 10 | + title: string; |
| 11 | + icon: string; |
| 12 | + action: string; |
| 13 | + value?: boolean; |
| 14 | + subtitle?: string; |
| 15 | +} |
| 16 | + |
| 17 | +export default function ProfileScreen() { |
| 18 | + const backgroundColor = useThemeColor({}, 'background'); |
| 19 | + const cardBackgroundColor = useThemeColor({ light: '#FFFFFF', dark: '#1C1C1E' }, 'background'); |
| 20 | + const secondaryBackgroundColor = useThemeColor({ light: '#F2F2F7', dark: '#2C2C2E' }, 'background'); |
| 21 | + const textColor = useThemeColor({}, 'text'); |
| 22 | + const tintColor = useThemeColor({}, 'tint'); |
| 23 | + const iconColor = useThemeColor({}, 'icon'); |
| 24 | + |
| 25 | + const profileSections = [ |
| 26 | + { |
| 27 | + title: 'Account', |
| 28 | + items: [ |
| 29 | + { id: '1', title: 'Personal Information', icon: 'person.fill', action: 'chevron.right' }, |
| 30 | + { id: '2', title: 'Security Settings', icon: 'lock.fill', action: 'chevron.right' }, |
| 31 | + { id: '3', title: 'Privacy', icon: 'hand.raised.fill', action: 'chevron.right' }, |
| 32 | + ], |
| 33 | + }, |
| 34 | + { |
| 35 | + title: 'Preferences', |
| 36 | + items: [ |
| 37 | + { id: '4', title: 'Notifications', icon: 'bell.fill', action: 'toggle', value: true }, |
| 38 | + { id: '5', title: 'Dark Mode', icon: 'moon.fill', action: 'toggle', value: false }, |
| 39 | + { id: '6', title: 'Language', icon: 'globe', action: 'chevron.right', subtitle: 'English' }, |
| 40 | + ], |
| 41 | + }, |
| 42 | + { |
| 43 | + title: 'Support', |
| 44 | + items: [ |
| 45 | + { id: '7', title: 'Help Center', icon: 'questionmark.circle.fill', action: 'chevron.right' }, |
| 46 | + { id: '8', title: 'Contact Us', icon: 'message.fill', action: 'chevron.right' }, |
| 47 | + { id: '9', title: 'About', icon: 'info.circle.fill', action: 'chevron.right' }, |
| 48 | + ], |
| 49 | + }, |
| 50 | + ]; |
| 51 | + |
| 52 | + const renderProfileItem = (item: ProfileItem, iconColor: string, textColor: string, secondaryBackgroundColor: string) => ( |
| 53 | + <TouchableOpacity key={item.id} style={styles.profileItem}> |
| 54 | + <View style={styles.itemLeft}> |
| 55 | + <View style={[styles.itemIcon, { backgroundColor: secondaryBackgroundColor }]}> |
| 56 | + <IconSymbol name="chevron.right" size={20} color={tintColor} /> |
| 57 | + </View> |
| 58 | + <View style={styles.itemContent}> |
| 59 | + <ThemedText style={styles.itemTitle}>{item.title}</ThemedText> |
| 60 | + {item.subtitle && ( |
| 61 | + <ThemedText style={[styles.itemSubtitle, { color: textColor, opacity: 0.6 }]}>{item.subtitle}</ThemedText> |
| 62 | + )} |
| 63 | + </View> |
| 64 | + </View> |
| 65 | + {item.action === 'toggle' ? ( |
| 66 | + <Switch value={item.value} onValueChange={() => {}} /> |
| 67 | + ) : ( |
| 68 | + <IconSymbol name={item.action} size={16} color={iconColor} /> |
| 69 | + )} |
| 70 | + </TouchableOpacity> |
| 71 | + ); |
11 | 72 |
|
12 | | -export default function TabTwoScreen() { |
13 | 73 | return ( |
14 | | - <ParallaxScrollView |
15 | | - headerBackgroundColor={{ light: '#D0D0D0', dark: '#353636' }} |
16 | | - headerImage={ |
17 | | - <IconSymbol |
18 | | - size={310} |
19 | | - color="#808080" |
20 | | - name="chevron.left.forwardslash.chevron.right" |
21 | | - style={styles.headerImage} |
22 | | - /> |
23 | | - }> |
24 | | - <ThemedView style={styles.titleContainer}> |
25 | | - <ThemedText |
26 | | - type="title" |
27 | | - style={{ |
28 | | - fontFamily: Fonts.rounded, |
29 | | - }}> |
30 | | - Explore |
31 | | - </ThemedText> |
| 74 | + <ScrollView style={[styles.container, { backgroundColor }]} showsVerticalScrollIndicator={false}> |
| 75 | + {/* Profile Header */} |
| 76 | + <ThemedView style={[styles.header, { backgroundColor: cardBackgroundColor }]}> |
| 77 | + <View style={styles.profileInfo}> |
| 78 | + <View style={styles.avatarContainer}> |
| 79 | + <IconSymbol name="person.circle.fill" size={80} color={tintColor} /> |
| 80 | + <TouchableOpacity style={[styles.editButton, { backgroundColor: tintColor }]}> |
| 81 | + <IconSymbol name="pencil.circle.fill" size={24} color={cardBackgroundColor} /> |
| 82 | + </TouchableOpacity> |
| 83 | + </View> |
| 84 | + <View style={styles.userInfo}> |
| 85 | + <ThemedText type="title" style={styles.userName}>John Doe</ThemedText> |
| 86 | + <ThemedText style={[styles.userEmail, { color: textColor, opacity: 0.7 }]}>[email protected]</ThemedText> |
| 87 | + <ThemedText style={[styles.userStatus, { color: tintColor }]}>Premium Member</ThemedText> |
| 88 | + </View> |
| 89 | + </View> |
32 | 90 | </ThemedView> |
33 | | - <ThemedText>This app includes example code to help you get started.</ThemedText> |
34 | | - <Collapsible title="File-based routing"> |
35 | | - <ThemedText> |
36 | | - This app has two screens:{' '} |
37 | | - <ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> and{' '} |
38 | | - <ThemedText type="defaultSemiBold">app/(tabs)/explore.tsx</ThemedText> |
39 | | - </ThemedText> |
40 | | - <ThemedText> |
41 | | - The layout file in <ThemedText type="defaultSemiBold">app/(tabs)/_layout.tsx</ThemedText>{' '} |
42 | | - sets up the tab navigator. |
43 | | - </ThemedText> |
44 | | - <ExternalLink href="https://docs.expo.dev/router/introduction"> |
45 | | - <ThemedText type="link">Learn more</ThemedText> |
46 | | - </ExternalLink> |
47 | | - </Collapsible> |
48 | | - <Collapsible title="Android, iOS, and web support"> |
49 | | - <ThemedText> |
50 | | - You can open this project on Android, iOS, and the web. To open the web version, press{' '} |
51 | | - <ThemedText type="defaultSemiBold">w</ThemedText> in the terminal running this project. |
52 | | - </ThemedText> |
53 | | - </Collapsible> |
54 | | - <Collapsible title="Images"> |
55 | | - <ThemedText> |
56 | | - For static images, you can use the <ThemedText type="defaultSemiBold">@2x</ThemedText> and{' '} |
57 | | - <ThemedText type="defaultSemiBold">@3x</ThemedText> suffixes to provide files for |
58 | | - different screen densities |
59 | | - </ThemedText> |
60 | | - <Image |
61 | | - source={require('@/assets/images/react-logo.png')} |
62 | | - style={{ width: 100, height: 100, alignSelf: 'center' }} |
63 | | - /> |
64 | | - <ExternalLink href="https://reactnative.dev/docs/images"> |
65 | | - <ThemedText type="link">Learn more</ThemedText> |
66 | | - </ExternalLink> |
67 | | - </Collapsible> |
68 | | - <Collapsible title="Light and dark mode components"> |
69 | | - <ThemedText> |
70 | | - This template has light and dark mode support. The{' '} |
71 | | - <ThemedText type="defaultSemiBold">useColorScheme()</ThemedText> hook lets you inspect |
72 | | - what the user's current color scheme is, and so you can adjust UI colors accordingly. |
73 | | - </ThemedText> |
74 | | - <ExternalLink href="https://docs.expo.dev/develop/user-interface/color-themes/"> |
75 | | - <ThemedText type="link">Learn more</ThemedText> |
76 | | - </ExternalLink> |
77 | | - </Collapsible> |
78 | | - <Collapsible title="Animations"> |
79 | | - <ThemedText> |
80 | | - This template includes an example of an animated component. The{' '} |
81 | | - <ThemedText type="defaultSemiBold">components/HelloWave.tsx</ThemedText> component uses |
82 | | - the powerful{' '} |
83 | | - <ThemedText type="defaultSemiBold" style={{ fontFamily: Fonts.mono }}> |
84 | | - react-native-reanimated |
85 | | - </ThemedText>{' '} |
86 | | - library to create a waving hand animation. |
87 | | - </ThemedText> |
88 | | - {Platform.select({ |
89 | | - ios: ( |
90 | | - <ThemedText> |
91 | | - The <ThemedText type="defaultSemiBold">components/ParallaxScrollView.tsx</ThemedText>{' '} |
92 | | - component provides a parallax effect for the header image. |
93 | | - </ThemedText> |
94 | | - ), |
95 | | - })} |
96 | | - </Collapsible> |
97 | | - </ParallaxScrollView> |
| 91 | + |
| 92 | + {/* Profile Sections */} |
| 93 | + {profileSections.map((section) => ( |
| 94 | + <ThemedView key={section.title} style={styles.section}> |
| 95 | + <ThemedText type="subtitle" style={[styles.sectionTitle, { color: textColor, opacity: 0.7 }]}> |
| 96 | + {section.title} |
| 97 | + </ThemedText> |
| 98 | + <View style={[styles.sectionContent, { backgroundColor: cardBackgroundColor }]}> |
| 99 | + {section.items.map((item) => renderProfileItem(item, iconColor, textColor, secondaryBackgroundColor))} |
| 100 | + </View> |
| 101 | + </ThemedView> |
| 102 | + ))} |
| 103 | + |
| 104 | + {/* Sign Out Button */} |
| 105 | + <TouchableOpacity style={[styles.signOutButton, { backgroundColor: cardBackgroundColor }]}> |
| 106 | + <IconSymbol name="arrow.right.square" size={20} color="#FF3B30" /> |
| 107 | + <ThemedText style={styles.signOutText}>Sign Out</ThemedText> |
| 108 | + </TouchableOpacity> |
| 109 | + |
| 110 | + {/* App Version */} |
| 111 | + <View style={styles.versionContainer}> |
| 112 | + <ThemedText style={styles.versionText}>Version 1.0.0</ThemedText> |
| 113 | + </View> |
| 114 | + </ScrollView> |
98 | 115 | ); |
99 | 116 | } |
100 | 117 |
|
101 | 118 | const styles = StyleSheet.create({ |
102 | | - headerImage: { |
103 | | - color: '#808080', |
104 | | - bottom: -90, |
105 | | - left: -35, |
| 119 | + container: { |
| 120 | + flex: 1, |
| 121 | + }, |
| 122 | + header: { |
| 123 | + paddingTop: 60, |
| 124 | + paddingBottom: 30, |
| 125 | + alignItems: 'center', |
| 126 | + borderBottomLeftRadius: 20, |
| 127 | + borderBottomRightRadius: 20, |
| 128 | + shadowColor: '#000', |
| 129 | + shadowOffset: { width: 0, height: 2 }, |
| 130 | + shadowOpacity: 0.1, |
| 131 | + shadowRadius: 4, |
| 132 | + elevation: 3, |
| 133 | + }, |
| 134 | + profileInfo: { |
| 135 | + alignItems: 'center', |
| 136 | + }, |
| 137 | + avatarContainer: { |
| 138 | + position: 'relative', |
| 139 | + marginBottom: 16, |
| 140 | + }, |
| 141 | + editButton: { |
106 | 142 | position: 'absolute', |
| 143 | + bottom: 0, |
| 144 | + right: 0, |
| 145 | + borderRadius: 12, |
| 146 | + width: 24, |
| 147 | + height: 24, |
| 148 | + justifyContent: 'center', |
| 149 | + alignItems: 'center', |
| 150 | + }, |
| 151 | + userInfo: { |
| 152 | + alignItems: 'center', |
| 153 | + }, |
| 154 | + userName: { |
| 155 | + fontSize: 24, |
| 156 | + fontWeight: 'bold', |
| 157 | + marginBottom: 4, |
| 158 | + }, |
| 159 | + userEmail: { |
| 160 | + fontSize: 16, |
| 161 | + marginBottom: 4, |
107 | 162 | }, |
108 | | - titleContainer: { |
| 163 | + userStatus: { |
| 164 | + fontSize: 14, |
| 165 | + fontWeight: '500', |
| 166 | + }, |
| 167 | + section: { |
| 168 | + marginTop: 24, |
| 169 | + paddingHorizontal: 20, |
| 170 | + }, |
| 171 | + sectionTitle: { |
| 172 | + marginBottom: 12, |
| 173 | + fontSize: 18, |
| 174 | + fontWeight: '600', |
| 175 | + }, |
| 176 | + sectionContent: { |
| 177 | + borderRadius: 12, |
| 178 | + overflow: 'hidden', |
| 179 | + shadowColor: '#000', |
| 180 | + shadowOffset: { width: 0, height: 1 }, |
| 181 | + shadowOpacity: 0.05, |
| 182 | + shadowRadius: 2, |
| 183 | + elevation: 1, |
| 184 | + }, |
| 185 | + profileItem: { |
109 | 186 | flexDirection: 'row', |
110 | | - gap: 8, |
| 187 | + alignItems: 'center', |
| 188 | + justifyContent: 'space-between', |
| 189 | + padding: 16, |
| 190 | + }, |
| 191 | + itemLeft: { |
| 192 | + flexDirection: 'row', |
| 193 | + alignItems: 'center', |
| 194 | + flex: 1, |
| 195 | + }, |
| 196 | + itemIcon: { |
| 197 | + width: 36, |
| 198 | + height: 36, |
| 199 | + borderRadius: 8, |
| 200 | + justifyContent: 'center', |
| 201 | + alignItems: 'center', |
| 202 | + marginRight: 12, |
| 203 | + }, |
| 204 | + itemContent: { |
| 205 | + flex: 1, |
| 206 | + }, |
| 207 | + itemTitle: { |
| 208 | + fontSize: 16, |
| 209 | + fontWeight: '500', |
| 210 | + }, |
| 211 | + itemSubtitle: { |
| 212 | + fontSize: 14, |
| 213 | + marginTop: 2, |
| 214 | + }, |
| 215 | + signOutButton: { |
| 216 | + flexDirection: 'row', |
| 217 | + alignItems: 'center', |
| 218 | + justifyContent: 'center', |
| 219 | + margin: 20, |
| 220 | + marginBottom: 10, |
| 221 | + padding: 16, |
| 222 | + borderRadius: 12, |
| 223 | + shadowColor: '#000', |
| 224 | + shadowOffset: { width: 0, height: 1 }, |
| 225 | + shadowOpacity: 0.05, |
| 226 | + shadowRadius: 2, |
| 227 | + elevation: 1, |
| 228 | + }, |
| 229 | + signOutText: { |
| 230 | + fontSize: 16, |
| 231 | + fontWeight: '500', |
| 232 | + color: '#FF3B30', |
| 233 | + marginLeft: 8, |
| 234 | + }, |
| 235 | + versionContainer: { |
| 236 | + alignItems: 'center', |
| 237 | + paddingBottom: 40, |
| 238 | + }, |
| 239 | + versionText: { |
| 240 | + fontSize: 14, |
| 241 | + opacity: 0.5, |
111 | 242 | }, |
112 | 243 | }); |
0 commit comments