[READ ONLY MIRROR] Open Source TikTok alternative built on AT Protocol github.com/sprksocial/client
flutter atproto video dart
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

Updates on profile page

C3B e06d61e9 2e5adede

+185 -54
+46 -50
app/(tabs)/ProfileScreen.tsx
··· 63 63 const colorScheme = useColorScheme(); 64 64 const route = useRouter(); 65 65 66 - // Ajuste aqui para os cenários que você quer simular: 67 - // - isLoggedIn = true/false 68 - // - isMine = true/false 69 - const isLoggedIn = true; // Se está logado ou não 70 - const isMine = true; // Se a conta do perfil atual é minha 66 + const isLoggedIn = true; 67 + const isMine = !true; 71 68 72 69 const [userData, setUserData] = useState<UserProps | null>(null); 73 70 const [videoPosts, setVideoPosts] = useState<PostProps[]>([]); 71 + 72 + const loadVideoPosts = async () => { 73 + try { 74 + const mediaPosts = await getProfileMedia(did, 'video'); 75 + const posts = mediaPosts.map((item: any) => item.post); 76 + setVideoPosts(posts); 77 + } catch (error) { 78 + console.error('Error loading video posts:', error); 79 + } 80 + }; 74 81 75 82 useEffect(() => { 76 - if (isLoggedIn) { 77 - // Carrega dados de um perfil "real" 83 + // When user is logged in OR (user is not logged in but viewing someone else's profile) 84 + if (isLoggedIn || (!isLoggedIn && !isMine)) { 78 85 const loadProfileData = async () => { 79 86 try { 80 87 const profileData = await getProfile(did); ··· 103 110 console.error('Error loading profile:', error); 104 111 } 105 112 }; 106 - const loadVideoPosts = async () => { 107 - try { 108 - const mediaPosts = await getProfileMedia(did, 'video'); 109 - const posts = mediaPosts.map((item: PostProps) => item as PostProps); 110 - setVideoPosts(posts); 111 - } catch (error) { 112 - console.error('Error loading video posts:', error); 113 - } 114 - }; 113 + 115 114 loadProfileData(); 116 115 loadVideoPosts(); 117 - } else { 118 - // Se não está logado, crie um "stub" de userData 116 + } else if (!isLoggedIn && isMine) { 117 + // When user is not logged in and viewing their own profile 119 118 setUserData({ 120 119 id: '', 121 120 did: '', ··· 132 131 labels: [], 133 132 }); 134 133 } 135 - }, [isLoggedIn]); 134 + }, [isLoggedIn, isMine]); 136 135 137 136 const paddedVideoData = padVideosWithPlaceholders(videoPosts); 138 137 ··· 261 260 {userData && <ProfilePicture userData={userData} />} 262 261 {userData && <ProfileInfo userData={userData} />} 263 262 264 - {/* 265 - 4 CASOS (botões de ação): 266 - 267 - 1) [logado && minha conta]: Editar / Compartilhar 268 - 2) [logado && não é minha conta]: Seguir 269 - 3) [não logado && não é minha conta]: Perfil + Botão "Seguir" (redireciona para login) 270 - 4) [não logado && é minha conta]: Botões de "Login" / "Registrar" 271 - */} 263 + 272 264 { 273 265 !isLoggedIn && isMine && ( 274 - // Não logado, mas é minha conta => mostrar Login / Register 266 + // Not logged in and viewing own profile => show Login / Register buttons 275 267 <View style={styles.profileActionButtonsVertical}> 276 268 <ActionButton 277 269 type="primary" ··· 290 282 } 291 283 { 292 284 !isLoggedIn && !isMine && ( 293 - // Não logado e não é minha conta => mostrar "Seguir" (redireciona pra login) 285 + // Not logged in and viewing someone else's profile => show "Follow" (redirects to login) 294 286 <ActionButton 295 287 type="primary" 296 288 title="Follow" ··· 301 293 } 302 294 { 303 295 isLoggedIn && !isMine && ( 304 - // Logado, mas não é minha conta => mostrar "Seguir" 296 + // Logged in and viewing someone else's profile => show "Follow" with function 305 297 <ActionButton 306 298 type="primary" 307 299 title="Follow" 308 300 onPress={() => { 309 - // Lógica real de seguir aqui 310 - console.log("Seguiu este perfil"); 301 + // Follow logic here 302 + console.log("followed " + userData?.did); 311 303 }} 312 304 width={250} 313 305 /> ··· 315 307 } 316 308 { 317 309 isLoggedIn && isMine && ( 318 - // Logado e é minha conta => mostrar editar e compartilhar 310 + // Logged in and viewing own profile => show edit and share buttons 319 311 <View style={styles.profileActionButtons}> 320 312 <ActionButton 321 313 type="secondary" ··· 342 334 343 335 {/* Tabs (Ex: Videos e Fotos) */} 344 336 <View style={styles.profileContent}> 337 + {/* Show tabs for everyone except when not logged in and viewing own profile */} 338 + { (isLoggedIn || (!isLoggedIn && !isMine)) && 345 339 <View style={styles.profileTabs}> 346 340 <View style={styles.tabButton}> 347 341 <Ionicons ··· 372 366 </ThemedText> 373 367 </View> 374 368 </View> 375 - 376 - {/* Grid de vídeos */} 377 - <View style={styles.videoGrid}> 378 - {paddedVideoData.map((item, index) => { 379 - const key = item.uri ? item.uri : `fallback-${index}`; 369 + } 370 + {/* Grid de vídeos - Only show when logged in or viewing someone else's profile */} 371 + { (isLoggedIn || (!isLoggedIn && !isMine)) && 372 + <View style={styles.videoGrid}> 373 + {paddedVideoData.map((item, index) => { 374 + const key = item.uri ? item.uri : `fallback-${index}`; 380 375 381 - if (item.isPlaceholder) { 382 - return <PlaceholderVideoDisplay key={key} />; 383 - } 384 - return ( 385 - <VideoDisplay 386 - key={key} 387 - videoSource={item} 388 - onVideoPress={handleOpenProfileFeed} 389 - /> 390 - ); 391 - })} 392 - </View> 376 + if (item.isPlaceholder) { 377 + return <PlaceholderVideoDisplay key={key} />; 378 + } 379 + return ( 380 + <VideoDisplay 381 + key={key} 382 + videoSource={item} 383 + onVideoPress={handleOpenProfileFeed} 384 + /> 385 + ); 386 + })} 387 + </View> 388 + } 393 389 </View> 394 390 </ScrollView> 395 391 </ContentWrapper>
+132
package-lock.json
··· 8 8 "name": "spark-social-app", 9 9 "version": "1.0.0", 10 10 "dependencies": { 11 + "@atproto/api": "^0.14.7", 11 12 "@expo/vector-icons": "^14.0.2", 12 13 "@gorhom/bottom-sheet": "^5.1.1", 13 14 "@react-native-community/datetimepicker": "8.2.0", ··· 23 24 "expo-constants": "~17.0.4", 24 25 "expo-font": "~13.0.3", 25 26 "expo-haptics": "~14.0.1", 27 + "expo-image-picker": "~16.0.6", 26 28 "expo-linear-gradient": "~14.0.2", 27 29 "expo-linking": "~7.0.4", 28 30 "expo-media-library": "~17.0.5", ··· 37 39 "react-dom": "18.3.1", 38 40 "react-native": "0.76.6", 39 41 "react-native-gesture-handler": "~2.20.2", 42 + "react-native-imglysdk": "^3.3.0", 40 43 "react-native-reanimated": "~3.16.1", 41 44 "react-native-safe-area-context": "4.12.0", 42 45 "react-native-screens": "~4.4.0", ··· 80 83 }, 81 84 "engines": { 82 85 "node": ">=6.0.0" 86 + } 87 + }, 88 + "node_modules/@atproto/api": { 89 + "version": "0.14.7", 90 + "resolved": "https://registry.npmjs.org/@atproto/api/-/api-0.14.7.tgz", 91 + "integrity": "sha512-YG2kvAtsgtajLlLrorYuHcxGgepG0c/RUB2/iJyBnwKjGqDLG8joOETf38JSNiGzs6NJbNKa9NHG6BQKourxBA==", 92 + "license": "MIT", 93 + "dependencies": { 94 + "@atproto/common-web": "^0.4.0", 95 + "@atproto/lexicon": "^0.4.7", 96 + "@atproto/syntax": "^0.3.3", 97 + "@atproto/xrpc": "^0.6.9", 98 + "await-lock": "^2.2.2", 99 + "multiformats": "^9.9.0", 100 + "tlds": "^1.234.0", 101 + "zod": "^3.23.8" 102 + } 103 + }, 104 + "node_modules/@atproto/common-web": { 105 + "version": "0.4.0", 106 + "resolved": "https://registry.npmjs.org/@atproto/common-web/-/common-web-0.4.0.tgz", 107 + "integrity": "sha512-ZYL0P9myHybNgwh/hBY0HaBzqiLR1B5/ie5bJpLQAg0whRzNA28t8/nU2vh99tbsWcAF0LOD29M8++LyENJLNQ==", 108 + "license": "MIT", 109 + "dependencies": { 110 + "graphemer": "^1.4.0", 111 + "multiformats": "^9.9.0", 112 + "uint8arrays": "3.0.0", 113 + "zod": "^3.23.8" 114 + } 115 + }, 116 + "node_modules/@atproto/lexicon": { 117 + "version": "0.4.7", 118 + "resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.4.7.tgz", 119 + "integrity": "sha512-/x6h3tAiDNzSi4eXtC8ke65B7UzsagtlGRHmUD95698x5lBRpDnpizj0fZWTZVYed5qnOmz/ZEue+v3wDmO61g==", 120 + "license": "MIT", 121 + "dependencies": { 122 + "@atproto/common-web": "^0.4.0", 123 + "@atproto/syntax": "^0.3.3", 124 + "iso-datestring-validator": "^2.2.2", 125 + "multiformats": "^9.9.0", 126 + "zod": "^3.23.8" 127 + } 128 + }, 129 + "node_modules/@atproto/syntax": { 130 + "version": "0.3.3", 131 + "resolved": "https://registry.npmjs.org/@atproto/syntax/-/syntax-0.3.3.tgz", 132 + "integrity": "sha512-F1LZweesNYdBbZBXVa72N/cSvchG8Q1tG4/209ZXbIuM3FwQtkgn+zgmmV4P4ORmhOeXPBNXvMBpcqiwx/gEQQ==", 133 + "license": "MIT" 134 + }, 135 + "node_modules/@atproto/xrpc": { 136 + "version": "0.6.9", 137 + "resolved": "https://registry.npmjs.org/@atproto/xrpc/-/xrpc-0.6.9.tgz", 138 + "integrity": "sha512-vQGA7++DYMNaHx3C7vEjT+2X6hYYLG7JNbBnDLWu0km1/1KYXgRkAz4h+FfYqg1mvzvIorHU7DAs5wevkJDDlw==", 139 + "license": "MIT", 140 + "dependencies": { 141 + "@atproto/lexicon": "^0.4.7", 142 + "zod": "^3.23.8" 83 143 } 84 144 }, 85 145 "node_modules/@babel/code-frame": { ··· 4693 4753 "funding": { 4694 4754 "url": "https://github.com/sponsors/ljharb" 4695 4755 } 4756 + }, 4757 + "node_modules/await-lock": { 4758 + "version": "2.2.2", 4759 + "resolved": "https://registry.npmjs.org/await-lock/-/await-lock-2.2.2.tgz", 4760 + "integrity": "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==", 4761 + "license": "MIT" 4696 4762 }, 4697 4763 "node_modules/babel-core": { 4698 4764 "version": "7.0.0-bridge.0", ··· 6715 6781 "expo": "*" 6716 6782 } 6717 6783 }, 6784 + "node_modules/expo-image-loader": { 6785 + "version": "5.0.0", 6786 + "resolved": "https://registry.npmjs.org/expo-image-loader/-/expo-image-loader-5.0.0.tgz", 6787 + "integrity": "sha512-Eg+5FHtyzv3Jjw9dHwu2pWy4xjf8fu3V0Asyy42kO+t/FbvW/vjUixpTjPtgKQLQh+2/9Nk4JjFDV6FwCnF2ZA==", 6788 + "license": "MIT", 6789 + "peerDependencies": { 6790 + "expo": "*" 6791 + } 6792 + }, 6793 + "node_modules/expo-image-picker": { 6794 + "version": "16.0.6", 6795 + "resolved": "https://registry.npmjs.org/expo-image-picker/-/expo-image-picker-16.0.6.tgz", 6796 + "integrity": "sha512-HN4xZirFjsFDIsWFb12AZh19fRzuvZjj2ll17cGr19VNRP06S/VPQU3Tdccn5vwUzQhOBlLu704CnNm278boiQ==", 6797 + "license": "MIT", 6798 + "dependencies": { 6799 + "expo-image-loader": "~5.0.0" 6800 + }, 6801 + "peerDependencies": { 6802 + "expo": "*" 6803 + } 6804 + }, 6718 6805 "node_modules/expo-keep-awake": { 6719 6806 "version": "14.0.2", 6720 6807 "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-14.0.2.tgz", ··· 7507 7594 "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", 7508 7595 "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" 7509 7596 }, 7597 + "node_modules/graphemer": { 7598 + "version": "1.4.0", 7599 + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", 7600 + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", 7601 + "license": "MIT" 7602 + }, 7510 7603 "node_modules/has-flag": { 7511 7604 "version": "4.0.0", 7512 7605 "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", ··· 8083 8176 "version": "2.0.0", 8084 8177 "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 8085 8178 "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" 8179 + }, 8180 + "node_modules/iso-datestring-validator": { 8181 + "version": "2.2.2", 8182 + "resolved": "https://registry.npmjs.org/iso-datestring-validator/-/iso-datestring-validator-2.2.2.tgz", 8183 + "integrity": "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==", 8184 + "license": "MIT" 8086 8185 }, 8087 8186 "node_modules/isobject": { 8088 8187 "version": "3.0.1", ··· 10368 10467 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 10369 10468 "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 10370 10469 }, 10470 + "node_modules/multiformats": { 10471 + "version": "9.9.0", 10472 + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", 10473 + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", 10474 + "license": "(Apache-2.0 AND MIT)" 10475 + }, 10371 10476 "node_modules/mz": { 10372 10477 "version": "2.7.0", 10373 10478 "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", ··· 13272 13377 "xtend": "~4.0.1" 13273 13378 } 13274 13379 }, 13380 + "node_modules/tlds": { 13381 + "version": "1.256.0", 13382 + "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.256.0.tgz", 13383 + "integrity": "sha512-ZmyVB9DAw+FFTmLElGYJgdZFsKLYd/I59Bg9NHkCGPwAbVZNRilFWDMAdX8UG+bHuv7kfursd5XGqo/9wi26lA==", 13384 + "license": "MIT", 13385 + "bin": { 13386 + "tlds": "bin.js" 13387 + } 13388 + }, 13275 13389 "node_modules/tmp": { 13276 13390 "version": "0.0.33", 13277 13391 "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", ··· 13413 13527 }, 13414 13528 "engines": { 13415 13529 "node": "*" 13530 + } 13531 + }, 13532 + "node_modules/uint8arrays": { 13533 + "version": "3.0.0", 13534 + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.0.0.tgz", 13535 + "integrity": "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==", 13536 + "license": "MIT", 13537 + "dependencies": { 13538 + "multiformats": "^9.4.2" 13416 13539 } 13417 13540 }, 13418 13541 "node_modules/undici": { ··· 14207 14330 }, 14208 14331 "funding": { 14209 14332 "url": "https://github.com/sponsors/sindresorhus" 14333 + } 14334 + }, 14335 + "node_modules/zod": { 14336 + "version": "3.24.2", 14337 + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", 14338 + "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", 14339 + "license": "MIT", 14340 + "funding": { 14341 + "url": "https://github.com/sponsors/colinhacks" 14210 14342 } 14211 14343 } 14212 14344 }
+7 -4
package.json
··· 15 15 "preset": "jest-expo" 16 16 }, 17 17 "dependencies": { 18 + "@atproto/api": "^0.14.7", 18 19 "@expo/vector-icons": "^14.0.2", 19 20 "@gorhom/bottom-sheet": "^5.1.1", 21 + "@react-native-community/datetimepicker": "8.2.0", 22 + "@react-native-community/slider": "4.5.5", 20 23 "@react-navigation/bottom-tabs": "^7.2.0", 21 24 "@react-navigation/drawer": "^7.1.1", 22 25 "@react-navigation/native": "^7.0.14", ··· 28 31 "expo-constants": "~17.0.4", 29 32 "expo-font": "~13.0.3", 30 33 "expo-haptics": "~14.0.1", 34 + "expo-image-picker": "~16.0.6", 31 35 "expo-linear-gradient": "~14.0.2", 32 36 "expo-linking": "~7.0.4", 33 37 "expo-media-library": "~17.0.5", ··· 42 46 "react-dom": "18.3.1", 43 47 "react-native": "0.76.6", 44 48 "react-native-gesture-handler": "~2.20.2", 49 + "react-native-imglysdk": "^3.3.0", 45 50 "react-native-reanimated": "~3.16.1", 46 51 "react-native-safe-area-context": "4.12.0", 47 52 "react-native-screens": "~4.4.0", 53 + "react-native-svg": "15.8.0", 48 54 "react-native-video": "^6.10.0", 49 55 "react-native-videoeditorsdk": "^3.3.0", 50 56 "react-native-web": "~0.19.13", 51 - "react-native-webview": "13.12.5", 52 - "@react-native-community/slider": "4.5.5", 53 - "react-native-svg": "15.8.0", 54 - "@react-native-community/datetimepicker": "8.2.0" 57 + "react-native-webview": "13.12.5" 55 58 }, 56 59 "devDependencies": { 57 60 "@babel/core": "^7.25.2",