diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/state/models/profile-view.ts | 22 | ||||
-rw-r--r-- | src/view/com/modals/EditProfile.tsx | 15 | ||||
-rw-r--r-- | src/view/com/profile/ProfileHeader.tsx | 2 | ||||
-rw-r--r-- | src/view/com/util/UserBanner.tsx | 46 |
4 files changed, 50 insertions, 35 deletions
diff --git a/src/state/models/profile-view.ts b/src/state/models/profile-view.ts index 787e69e3f..9b32c8744 100644 --- a/src/state/models/profile-view.ts +++ b/src/state/models/profile-view.ts @@ -39,15 +39,13 @@ export class ProfileViewModel { displayName?: string description?: string avatar?: string + banner?: string followersCount: number = 0 followsCount: number = 0 membersCount: number = 0 postsCount: number = 0 myState = new ProfileViewMyStateModel() - // TODO TEMP data to be implemented in the protocol - userBanner: string | null = null - // added data descriptionEntities?: Entity[] @@ -123,11 +121,8 @@ export class ProfileViewModel { async updateProfile( updates: Profile.Record, newUserAvatar: PickedImage | undefined, - userBanner: string | null, // TODO TEMP + newUserBanner: PickedImage | undefined, ) { - // TODO TEMP add userBanner to the protocol when suported - this.userBanner = userBanner - if (newUserAvatar) { const res = await this.rootStore.api.com.atproto.blob.upload( newUserAvatar.path, // this will be special-cased by the fetch monkeypatch in /src/state/lib/api.ts @@ -140,6 +135,18 @@ export class ProfileViewModel { mimeType: newUserAvatar.mime, } } + if (newUserBanner) { + const res = await this.rootStore.api.com.atproto.blob.upload( + newUserBanner.path, // this will be special-cased by the fetch monkeypatch in /src/state/lib/api.ts + { + encoding: newUserBanner.mime, + }, + ) + updates.banner = { + cid: res.data.cid, + mimeType: newUserBanner.mime, + } + } await this.rootStore.api.app.bsky.actor.updateProfile(updates) await this.rootStore.me.load() await this.refresh() @@ -187,6 +194,7 @@ export class ProfileViewModel { this.displayName = res.data.displayName this.description = res.data.description this.avatar = res.data.avatar + this.banner = res.data.banner this.followersCount = res.data.followersCount this.followsCount = res.data.followsCount this.membersCount = res.data.membersCount diff --git a/src/view/com/modals/EditProfile.tsx b/src/view/com/modals/EditProfile.tsx index cf89f1822..dcb0ba834 100644 --- a/src/view/com/modals/EditProfile.tsx +++ b/src/view/com/modals/EditProfile.tsx @@ -41,12 +41,13 @@ export function Component({ const [description, setDescription] = useState<string>( profileView.description || '', ) - const [userBanner, setUserBanner] = useState<string | null>( - profileView.userBanner, + const [userBanner, setUserBanner] = useState<string | undefined>( + profileView.banner, ) const [userAvatar, setUserAvatar] = useState<string | undefined>( profileView.avatar, ) + const [newUserBanner, setNewUserBanner] = useState<PickedImage | undefined>() const [newUserAvatar, setNewUserAvatar] = useState<PickedImage | undefined>() const onPressCancel = () => { store.shell.closeModal() @@ -55,6 +56,10 @@ export function Component({ setNewUserAvatar(img) setUserAvatar(img.path) } + const onSelectNewBanner = (img: PickedImage) => { + setNewUserBanner(img) + setUserBanner(img.path) + } const onPressSave = async () => { setProcessing(true) if (error) { @@ -67,7 +72,7 @@ export function Component({ description, }, newUserAvatar, - userBanner, // TEMP + newUserBanner, ) Toast.show('Profile updated') onUpdate?.() @@ -90,8 +95,8 @@ export function Component({ <Text style={styles.title}>Edit my profile</Text> <View style={styles.photos}> <UserBanner - userBanner={userBanner} - setUserBanner={setUserBanner} + banner={userBanner} + onSelectNewBanner={onSelectNewBanner} handle={profileView.handle} /> <View style={styles.avi}> diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx index fb31c1847..eb0a7477c 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 ( <View style={styles.outer}> - <UserBanner handle={view.handle} userBanner={view.userBanner} /> + <UserBanner handle={view.handle} banner={view.banner} /> <View style={styles.avi}> <UserAvatar size={80} diff --git a/src/view/com/util/UserBanner.tsx b/src/view/com/util/UserBanner.tsx index b0c6bb165..697e900b1 100644 --- a/src/view/com/util/UserBanner.tsx +++ b/src/view/com/util/UserBanner.tsx @@ -2,6 +2,7 @@ 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' +import {Image as PickedImage} from 'react-native-image-crop-picker' import {getGradient} from '../../lib/asset-gen' import {colors} from '../../lib/styles' import { @@ -9,16 +10,15 @@ import { openCropper, openPicker, } from 'react-native-image-crop-picker' -import {IMAGES_ENABLED} from '../../../build-flags' export function UserBanner({ handle, - userBanner, - setUserBanner, + banner, + onSelectNewBanner, }: { handle: string - userBanner?: string | null - setUserBanner?: React.Dispatch<React.SetStateAction<string | null>> + banner?: string | null + onSelectNewBanner?: (img: PickedImage) => void }) { const gradient = getGradient(handle) @@ -30,13 +30,14 @@ export function UserBanner({ openCamera({ mediaType: 'photo', cropping: true, + compressImageMaxWidth: 1500, width: 1500, + compressImageMaxHeight: 500, height: 500, - }).then(item => { - if (setUserBanner != null) { - setUserBanner(item.path) - } - }) + forceJpg: true, // ios only + compressImageQuality: 0.4, + includeExif: true, + }).then(onSelectNewBanner) }, }, { @@ -48,18 +49,19 @@ export function UserBanner({ await openCropper({ mediaType: 'photo', path: item.path, + compressImageMaxWidth: 1500, width: 1500, + compressImageMaxHeight: 500, height: 500, - }).then(croppedItem => { - if (setUserBanner != null) { - setUserBanner(croppedItem.path) - } - }) + forceJpg: true, // ios only + compressImageQuality: 0.4, + includeExif: true, + }).then(onSelectNewBanner) }) }, }, ]) - }, [setUserBanner]) + }, [onSelectNewBanner]) const renderSvg = () => ( <Svg width="100%" height="120" viewBox="50 0 200 100"> @@ -79,10 +81,10 @@ export function UserBanner({ ) // setUserBanner is only passed as prop on the EditProfile component - return setUserBanner != null && IMAGES_ENABLED ? ( + return onSelectNewBanner ? ( <TouchableOpacity onPress={handleEditBanner}> - {userBanner ? ( - <Image style={styles.bannerImage} source={{uri: userBanner}} /> + {banner ? ( + <Image style={styles.bannerImage} source={{uri: banner}} /> ) : ( renderSvg() )} @@ -94,11 +96,11 @@ export function UserBanner({ /> </View> </TouchableOpacity> - ) : userBanner ? ( + ) : banner ? ( <Image style={styles.bannerImage} - resizeMode="stretch" - source={{uri: userBanner}} + resizeMode="cover" + source={{uri: banner}} /> ) : ( renderSvg() |