Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions ts/components/dialog/EditProfilePictureModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ export const EditProfilePictureModal = ({ conversationId }: EditProfilePictureMo
const ourAvatarIsUploading = useOurAvatarIsUploading();
const ourAvatarUploadFailed = useOurAvatarUploadFailed();
const sogsAvatarIsUploading = useAvatarOfRoomIsUploading(conversationId);
const [isProcessing, setIsProcessing] = useState(false);

const [newAvatarObjectUrl, setNewAvatarObjectUrl] = useState<string | null>(avatarPath);
const [isNewAvatarAnimated, setIsNewAvatarAnimated] = useState<boolean>(false);
Expand Down Expand Up @@ -169,7 +170,7 @@ export const EditProfilePictureModal = ({ conversationId }: EditProfilePictureMo
const isPublic = useIsPublic(conversationId);

const handleAvatarClick = async () => {
const res = await pickFileForAvatar();
const res = await pickFileForAvatar(setIsProcessing);

if (!res) {
window.log.error('Failed to pick avatar');
Expand Down Expand Up @@ -210,7 +211,8 @@ export const EditProfilePictureModal = ({ conversationId }: EditProfilePictureMo
await triggerUploadProfileAvatar(newAvatarObjectUrl, conversationId, dispatch);
};

const loading = ourAvatarIsUploading || groupAvatarChangePending || sogsAvatarIsUploading;
const loading =
ourAvatarIsUploading || groupAvatarChangePending || sogsAvatarIsUploading || isProcessing;

const newAvatarLoaded = newAvatarObjectUrl !== avatarPath;

Expand Down Expand Up @@ -328,7 +330,7 @@ export const EditProfilePictureModal = ({ conversationId }: EditProfilePictureMo
{loading ? (
<>
<SpacerSM />
{isMe ? <Localizer token="updating" /> : null}
{isMe && !isProcessing ? <Localizer token="updating" /> : null}
<SessionSpinner loading={loading} height="30px" />
</>
) : (
Expand Down
7 changes: 6 additions & 1 deletion ts/types/attachments/VisualAttachment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,13 @@ async function pickFileForTestIntegration() {
/**
* Shows the system file picker for images, scale the image down for avatar/opengroup measurements and return the blob objectURL on success
*/
export async function pickFileForAvatar(): Promise<ProcessedAvatarDataType | null> {
export async function pickFileForAvatar(
processingCb: (isProcessing: boolean) => void
): Promise<ProcessedAvatarDataType | null> {
const file = isTestIntegration() ? await pickFileForTestIntegration() : await pickFileForReal();

try {
processingCb(true);
const arrayBuffer = await file.arrayBuffer();
// pickFileForAvatar is only used for avatars we want to be able to reupload (ourselves or 03-groups)
const processed = await processAvatarData(arrayBuffer, true);
Expand All @@ -244,5 +247,7 @@ export async function pickFileForAvatar(): Promise<ProcessedAvatarDataType | nul
);
window.log.error(e);
return null;
} finally {
processingCb(false);
}
}
29 changes: 18 additions & 11 deletions ts/webworker/workers/node/image_processor/image_processor.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,19 +127,23 @@ function metadataToFrameHeight(metadata: sharp.Metadata) {
*
* Note: this will also orient a jpeg if needed. (i.e. calls rotate() through sharpFrom)
* Note: metadata height will be set to the frame height, not the full height
* of the canvas (as sharp.metadata does with animated webps)
* of the canvas (as sharp.metadata does with animated webp)
*/
async function metadataFromBuffer(
inputBuffer: ArrayBufferLike | Buffer,
rethrow = false,
options?: sharp.SharpOptions
) {
// Note: this might throw and we want to allow the error to be forwarded to the user if that happens.
// A toast will display the error
try {
const metadata = await sharpFrom(inputBuffer, options).metadata();
const frameHeight = metadataToFrameHeight(metadata);
// we do need the await above so the try/catch does its job
return { ...metadata, height: frameHeight };
} catch (e) {
console.info('metadataFromBuffer failed with', e.message);
if (rethrow) {
throw e;
}
return null;
}
}
Expand Down Expand Up @@ -263,7 +267,7 @@ async function sleepFor(ms: number) {
async function processPlanForReuploadAvatar({ inputBuffer }: { inputBuffer: ArrayBufferLike }) {
const start = Date.now();

const metadata = await metadataFromBuffer(inputBuffer, { animated: true });
const metadata = await metadataFromBuffer(inputBuffer, true, { animated: true });
if (!metadata) {
return null;
}
Expand Down Expand Up @@ -365,7 +369,10 @@ async function processPlanForReuploadAvatar({ inputBuffer }: { inputBuffer: Arra
return null;
}

const resizedMetadataSize = metadataSizeIsSetOrThrow(resizedMetadata, 'processPlanForReuploadAvatar');
const resizedMetadataSize = metadataSizeIsSetOrThrow(
resizedMetadata,
'processPlanForReuploadAvatar'
);

logIfOn(
`[imageProcessorWorker] processPlanForReuploadAvatar mainAvatar resize took ${Date.now() - start}ms for ${inputBuffer.byteLength} bytes`
Expand Down Expand Up @@ -398,7 +405,7 @@ async function processPlanForReuploadAvatar({ inputBuffer }: { inputBuffer: Arra
async function processNoPlanForReuploadAvatar({ inputBuffer }: { inputBuffer: ArrayBufferLike }) {
const start = Date.now();
const sizeRequired = maxAvatarDetails.maxSideNoReuploadRequired;
const metadata = await metadataFromBuffer(inputBuffer, { animated: true });
const metadata = await metadataFromBuffer(inputBuffer, false, { animated: true });

if (!metadata) {
return null;
Expand Down Expand Up @@ -499,7 +506,7 @@ const workerActions: ImageProcessorWorkerActions = {
throw new Error('imageMetadata: inputBuffer is required');
}

const metadata = await metadataFromBuffer(inputBuffer, { animated: true });
const metadata = await metadataFromBuffer(inputBuffer, false, { animated: true });

if (!metadata) {
return null;
Expand Down Expand Up @@ -568,7 +575,7 @@ const workerActions: ImageProcessorWorkerActions = {
}

const parsed = sharpFrom(inputBuffer, { animated: false });
const metadata = await metadataFromBuffer(inputBuffer, { animated: false });
const metadata = await metadataFromBuffer(inputBuffer, false, { animated: false });

if (!metadata) {
return null;
Expand Down Expand Up @@ -609,7 +616,7 @@ const workerActions: ImageProcessorWorkerActions = {
const parsed = sharpFrom(inputBuffer, { animated: false }).resize(
centerCoverOpts({ maxSidePx, withoutEnlargement: false }) // We actually want to enlarge the image if required for a thumbnail in conversation
);
const metadata = await metadataFromBuffer(inputBuffer, { animated: false });
const metadata = await metadataFromBuffer(inputBuffer, false, { animated: false });

if (!metadata) {
return null;
Expand Down Expand Up @@ -657,7 +664,7 @@ const workerActions: ImageProcessorWorkerActions = {
}
const lossyFormats = ['jpeg', 'webp', 'avif'];
const start = Date.now();
const metadata = await metadataFromBuffer(inputBuffer);
const metadata = await metadataFromBuffer(inputBuffer, false);

if (
!metadata ||
Expand Down Expand Up @@ -761,7 +768,7 @@ const workerActions: ImageProcessorWorkerActions = {

if (buffer.length < maxSizeBytes) {
// eslint-disable-next-line no-await-in-loop
const outputMetadata = await metadataFromBuffer(buffer);
const outputMetadata = await metadataFromBuffer(buffer, false);

if (!outputMetadata) {
return null;
Expand Down
Loading