From ef9ea5722bae4becb3d252f0aa901129366fe056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreiro?= Date: Wed, 30 Nov 2022 15:19:58 +0000 Subject: [PATCH 01/17] add editable button profile picture --- src/view/com/profile/ProfileHeader.tsx | 1 + src/view/com/util/UserAvatar.tsx | 47 +++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx index 1b25c7c13c..7a26fa1628 100644 --- a/src/view/com/profile/ProfileHeader.tsx +++ b/src/view/com/profile/ProfileHeader.tsx @@ -156,6 +156,7 @@ export const ProfileHeader = observer(function ProfileHeader({ diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx index 9016cc4cce..f4dc982be3 100644 --- a/src/view/com/util/UserAvatar.tsx +++ b/src/view/com/util/UserAvatar.tsx @@ -1,19 +1,25 @@ -import React from 'react' +import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import React, {useCallback} from 'react' +import {Alert, StyleSheet, View, TouchableOpacity} from 'react-native' import Svg, {Circle, Text, Defs, LinearGradient, Stop} from 'react-native-svg' import {getGradient} from '../../lib/asset-gen' +import {colors} from '../../lib/styles' export function UserAvatar({ + isMe = false, size, - displayName, handle, + displayName, }: { + isMe?: boolean size: number - displayName: string | undefined handle: string + displayName: string | undefined }) { const initials = getInitials(displayName || handle) const gradient = getGradient(handle) - return ( + + const renderSvg = (size: number, initials: string) => ( @@ -33,6 +39,25 @@ export function UserAvatar({ ) + + const handleEditAvatar = useCallback(() => { + Alert.alert('TB Implemented') + }, []) + + return isMe ? ( + + {renderSvg(size, initials)} + + + + + ) : ( + renderSvg(size, initials) + ) } function getInitials(str: string): string { @@ -50,3 +75,17 @@ function getInitials(str: string): string { } return 'X' } + +const styles = StyleSheet.create({ + editButtonContainer: { + position: 'absolute', + bottom: 6, + right: 6, + backgroundColor: colors.gray5, + width: 20, + height: 20, + borderRadius: 10, + alignItems: 'center', + justifyContent: 'center', + }, +}) From 28ebf3d2cb2d6884c03a79c0040a187ac62fd39b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreiro?= Date: Wed, 30 Nov 2022 15:22:49 +0000 Subject: [PATCH 02/17] add editable button cover picture --- src/view/com/profile/ProfileHeader.tsx | 2 +- src/view/com/util/UserBanner.tsx | 49 ++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx index 7a26fa1628..228b6c594a 100644 --- a/src/view/com/profile/ProfileHeader.tsx +++ b/src/view/com/profile/ProfileHeader.tsx @@ -152,7 +152,7 @@ export const ProfileHeader = observer(function ProfileHeader({ } return ( - + ( @@ -20,4 +30,37 @@ export function UserBanner({handle}: {handle: string}) { ) + + const handleEditBanner = useCallback(() => { + Alert.alert('TB Implemented') + }, []) + + return isMe ? ( + + {renderSvg()} + + + + + ) : ( + renderSvg() + ) } + +const styles = StyleSheet.create({ + editButtonContainer: { + position: 'absolute', + bottom: 6, + right: 6, + backgroundColor: colors.gray5, + width: 20, + height: 20, + borderRadius: 10, + alignItems: 'center', + justifyContent: 'center', + }, +}) From 34be0ad6f524d0d768500171204c7e70b9ae4d38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreiro?= Date: Mon, 5 Dec 2022 15:25:43 +0000 Subject: [PATCH 03/17] upload profile photos (save them locally) --- src/view/com/util/UserAvatar.tsx | 62 +++++++++++++++++++++++++++----- src/view/com/util/UserBanner.tsx | 58 ++++++++++++++++++++++++++---- 2 files changed, 105 insertions(+), 15 deletions(-) diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx index f4dc982be3..eeef51b2ef 100644 --- a/src/view/com/util/UserAvatar.tsx +++ b/src/view/com/util/UserAvatar.tsx @@ -1,7 +1,8 @@ -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import React, {useCallback} from 'react' -import {Alert, StyleSheet, View, TouchableOpacity} from 'react-native' +import React, {useCallback, useState} from 'react' +import {StyleSheet, View, TouchableOpacity, Alert, Image} from 'react-native' import Svg, {Circle, Text, Defs, LinearGradient, Stop} from 'react-native-svg' +import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import {openCamera, openCropper, openPicker} from 'react-native-image-crop-picker' import {getGradient} from '../../lib/asset-gen' import {colors} from '../../lib/styles' @@ -16,9 +17,49 @@ export function UserAvatar({ handle: string displayName: string | undefined }) { + const [localAvatarPicture, setLocalAvatarPicture] = useState( + null, + ) const initials = getInitials(displayName || handle) const gradient = getGradient(handle) + const handleEditAvatar = useCallback(() => { + Alert.alert('', 'Select upload method', [ + { + text: 'Take a new photo', + onPress: () => { + openCamera({ + mediaType: 'photo', + cropping: true, + width: 80, + height: 80, + cropperCircleOverlay: true, + }).then(item => { + setLocalAvatarPicture(item.path) + }) + }, + }, + { + text: 'Select from gallery', + onPress: () => { + openPicker({ + mediaType: 'photo', + }).then(async item => { + await openCropper({ + mediaType: 'photo', + path: item.path, + width: 80, + height: 80, + cropperCircleOverlay: true, + }).then(croppedItem => { + setLocalAvatarPicture(croppedItem.path) + }) + }) + }, + }, + ]) + }, []) + const renderSvg = (size: number, initials: string) => ( @@ -40,13 +81,13 @@ export function UserAvatar({ ) - const handleEditAvatar = useCallback(() => { - Alert.alert('TB Implemented') - }, []) - return isMe ? ( - {renderSvg(size, initials)} + {localAvatarPicture != null ? ( + + ) : ( + renderSvg(size, initials) + )} ( + null, + ) + const gradient = getGradient(handle) + const handleEditBanner = useCallback(() => { + Alert.alert('', 'Select upload method', [ + { + text: 'Take a new photo', + onPress: () => { + openCamera({ + mediaType: 'photo', + cropping: true, + width: 1000, + height: 120, + }).then(item => { + setLocalBannerPicture(item.path) + }) + }, + }, + { + text: 'Select from gallery', + onPress: () => { + openPicker({ + mediaType: 'photo', + }).then(async item => { + await openCropper({ + mediaType: 'photo', + path: item.path, + width: 1000, + height: 120, + }).then(croppedItem => { + setLocalBannerPicture(croppedItem.path) + }) + }) + }, + }, + ]) + }, []) + const renderSvg = () => ( @@ -31,13 +71,13 @@ export function UserBanner({ ) - const handleEditBanner = useCallback(() => { - Alert.alert('TB Implemented') - }, []) - return isMe ? ( - {renderSvg()} + {localBannerPicture != null ? ( + + ) : ( + renderSvg() + )} Date: Mon, 5 Dec 2022 15:26:20 +0000 Subject: [PATCH 04/17] rollback pbxproj changes --- ios/app.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ios/app.xcodeproj/project.pbxproj b/ios/app.xcodeproj/project.pbxproj index 485aa8e04c..50db4563af 100644 --- a/ios/app.xcodeproj/project.pbxproj +++ b/ios/app.xcodeproj/project.pbxproj @@ -455,7 +455,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = app/app.entitlements; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 28H695D9YK; + DEVELOPMENT_TEAM = B3LX46C5HS; ENABLE_BITCODE = NO; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; INFOPLIST_FILE = app/Info.plist; @@ -468,7 +468,7 @@ "-ObjC", "-lc++", ); - PRODUCT_BUNDLE_IDENTIFIER = "xyz.blueskyweb.app-"; + PRODUCT_BUNDLE_IDENTIFIER = xyz.blueskyweb.app; PRODUCT_NAME = app; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -484,7 +484,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = app/app.entitlements; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 28H695D9YK; + DEVELOPMENT_TEAM = B3LX46C5HS; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; INFOPLIST_FILE = app/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -496,7 +496,7 @@ "-ObjC", "-lc++", ); - PRODUCT_BUNDLE_IDENTIFIER = "xyz.blueskyweb.app-"; + PRODUCT_BUNDLE_IDENTIFIER = xyz.blueskyweb.app; PRODUCT_NAME = app; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; From a9da790fef9b5c42e553136851325b8971d3a4d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreiro?= Date: Mon, 5 Dec 2022 15:33:28 +0000 Subject: [PATCH 05/17] rollback podfile checksum (for git only) --- ios/Podfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 39f1ead9ed..182ceab758 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -540,6 +540,6 @@ SPEC CHECKSUMS: TOCropViewController: edfd4f25713d56905ad1e0b9f5be3fbe0f59c863 Yoga: 99652481fcd320aefa4a7ef90095b95acd181952 -PODFILE CHECKSUM: 95dad1cd550c9983fb5c851af858b806e8250502 +PODFILE CHECKSUM: cf94853ebcb0d8e0d027dca9ab7a4ede886a8f20 COCOAPODS: 1.11.3 From 979a264cc08373ac9647eef0921f12ad5623a004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreiro?= Date: Mon, 5 Dec 2022 16:07:24 +0000 Subject: [PATCH 06/17] move edit photos onto edit profile modal --- src/view/com/modals/EditProfile.tsx | 27 ++++++++++++++++++++++ src/view/com/profile/ProfileHeader.tsx | 3 +-- src/view/com/util/UserAvatar.tsx | 30 ++++++++++++++----------- src/view/com/util/UserBanner.tsx | 31 ++++++++++++++------------ 4 files changed, 62 insertions(+), 29 deletions(-) diff --git a/src/view/com/modals/EditProfile.tsx b/src/view/com/modals/EditProfile.tsx index 1b5c99d977..08ce5f350c 100644 --- a/src/view/com/modals/EditProfile.tsx +++ b/src/view/com/modals/EditProfile.tsx @@ -13,6 +13,8 @@ import { MAX_DESCRIPTION, } from '../../../lib/strings' import * as Profile from '../../../third-party/api/src/client/types/app/bsky/actor/profile' +import {UserBanner} from '../util/UserBanner' +import {UserAvatar} from '../util/UserAvatar' export const snapPoints = ['60%'] @@ -67,6 +69,17 @@ export function Component({ Edit my profile + + + + + + {error !== '' && ( @@ -155,4 +168,18 @@ const styles = StyleSheet.create({ padding: 10, marginBottom: 10, }, + avi: { + position: 'absolute', + top: 80, + left: 10, + width: 84, + height: 84, + borderWidth: 2, + borderRadius: 42, + borderColor: colors.white, + backgroundColor: colors.white, + }, + photos: { + marginBottom: 48, + }, }) diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx index 228b6c594a..1b25c7c13c 100644 --- a/src/view/com/profile/ProfileHeader.tsx +++ b/src/view/com/profile/ProfileHeader.tsx @@ -152,11 +152,10 @@ export const ProfileHeader = observer(function ProfileHeader({ } return ( - + diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx index eeef51b2ef..2826a7846d 100644 --- a/src/view/com/util/UserAvatar.tsx +++ b/src/view/com/util/UserAvatar.tsx @@ -1,30 +1,31 @@ -import React, {useCallback, useState} from 'react' +import React, {useCallback} from 'react' import {StyleSheet, View, TouchableOpacity, Alert, Image} from 'react-native' import Svg, {Circle, Text, Defs, LinearGradient, Stop} from 'react-native-svg' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import {openCamera, openCropper, openPicker} from 'react-native-image-crop-picker' +import { + openCamera, + openCropper, + openPicker, +} from 'react-native-image-crop-picker' import {getGradient} from '../../lib/asset-gen' import {colors} from '../../lib/styles' export function UserAvatar({ - isMe = false, + isEditable = false, size, handle, displayName, }: { - isMe?: boolean + isEditable?: boolean size: number handle: string displayName: string | undefined }) { - const [localAvatarPicture, setLocalAvatarPicture] = useState( - null, - ) const initials = getInitials(displayName || handle) const gradient = getGradient(handle) const handleEditAvatar = useCallback(() => { - Alert.alert('', 'Select upload method', [ + Alert.alert('Select upload method', '', [ { text: 'Take a new photo', onPress: () => { @@ -35,7 +36,8 @@ export function UserAvatar({ height: 80, cropperCircleOverlay: true, }).then(item => { - setLocalAvatarPicture(item.path) + // setLocalAvatarPicture(item.path) + console.log(item) }) }, }, @@ -52,7 +54,8 @@ export function UserAvatar({ height: 80, cropperCircleOverlay: true, }).then(croppedItem => { - setLocalAvatarPicture(croppedItem.path) + // setLocalAvatarPicture(croppedItem.path) + console.log(croppedItem) }) }) }, @@ -81,13 +84,14 @@ export function UserAvatar({ ) - return isMe ? ( + return isEditable ? ( - {localAvatarPicture != null ? ( + {/* {localAvatarPicture != null ? ( ) : ( renderSvg(size, initials) - )} + )} */} + {renderSvg(size, initials)} ( - null, - ) - const gradient = getGradient(handle) const handleEditBanner = useCallback(() => { - Alert.alert('', 'Select upload method', [ + Alert.alert('Select upload method', '', [ { text: 'Take a new photo', onPress: () => { @@ -30,7 +30,8 @@ export function UserBanner({ width: 1000, height: 120, }).then(item => { - setLocalBannerPicture(item.path) + // setLocalBannerPicture(item.path) + console.log(item) }) }, }, @@ -46,7 +47,8 @@ export function UserBanner({ width: 1000, height: 120, }).then(croppedItem => { - setLocalBannerPicture(croppedItem.path) + // setLocalBannerPicture(croppedItem.path) + console.log(croppedItem) }) }) }, @@ -71,13 +73,14 @@ export function UserBanner({ ) - return isMe ? ( + return isEditable ? ( - {localBannerPicture != null ? ( + {/* {localBannerPicture != null ? ( ) : ( renderSvg() - )} + )} */} + {renderSvg()} Date: Mon, 5 Dec 2022 16:29:44 +0000 Subject: [PATCH 07/17] adjust edit icon and image cropping size --- src/view/com/util/UserAvatar.tsx | 17 +++++++++-------- src/view/com/util/UserBanner.tsx | 30 ++++++++++++++++-------------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx index 2826a7846d..f668c69ed0 100644 --- a/src/view/com/util/UserAvatar.tsx +++ b/src/view/com/util/UserAvatar.tsx @@ -95,8 +95,8 @@ export function UserAvatar({ @@ -124,14 +124,15 @@ function getInitials(str: string): string { const styles = StyleSheet.create({ editButtonContainer: { position: 'absolute', - bottom: 6, - right: 6, - backgroundColor: colors.gray5, - width: 20, - height: 20, - borderRadius: 10, + width: 50, + height: 50, + top: '50%', + left: '50%', + borderRadius: 25, alignItems: 'center', justifyContent: 'center', + backgroundColor: colors.gray5 + '99', + transform: [{translateX: -25}, {translateY: -25}], }, avatarImage: { width: 80, diff --git a/src/view/com/util/UserBanner.tsx b/src/view/com/util/UserBanner.tsx index 2183dfcdcd..dc27ef9685 100644 --- a/src/view/com/util/UserBanner.tsx +++ b/src/view/com/util/UserBanner.tsx @@ -1,5 +1,5 @@ import React, {useCallback} from 'react' -import {StyleSheet, View, TouchableOpacity, Alert, Image} from 'react-native' +import {StyleSheet, View, TouchableOpacity, Alert, Image, Dimensions} from 'react-native' import Svg, {Rect, Defs, LinearGradient, Stop} from 'react-native-svg' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {getGradient} from '../../lib/asset-gen' @@ -27,8 +27,8 @@ export function UserBanner({ openCamera({ mediaType: 'photo', cropping: true, - width: 1000, - height: 120, + width: 1500, + height: 500, }).then(item => { // setLocalBannerPicture(item.path) console.log(item) @@ -44,8 +44,8 @@ export function UserBanner({ await openCropper({ mediaType: 'photo', path: item.path, - width: 1000, - height: 120, + width: 1500, + height: 500, }).then(croppedItem => { // setLocalBannerPicture(croppedItem.path) console.log(croppedItem) @@ -84,8 +84,8 @@ export function UserBanner({ @@ -97,17 +97,19 @@ export function UserBanner({ const styles = StyleSheet.create({ editButtonContainer: { position: 'absolute', - bottom: 6, - right: 6, - backgroundColor: colors.gray5, - width: 20, - height: 20, - borderRadius: 10, + width: 50, + height: 50, + top: '50%', + left: '50%', + borderRadius: 25, alignItems: 'center', justifyContent: 'center', + backgroundColor: colors.gray5 + '99', + transform: [{translateX: -25}, {translateY: -25}], }, bannerImage: { - width: 1000, + width: '100%', height: 120, + resizeMode: 'contain', }, }) From 7895e084f818d191cc1aa629adef9e4aedac0b8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreiro?= Date: Mon, 5 Dec 2022 16:51:18 +0000 Subject: [PATCH 08/17] added temporary (react state) image --- src/view/com/util/UserAvatar.tsx | 17 +++++++++-------- src/view/com/util/UserBanner.tsx | 23 ++++++++++++++--------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx index f668c69ed0..406654e4df 100644 --- a/src/view/com/util/UserAvatar.tsx +++ b/src/view/com/util/UserAvatar.tsx @@ -1,4 +1,4 @@ -import React, {useCallback} from 'react' +import React, {useCallback, useState} from 'react' import {StyleSheet, View, TouchableOpacity, Alert, Image} from 'react-native' import Svg, {Circle, Text, Defs, LinearGradient, Stop} from 'react-native-svg' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' @@ -24,6 +24,8 @@ export function UserAvatar({ const initials = getInitials(displayName || handle) const gradient = getGradient(handle) + const [uploadedImage, setUploadedImage] = useState(null) + const handleEditAvatar = useCallback(() => { Alert.alert('Select upload method', '', [ { @@ -36,8 +38,7 @@ export function UserAvatar({ height: 80, cropperCircleOverlay: true, }).then(item => { - // setLocalAvatarPicture(item.path) - console.log(item) + setUploadedImage(item.path) }) }, }, @@ -54,7 +55,7 @@ export function UserAvatar({ height: 80, cropperCircleOverlay: true, }).then(croppedItem => { - // setLocalAvatarPicture(croppedItem.path) + setUploadedImage(croppedItem.path) console.log(croppedItem) }) }) @@ -86,12 +87,12 @@ export function UserAvatar({ return isEditable ? ( - {/* {localAvatarPicture != null ? ( - + {/* Added a react state temporary photo white the protocol does not support imagery */} + {uploadedImage != null ? ( + ) : ( renderSvg(size, initials) - )} */} - {renderSvg(size, initials)} + )} (null) + const handleEditBanner = useCallback(() => { Alert.alert('Select upload method', '', [ { @@ -30,7 +32,7 @@ export function UserBanner({ width: 1500, height: 500, }).then(item => { - // setLocalBannerPicture(item.path) + setUploadedImage(item.path) console.log(item) }) }, @@ -47,7 +49,7 @@ export function UserBanner({ width: 1500, height: 500, }).then(croppedItem => { - // setLocalBannerPicture(croppedItem.path) + setUploadedImage(croppedItem.path) console.log(croppedItem) }) }) @@ -75,12 +77,16 @@ export function UserBanner({ return isEditable ? ( - {/* {localBannerPicture != null ? ( - + {/* Added a react state temporary photo white the protocol does not support imagery */} + {uploadedImage != null ? ( + ) : ( renderSvg() - )} */} - {renderSvg()} + )} Date: Mon, 5 Dec 2022 17:00:41 +0000 Subject: [PATCH 09/17] added IMAGES_ENABLED flag --- src/view/com/util/UserAvatar.tsx | 3 ++- src/view/com/util/UserBanner.tsx | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx index 406654e4df..79f243709f 100644 --- a/src/view/com/util/UserAvatar.tsx +++ b/src/view/com/util/UserAvatar.tsx @@ -9,6 +9,7 @@ import { } from 'react-native-image-crop-picker' import {getGradient} from '../../lib/asset-gen' import {colors} from '../../lib/styles' +import { IMAGES_ENABLED } from '../../../build-flags' export function UserAvatar({ isEditable = false, @@ -85,7 +86,7 @@ export function UserAvatar({ ) - return isEditable ? ( + return isEditable && IMAGES_ENABLED ? ( {/* Added a react state temporary photo white the protocol does not support imagery */} {uploadedImage != null ? ( diff --git a/src/view/com/util/UserBanner.tsx b/src/view/com/util/UserBanner.tsx index 0b83622f3c..174a29e7cc 100644 --- a/src/view/com/util/UserBanner.tsx +++ b/src/view/com/util/UserBanner.tsx @@ -9,6 +9,7 @@ import { openCropper, openPicker, } from 'react-native-image-crop-picker' +import { IMAGES_ENABLED } from '../../../build-flags' export function UserBanner({ handle, @@ -75,7 +76,7 @@ export function UserBanner({ ) - return isEditable ? ( + return isEditable && IMAGES_ENABLED ? ( {/* Added a react state temporary photo white the protocol does not support imagery */} {uploadedImage != null ? ( From 032ab34d98af25c00dea1cf4899e4bf4ce5a11a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreiro?= Date: Mon, 5 Dec 2022 17:15:43 +0000 Subject: [PATCH 10/17] minor lint fix --- src/view/com/util/UserAvatar.tsx | 2 +- src/view/com/util/UserBanner.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx index 79f243709f..d3251f5041 100644 --- a/src/view/com/util/UserAvatar.tsx +++ b/src/view/com/util/UserAvatar.tsx @@ -9,7 +9,7 @@ import { } from 'react-native-image-crop-picker' import {getGradient} from '../../lib/asset-gen' import {colors} from '../../lib/styles' -import { IMAGES_ENABLED } from '../../../build-flags' +import {IMAGES_ENABLED} from '../../../build-flags' export function UserAvatar({ isEditable = false, diff --git a/src/view/com/util/UserBanner.tsx b/src/view/com/util/UserBanner.tsx index 174a29e7cc..8212c049c3 100644 --- a/src/view/com/util/UserBanner.tsx +++ b/src/view/com/util/UserBanner.tsx @@ -9,7 +9,7 @@ import { openCropper, openPicker, } from 'react-native-image-crop-picker' -import { IMAGES_ENABLED } from '../../../build-flags' +import {IMAGES_ENABLED} from '../../../build-flags' export function UserBanner({ handle, From a067312f191219503a0e364bcd668799f41130d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreiro?= Date: Tue, 6 Dec 2022 10:30:04 +0000 Subject: [PATCH 11/17] save local photos on edit profile upload (wip) --- src/view/com/modals/EditProfile.tsx | 3 +- src/view/com/profile/ProfileHeader.tsx | 3 +- src/view/com/util/UserAvatar.tsx | 39 +++++++++++++++++++------- src/view/com/util/UserBanner.tsx | 36 ++++++++++++++++++------ 4 files changed, 60 insertions(+), 21 deletions(-) diff --git a/src/view/com/modals/EditProfile.tsx b/src/view/com/modals/EditProfile.tsx index 08ce5f350c..b330120664 100644 --- a/src/view/com/modals/EditProfile.tsx +++ b/src/view/com/modals/EditProfile.tsx @@ -70,10 +70,11 @@ export function Component({ Edit my profile - + - + (null) + const [userAvatarImage, setUserAvatarImage] = useState(null) + + useEffect(() => { + async function loadLocalImage() { + if (isMe) { + await loadString('userAvatarImage').then(uri => { + setUserAvatarImage(uri) + }) + } + } + loadLocalImage() + }, [isMe]) const handleEditAvatar = useCallback(() => { Alert.alert('Select upload method', '', [ @@ -39,7 +53,7 @@ export function UserAvatar({ height: 80, cropperCircleOverlay: true, }).then(item => { - setUploadedImage(item.path) + saveString('userAvatarImage', item.path) }) }, }, @@ -56,8 +70,7 @@ export function UserAvatar({ height: 80, cropperCircleOverlay: true, }).then(croppedItem => { - setUploadedImage(croppedItem.path) - console.log(croppedItem) + saveString('userAvatarImage', croppedItem.path) }) }) }, @@ -88,9 +101,9 @@ export function UserAvatar({ return isEditable && IMAGES_ENABLED ? ( - {/* Added a react state temporary photo white the protocol does not support imagery */} - {uploadedImage != null ? ( - + {/* Added a react state temporary photo while the protocol does not support imagery */} + {userAvatarImage != null ? ( + ) : ( renderSvg(size, initials) )} @@ -102,6 +115,12 @@ export function UserAvatar({ /> + ) : isMe && userAvatarImage != null ? ( + ) : ( renderSvg(size, initials) ) diff --git a/src/view/com/util/UserBanner.tsx b/src/view/com/util/UserBanner.tsx index 8212c049c3..8809d0b92f 100644 --- a/src/view/com/util/UserBanner.tsx +++ b/src/view/com/util/UserBanner.tsx @@ -1,4 +1,4 @@ -import React, {useCallback, useState} from 'react' +import React, {useCallback, useEffect, useState} from 'react' import {StyleSheet, View, TouchableOpacity, Alert, Image} from 'react-native' import Svg, {Rect, Defs, LinearGradient, Stop} from 'react-native-svg' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' @@ -10,17 +10,31 @@ import { openPicker, } from 'react-native-image-crop-picker' import {IMAGES_ENABLED} from '../../../build-flags' +import {saveString, loadString} from '../../../state/lib/storage' export function UserBanner({ handle, + isMe = false, isEditable = false, }: { handle: string + isMe?: boolean isEditable?: boolean }) { const gradient = getGradient(handle) - const [uploadedImage, setUploadedImage] = useState(null) + const [userBannerImage, setUserBannerImage] = useState(null) + + useEffect(() => { + async function loadLocalImage() { + if (isMe) { + await loadString('userBannerImage').then(uri => { + setUserBannerImage(uri) + }) + } + } + loadLocalImage() + }, [isMe]) const handleEditBanner = useCallback(() => { Alert.alert('Select upload method', '', [ @@ -33,8 +47,7 @@ export function UserBanner({ width: 1500, height: 500, }).then(item => { - setUploadedImage(item.path) - console.log(item) + saveString('userBannerImage', item.path) }) }, }, @@ -50,8 +63,7 @@ export function UserBanner({ width: 1500, height: 500, }).then(croppedItem => { - setUploadedImage(croppedItem.path) - console.log(croppedItem) + saveString('userBannerImage', croppedItem.path) }) }) }, @@ -78,12 +90,12 @@ export function UserBanner({ return isEditable && IMAGES_ENABLED ? ( - {/* Added a react state temporary photo white the protocol does not support imagery */} - {uploadedImage != null ? ( + {/* Added a react state temporary photo while the protocol does not support imagery */} + {userBannerImage != null ? ( ) : ( renderSvg() @@ -96,6 +108,12 @@ export function UserBanner({ /> + ) : isMe && userBannerImage != null ? ( + ) : ( renderSvg() ) From 8d98c9970517175d63e018f61b87b84a84dc0556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreiro?= Date: Tue, 6 Dec 2022 11:12:13 +0000 Subject: [PATCH 12/17] save profile photos on profile view state (wip) --- src/state/models/profile-view.ts | 21 +++++++++++++++ src/view/com/modals/EditProfile.tsx | 12 ++++++--- src/view/com/profile/ProfileHeader.tsx | 25 +++++++++--------- src/view/com/util/UserAvatar.tsx | 36 ++++++++++---------------- src/view/com/util/UserBanner.tsx | 33 ++++++++--------------- 5 files changed, 68 insertions(+), 59 deletions(-) diff --git a/src/state/models/profile-view.ts b/src/state/models/profile-view.ts index 927374cc67..013a1b04fc 100644 --- a/src/state/models/profile-view.ts +++ b/src/state/models/profile-view.ts @@ -6,6 +6,7 @@ import {extractEntities} from '../../lib/strings' import {Declaration} from './_common' import {RootStoreModel} from './root-store' import * as apilib from '../lib/api' +import {Image} from 'react-native-image-crop-picker' export const ACTOR_TYPE_USER = 'app.bsky.system.actorUser' export const ACTOR_TYPE_SCENE = 'app.bsky.system.actorScene' @@ -46,6 +47,10 @@ export class ProfileViewModel { // added data descriptionEntities?: Entity[] + // temp state while imagery is not supported by the protocol + userAvatar: Image | null = null + userBanner: Image | null = null + constructor( public rootStore: RootStoreModel, params: GetProfile.QueryParams, @@ -81,6 +86,14 @@ export class ProfileViewModel { return this.declaration.actorType === ACTOR_TYPE_SCENE } + get userAvatarPath() { + return this.userAvatar?.path + } + + get userBannerPath() { + return this.userBanner?.path + } + // public api // = @@ -123,6 +136,14 @@ export class ProfileViewModel { // state transitions // = + updateUserAvatar(img: Image) { + this.userAvatar = img + } + + updateUserBanner(img: Image) { + this.userBanner = img + } + private _xLoading(isRefreshing = false) { this.isLoading = true this.isRefreshing = isRefreshing diff --git a/src/view/com/modals/EditProfile.tsx b/src/view/com/modals/EditProfile.tsx index b330120664..0a305115d6 100644 --- a/src/view/com/modals/EditProfile.tsx +++ b/src/view/com/modals/EditProfile.tsx @@ -70,14 +70,20 @@ export function Component({ Edit my profile - + diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx index b271fc8b6a..e31c51418d 100644 --- a/src/view/com/profile/ProfileHeader.tsx +++ b/src/view/com/profile/ProfileHeader.tsx @@ -32,15 +32,15 @@ export const ProfileHeader = observer(function ProfileHeader({ const store = useStores() const isMember = useMemo( () => view.isScene && view.myState.member, - [view.myState.member], + [view.isScene, view.myState.member], ) - const onPressBack = () => { - store.nav.tab.goBack() - } - const onPressSearch = () => { - store.nav.navigate(`/search`) - } + // const onPressBack = () => { + // store.nav.tab.goBack() + // } + // const onPressSearch = () => { + // store.nav.navigate('/search') + // } const onPressToggleFollow = () => { view?.toggleFollowing().then( () => { @@ -72,7 +72,7 @@ export const ProfileHeader = observer(function ProfileHeader({ store.shell.openModal( new ConfirmModel( 'Leave this scene?', - `You'll be able to come back unless your invite is revoked.`, + "You'll be able to come back unless your invite is revoked.", onPressConfirmLeaveScene, ), ) @@ -83,7 +83,7 @@ export const ProfileHeader = observer(function ProfileHeader({ did: store.me.did || '', rkey: new AtUri(view.myState.member).rkey, }) - Toast.show(`Scene left`) + Toast.show('Scene left') } onRefreshAll() } @@ -152,13 +152,14 @@ export const ProfileHeader = observer(function ProfileHeader({ } return ( - + diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx index 93500d5a45..566d4f6c90 100644 --- a/src/view/com/util/UserAvatar.tsx +++ b/src/view/com/util/UserAvatar.tsx @@ -1,4 +1,4 @@ -import React, {useCallback, useEffect, useState} from 'react' +import React, {useCallback} from 'react' import {StyleSheet, View, TouchableOpacity, Alert, Image} from 'react-native' import Svg, {Circle, Text, Defs, LinearGradient, Stop} from 'react-native-svg' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' @@ -10,11 +10,12 @@ import { import {getGradient} from '../../lib/asset-gen' import {colors} from '../../lib/styles' import {IMAGES_ENABLED} from '../../../build-flags' -import {loadString, saveString} from '../../../state/lib/storage' +import {ProfileViewModel} from '../../../state/models/profile-view' export function UserAvatar({ size, handle, + profileView, displayName, isMe = false, isEditable = false, @@ -24,23 +25,11 @@ export function UserAvatar({ isMe?: boolean isEditable?: boolean displayName: string | undefined + profileView: ProfileViewModel }) { const initials = getInitials(displayName || handle) const gradient = getGradient(handle) - const [userAvatarImage, setUserAvatarImage] = useState(null) - - useEffect(() => { - async function loadLocalImage() { - if (isMe) { - await loadString('userAvatarImage').then(uri => { - setUserAvatarImage(uri) - }) - } - } - loadLocalImage() - }, [isMe]) - const handleEditAvatar = useCallback(() => { Alert.alert('Select upload method', '', [ { @@ -53,7 +42,7 @@ export function UserAvatar({ height: 80, cropperCircleOverlay: true, }).then(item => { - saveString('userAvatarImage', item.path) + profileView.updateUserAvatar(item) }) }, }, @@ -70,13 +59,13 @@ export function UserAvatar({ height: 80, cropperCircleOverlay: true, }).then(croppedItem => { - saveString('userAvatarImage', croppedItem.path) + profileView.updateUserAvatar(croppedItem) }) }) }, }, ]) - }, []) + }, [profileView]) const renderSvg = (size: number, initials: string) => ( @@ -102,8 +91,11 @@ export function UserAvatar({ return isEditable && IMAGES_ENABLED ? ( {/* Added a react state temporary photo while the protocol does not support imagery */} - {userAvatarImage != null ? ( - + {profileView.userAvatar != null ? ( + ) : ( renderSvg(size, initials) )} @@ -115,11 +107,11 @@ export function UserAvatar({ /> - ) : isMe && userAvatarImage != null ? ( + ) : isMe && profileView.userAvatar != null ? ( ) : ( renderSvg(size, initials) diff --git a/src/view/com/util/UserBanner.tsx b/src/view/com/util/UserBanner.tsx index 8809d0b92f..db37beb5d3 100644 --- a/src/view/com/util/UserBanner.tsx +++ b/src/view/com/util/UserBanner.tsx @@ -1,4 +1,4 @@ -import React, {useCallback, useEffect, useState} from 'react' +import React, {useCallback} from 'react' import {StyleSheet, View, TouchableOpacity, Alert, Image} from 'react-native' import Svg, {Rect, Defs, LinearGradient, Stop} from 'react-native-svg' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' @@ -10,32 +10,21 @@ import { openPicker, } from 'react-native-image-crop-picker' import {IMAGES_ENABLED} from '../../../build-flags' -import {saveString, loadString} from '../../../state/lib/storage' +import {ProfileViewModel} from '../../../state/models/profile-view' export function UserBanner({ handle, + profileView, isMe = false, isEditable = false, }: { handle: string isMe?: boolean + profileView: ProfileViewModel isEditable?: boolean }) { const gradient = getGradient(handle) - const [userBannerImage, setUserBannerImage] = useState(null) - - useEffect(() => { - async function loadLocalImage() { - if (isMe) { - await loadString('userBannerImage').then(uri => { - setUserBannerImage(uri) - }) - } - } - loadLocalImage() - }, [isMe]) - const handleEditBanner = useCallback(() => { Alert.alert('Select upload method', '', [ { @@ -47,7 +36,7 @@ export function UserBanner({ width: 1500, height: 500, }).then(item => { - saveString('userBannerImage', item.path) + profileView.updateUserBanner(item) }) }, }, @@ -63,13 +52,13 @@ export function UserBanner({ width: 1500, height: 500, }).then(croppedItem => { - saveString('userBannerImage', croppedItem.path) + profileView.updateUserBanner(croppedItem) }) }) }, }, ]) - }, []) + }, [profileView]) const renderSvg = () => ( @@ -91,11 +80,11 @@ export function UserBanner({ return isEditable && IMAGES_ENABLED ? ( {/* Added a react state temporary photo while the protocol does not support imagery */} - {userBannerImage != null ? ( + {profileView.userBanner != null ? ( ) : ( renderSvg() @@ -108,11 +97,11 @@ export function UserBanner({ /> - ) : isMe && userBannerImage != null ? ( + ) : isMe && profileView.userBanner != null ? ( ) : ( renderSvg() From 174bcfce1de281cc4b020effe55fa2527c78df84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreiro?= Date: Tue, 6 Dec 2022 11:16:41 +0000 Subject: [PATCH 13/17] remove unecessary computed --- src/state/models/profile-view.ts | 8 -------- src/view/com/util/UserAvatar.tsx | 4 ++-- src/view/com/util/UserBanner.tsx | 4 ++-- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/state/models/profile-view.ts b/src/state/models/profile-view.ts index 013a1b04fc..60d9067576 100644 --- a/src/state/models/profile-view.ts +++ b/src/state/models/profile-view.ts @@ -86,14 +86,6 @@ export class ProfileViewModel { return this.declaration.actorType === ACTOR_TYPE_SCENE } - get userAvatarPath() { - return this.userAvatar?.path - } - - get userBannerPath() { - return this.userBanner?.path - } - // public api // = diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx index 566d4f6c90..95c70c32db 100644 --- a/src/view/com/util/UserAvatar.tsx +++ b/src/view/com/util/UserAvatar.tsx @@ -94,7 +94,7 @@ export function UserAvatar({ {profileView.userAvatar != null ? ( ) : ( renderSvg(size, initials) @@ -111,7 +111,7 @@ export function UserAvatar({ ) : ( renderSvg(size, initials) diff --git a/src/view/com/util/UserBanner.tsx b/src/view/com/util/UserBanner.tsx index db37beb5d3..710463e976 100644 --- a/src/view/com/util/UserBanner.tsx +++ b/src/view/com/util/UserBanner.tsx @@ -84,7 +84,7 @@ export function UserBanner({ ) : ( renderSvg() @@ -101,7 +101,7 @@ export function UserBanner({ ) : ( renderSvg() From 90d851c0c53b1acd9bf018d1e940da203953d248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreiro?= Date: Tue, 6 Dec 2022 11:26:13 +0000 Subject: [PATCH 14/17] save photo in state before pushing it to viewmodel --- src/view/com/profile/ProfileHeader.tsx | 18 +++++++++--------- src/view/com/util/UserAvatar.tsx | 10 +++++++--- src/view/com/util/UserBanner.tsx | 10 +++++++--- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx index e31c51418d..0dee773546 100644 --- a/src/view/com/profile/ProfileHeader.tsx +++ b/src/view/com/profile/ProfileHeader.tsx @@ -32,15 +32,15 @@ export const ProfileHeader = observer(function ProfileHeader({ const store = useStores() const isMember = useMemo( () => view.isScene && view.myState.member, - [view.isScene, view.myState.member], + [view.myState.member], ) - // const onPressBack = () => { - // store.nav.tab.goBack() - // } - // const onPressSearch = () => { - // store.nav.navigate('/search') - // } + const onPressBack = () => { + store.nav.tab.goBack() + } + const onPressSearch = () => { + store.nav.navigate(`/search`) + } const onPressToggleFollow = () => { view?.toggleFollowing().then( () => { @@ -72,7 +72,7 @@ export const ProfileHeader = observer(function ProfileHeader({ store.shell.openModal( new ConfirmModel( 'Leave this scene?', - "You'll be able to come back unless your invite is revoked.", + `You'll be able to come back unless your invite is revoked.`, onPressConfirmLeaveScene, ), ) @@ -83,7 +83,7 @@ export const ProfileHeader = observer(function ProfileHeader({ did: store.me.did || '', rkey: new AtUri(view.myState.member).rkey, }) - Toast.show('Scene left') + Toast.show(`Scene left`) } onRefreshAll() } diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx index 95c70c32db..ed9c96d164 100644 --- a/src/view/com/util/UserAvatar.tsx +++ b/src/view/com/util/UserAvatar.tsx @@ -1,4 +1,4 @@ -import React, {useCallback} from 'react' +import React, {useCallback, useState} from 'react' import {StyleSheet, View, TouchableOpacity, Alert, Image} from 'react-native' import Svg, {Circle, Text, Defs, LinearGradient, Stop} from 'react-native-svg' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' @@ -30,6 +30,8 @@ export function UserAvatar({ const initials = getInitials(displayName || handle) const gradient = getGradient(handle) + const [tempUserAvatar, setTempUserAvatar] = useState(null) + const handleEditAvatar = useCallback(() => { Alert.alert('Select upload method', '', [ { @@ -43,6 +45,7 @@ export function UserAvatar({ cropperCircleOverlay: true, }).then(item => { profileView.updateUserAvatar(item) + setTempUserAvatar(item.path) }) }, }, @@ -60,6 +63,7 @@ export function UserAvatar({ cropperCircleOverlay: true, }).then(croppedItem => { profileView.updateUserAvatar(croppedItem) + setTempUserAvatar(croppedItem.path) }) }) }, @@ -91,10 +95,10 @@ export function UserAvatar({ return isEditable && IMAGES_ENABLED ? ( {/* Added a react state temporary photo while the protocol does not support imagery */} - {profileView.userAvatar != null ? ( + {profileView.userAvatar != null || tempUserAvatar != null ? ( ) : ( renderSvg(size, initials) diff --git a/src/view/com/util/UserBanner.tsx b/src/view/com/util/UserBanner.tsx index 710463e976..bc2c4a9207 100644 --- a/src/view/com/util/UserBanner.tsx +++ b/src/view/com/util/UserBanner.tsx @@ -1,4 +1,4 @@ -import React, {useCallback} from 'react' +import React, {useCallback, useState} from 'react' import {StyleSheet, View, TouchableOpacity, Alert, Image} from 'react-native' import Svg, {Rect, Defs, LinearGradient, Stop} from 'react-native-svg' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' @@ -25,6 +25,8 @@ export function UserBanner({ }) { const gradient = getGradient(handle) + const [tempUserBanner, setTempUserBanner] = useState(null) + const handleEditBanner = useCallback(() => { Alert.alert('Select upload method', '', [ { @@ -37,6 +39,7 @@ export function UserBanner({ height: 500, }).then(item => { profileView.updateUserBanner(item) + setTempUserBanner(item.path) }) }, }, @@ -53,6 +56,7 @@ export function UserBanner({ height: 500, }).then(croppedItem => { profileView.updateUserBanner(croppedItem) + setTempUserBanner(croppedItem.path) }) }) }, @@ -80,11 +84,11 @@ export function UserBanner({ return isEditable && IMAGES_ENABLED ? ( {/* Added a react state temporary photo while the protocol does not support imagery */} - {profileView.userBanner != null ? ( + {profileView.userBanner != null || tempUserBanner != null ? ( ) : ( renderSvg() From ed6bcfdb75f10be0ee0245a6b07c6484559a07c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreiro?= Date: Tue, 6 Dec 2022 14:50:20 +0000 Subject: [PATCH 15/17] refactor profile pictures's state --- src/state/models/profile-view.ts | 26 ++++++++--------- src/view/com/modals/EditProfile.tsx | 16 ++++++++--- src/view/com/profile/ProfileHeader.tsx | 8 ++++-- src/view/com/util/UserAvatar.tsx | 39 ++++++++++++-------------- src/view/com/util/UserBanner.tsx | 36 +++++++++--------------- 5 files changed, 62 insertions(+), 63 deletions(-) diff --git a/src/state/models/profile-view.ts b/src/state/models/profile-view.ts index 60d9067576..5244e0912f 100644 --- a/src/state/models/profile-view.ts +++ b/src/state/models/profile-view.ts @@ -6,7 +6,6 @@ import {extractEntities} from '../../lib/strings' import {Declaration} from './_common' import {RootStoreModel} from './root-store' import * as apilib from '../lib/api' -import {Image} from 'react-native-image-crop-picker' export const ACTOR_TYPE_USER = 'app.bsky.system.actorUser' export const ACTOR_TYPE_SCENE = 'app.bsky.system.actorScene' @@ -44,13 +43,13 @@ export class ProfileViewModel { postsCount: number = 0 myState = new ProfileViewMyStateModel() + // data to be implemented in the protocol + userAvatar: string | null = null + userBanner: string | null = null + // added data descriptionEntities?: Entity[] - // temp state while imagery is not supported by the protocol - userAvatar: Image | null = null - userBanner: Image | null = null - constructor( public rootStore: RootStoreModel, params: GetProfile.QueryParams, @@ -120,22 +119,21 @@ export class ProfileViewModel { } } - async updateProfile(fn: (existing?: Profile.Record) => Profile.Record) { + async updateProfile( + fn: (existing?: Profile.Record) => Profile.Record, + userAvatar: string | null, + userBanner: string | null, + ) { await apilib.updateProfile(this.rootStore, this.did, fn) + // add userBanner & userAvatar in the protocol when suported + this.userAvatar = userAvatar + this.userBanner = userBanner await this.refresh() } // state transitions // = - updateUserAvatar(img: Image) { - this.userAvatar = img - } - - updateUserBanner(img: Image) { - this.userBanner = img - } - private _xLoading(isRefreshing = false) { this.isLoading = true this.isRefreshing = isRefreshing diff --git a/src/view/com/modals/EditProfile.tsx b/src/view/com/modals/EditProfile.tsx index 0a305115d6..af5cf27b30 100644 --- a/src/view/com/modals/EditProfile.tsx +++ b/src/view/com/modals/EditProfile.tsx @@ -33,6 +33,12 @@ export function Component({ const [description, setDescription] = useState( profileView.description || '', ) + const [userBanner, setUserBanner] = useState( + profileView.userBanner, + ) + const [userAvatar, setUserAvatar] = useState( + profileView.userAvatar, + ) const onPressCancel = () => { store.shell.closeModal() } @@ -53,6 +59,8 @@ export function Component({ description, } }, + userAvatar, + userBanner, ) Toast.show('Profile updated') onUpdate?.() @@ -72,17 +80,17 @@ export function Component({ diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx index 0dee773546..2642868fb2 100644 --- a/src/view/com/profile/ProfileHeader.tsx +++ b/src/view/com/profile/ProfileHeader.tsx @@ -152,14 +152,18 @@ export const ProfileHeader = observer(function ProfileHeader({ } return ( - + diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx index ed9c96d164..fbcc53e0e3 100644 --- a/src/view/com/util/UserAvatar.tsx +++ b/src/view/com/util/UserAvatar.tsx @@ -1,4 +1,4 @@ -import React, {useCallback, useState} from 'react' +import React, {useCallback} from 'react' import {StyleSheet, View, TouchableOpacity, Alert, Image} from 'react-native' import Svg, {Circle, Text, Defs, LinearGradient, Stop} from 'react-native-svg' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' @@ -10,28 +10,25 @@ import { import {getGradient} from '../../lib/asset-gen' import {colors} from '../../lib/styles' import {IMAGES_ENABLED} from '../../../build-flags' -import {ProfileViewModel} from '../../../state/models/profile-view' export function UserAvatar({ size, handle, - profileView, + userAvatar, displayName, isMe = false, - isEditable = false, + setUserAvatar, }: { size: number handle: string isMe?: boolean - isEditable?: boolean displayName: string | undefined - profileView: ProfileViewModel + userAvatar: string | null + setUserAvatar?: React.Dispatch> }) { const initials = getInitials(displayName || handle) const gradient = getGradient(handle) - const [tempUserAvatar, setTempUserAvatar] = useState(null) - const handleEditAvatar = useCallback(() => { Alert.alert('Select upload method', '', [ { @@ -44,8 +41,9 @@ export function UserAvatar({ height: 80, cropperCircleOverlay: true, }).then(item => { - profileView.updateUserAvatar(item) - setTempUserAvatar(item.path) + if (setUserAvatar != null) { + setUserAvatar(item.path) + } }) }, }, @@ -62,14 +60,15 @@ export function UserAvatar({ height: 80, cropperCircleOverlay: true, }).then(croppedItem => { - profileView.updateUserAvatar(croppedItem) - setTempUserAvatar(croppedItem.path) + if (setUserAvatar != null) { + setUserAvatar(croppedItem.path) + } }) }) }, }, ]) - }, [profileView]) + }, [setUserAvatar]) const renderSvg = (size: number, initials: string) => ( @@ -92,14 +91,12 @@ export function UserAvatar({ ) - return isEditable && IMAGES_ENABLED ? ( + // setUserAvatar is only passed as prop on the EditProfile component + return setUserAvatar != null && IMAGES_ENABLED ? ( {/* Added a react state temporary photo while the protocol does not support imagery */} - {profileView.userAvatar != null || tempUserAvatar != null ? ( - + {userAvatar != null ? ( + ) : ( renderSvg(size, initials) )} @@ -111,11 +108,11 @@ export function UserAvatar({ /> - ) : isMe && profileView.userAvatar != null ? ( + ) : isMe && userAvatar != null ? ( ) : ( renderSvg(size, initials) diff --git a/src/view/com/util/UserBanner.tsx b/src/view/com/util/UserBanner.tsx index bc2c4a9207..4a6fe246eb 100644 --- a/src/view/com/util/UserBanner.tsx +++ b/src/view/com/util/UserBanner.tsx @@ -1,4 +1,4 @@ -import React, {useCallback, useState} from 'react' +import React, {useCallback} from 'react' import {StyleSheet, View, TouchableOpacity, Alert, Image} from 'react-native' import Svg, {Rect, Defs, LinearGradient, Stop} from 'react-native-svg' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' @@ -10,23 +10,20 @@ import { openPicker, } from 'react-native-image-crop-picker' import {IMAGES_ENABLED} from '../../../build-flags' -import {ProfileViewModel} from '../../../state/models/profile-view' export function UserBanner({ handle, - profileView, + userBanner, isMe = false, - isEditable = false, + setUserBanner, }: { handle: string isMe?: boolean - profileView: ProfileViewModel - isEditable?: boolean + userBanner: string | null + setUserBanner?: React.Dispatch> }) { const gradient = getGradient(handle) - const [tempUserBanner, setTempUserBanner] = useState(null) - const handleEditBanner = useCallback(() => { Alert.alert('Select upload method', '', [ { @@ -38,8 +35,7 @@ export function UserBanner({ width: 1500, height: 500, }).then(item => { - profileView.updateUserBanner(item) - setTempUserBanner(item.path) + setUserBanner(item.path) }) }, }, @@ -55,14 +51,13 @@ export function UserBanner({ width: 1500, height: 500, }).then(croppedItem => { - profileView.updateUserBanner(croppedItem) - setTempUserBanner(croppedItem.path) + setUserBanner(croppedItem.path) }) }) }, }, ]) - }, [profileView]) + }, [setUserBanner]) const renderSvg = () => ( @@ -81,15 +76,12 @@ export function UserBanner({ ) - return isEditable && IMAGES_ENABLED ? ( + // setUserBanner is only passed as prop on the EditProfile component + return setUserBanner != null && IMAGES_ENABLED ? ( {/* Added a react state temporary photo while the protocol does not support imagery */} - {profileView.userBanner != null || tempUserBanner != null ? ( - + {userBanner != null ? ( + ) : ( renderSvg() )} @@ -101,11 +93,11 @@ export function UserBanner({ /> - ) : isMe && profileView.userBanner != null ? ( + ) : isMe && userBanner != null ? ( ) : ( renderSvg() From 80b8c7be09965f2725094fd84b3a610645e60311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreiro?= Date: Tue, 6 Dec 2022 15:08:19 +0000 Subject: [PATCH 16/17] remove unnecessary isMe prop --- src/view/com/profile/ProfileHeader.tsx | 7 +------ src/view/com/util/UserAvatar.tsx | 4 +--- src/view/com/util/UserBanner.tsx | 12 +++++++----- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx index 2642868fb2..d23be65a36 100644 --- a/src/view/com/profile/ProfileHeader.tsx +++ b/src/view/com/profile/ProfileHeader.tsx @@ -152,15 +152,10 @@ export const ProfileHeader = observer(function ProfileHeader({ } return ( - + > @@ -108,7 +106,7 @@ export function UserAvatar({ /> - ) : isMe && userAvatar != null ? ( + ) : userAvatar != null ? ( > }) { @@ -35,7 +33,9 @@ export function UserBanner({ width: 1500, height: 500, }).then(item => { - setUserBanner(item.path) + if (setUserBanner != null) { + setUserBanner(item.path) + } }) }, }, @@ -51,7 +51,9 @@ export function UserBanner({ width: 1500, height: 500, }).then(croppedItem => { - setUserBanner(croppedItem.path) + if (setUserBanner != null) { + setUserBanner(croppedItem.path) + } }) }) }, @@ -93,7 +95,7 @@ export function UserBanner({ /> - ) : isMe && userBanner != null ? ( + ) : userBanner != null ? ( Date: Tue, 6 Dec 2022 15:10:18 +0000 Subject: [PATCH 17/17] removing old comments --- src/view/com/util/UserAvatar.tsx | 1 - src/view/com/util/UserBanner.tsx | 1 - 2 files changed, 2 deletions(-) diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx index ea0ca1b634..8e5ac23097 100644 --- a/src/view/com/util/UserAvatar.tsx +++ b/src/view/com/util/UserAvatar.tsx @@ -92,7 +92,6 @@ export function UserAvatar({ // setUserAvatar is only passed as prop on the EditProfile component return setUserAvatar != null && IMAGES_ENABLED ? ( - {/* Added a react state temporary photo while the protocol does not support imagery */} {userAvatar != null ? ( ) : ( diff --git a/src/view/com/util/UserBanner.tsx b/src/view/com/util/UserBanner.tsx index e94bf04139..5a6d123a70 100644 --- a/src/view/com/util/UserBanner.tsx +++ b/src/view/com/util/UserBanner.tsx @@ -81,7 +81,6 @@ export function UserBanner({ // setUserBanner is only passed as prop on the EditProfile component return setUserBanner != null && IMAGES_ENABLED ? ( - {/* Added a react state temporary photo while the protocol does not support imagery */} {userBanner != null ? ( ) : (