Sticker pack download: require just one successful sticker download
This commit is contained in:
parent
3620309f22
commit
5a7196e464
5 changed files with 159 additions and 57 deletions
|
@ -5756,6 +5756,7 @@ button.module-image__border-overlay:focus {
|
|||
grid-gap: 8px;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding: 0 16px;
|
||||
|
||||
&::after {
|
||||
|
|
|
@ -692,13 +692,6 @@ export async function startApp(): Promise<void> {
|
|||
await window.Signal.Services.eraseAllStorageServiceState();
|
||||
}
|
||||
|
||||
if (
|
||||
lastVersion === 'v1.40.0-beta.1' &&
|
||||
window.isAfterVersion(lastVersion, 'v1.40.0-beta.1')
|
||||
) {
|
||||
await window.Signal.Data.clearAllErrorStickerPackAttempts();
|
||||
}
|
||||
|
||||
if (window.isBeforeVersion(lastVersion, 'v5.2.0')) {
|
||||
const legacySenderCertificateStorageKey = 'senderCertificateWithUuid';
|
||||
await removeStorageKeyJobQueue.add({
|
||||
|
@ -715,6 +708,10 @@ export async function startApp(): Promise<void> {
|
|||
await window.storage.remove(GROUP_CREDENTIALS_KEY);
|
||||
}
|
||||
|
||||
if (window.isBeforeVersion(lastVersion, 'v5.37.0-alpha')) {
|
||||
await window.Signal.Data.clearAllErrorStickerPackAttempts();
|
||||
}
|
||||
|
||||
// This one should always be last - it could restart the app
|
||||
if (window.isBeforeVersion(lastVersion, 'v5.30.0-alpha')) {
|
||||
await deleteAllLogs();
|
||||
|
|
|
@ -17,27 +17,30 @@ import {
|
|||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
|
||||
storiesOf('Components/Stickers/StickerPreviewModal', module).add('Full', () => {
|
||||
const book = storiesOf('Components/Stickers/StickerPreviewModal', module);
|
||||
|
||||
const abeSticker = {
|
||||
id: -1,
|
||||
emoji: '🎩',
|
||||
url: squareStickerUrl,
|
||||
packId: 'abe',
|
||||
};
|
||||
const wideSticker = {
|
||||
id: -2,
|
||||
emoji: '🤯',
|
||||
url: landscapeGreenUrl,
|
||||
packId: 'wide',
|
||||
};
|
||||
const tallSticker = {
|
||||
id: -3,
|
||||
emoji: '🔥',
|
||||
url: portraitTealUrl,
|
||||
packId: 'tall',
|
||||
};
|
||||
|
||||
book.add('Full', () => {
|
||||
const title = text('title', 'Foo');
|
||||
const author = text('author', 'Foo McBarrington');
|
||||
const abeSticker = {
|
||||
id: -1,
|
||||
emoji: '🎩',
|
||||
url: squareStickerUrl,
|
||||
packId: 'abe',
|
||||
};
|
||||
const wideSticker = {
|
||||
id: -2,
|
||||
emoji: '🤯',
|
||||
url: landscapeGreenUrl,
|
||||
packId: 'wide',
|
||||
};
|
||||
const tallSticker = {
|
||||
id: -3,
|
||||
emoji: '🔥',
|
||||
url: portraitTealUrl,
|
||||
packId: 'tall',
|
||||
};
|
||||
|
||||
const pack = {
|
||||
id: 'foo',
|
||||
|
@ -69,3 +72,59 @@ storiesOf('Components/Stickers/StickerPreviewModal', module).add('Full', () => {
|
|||
/>
|
||||
);
|
||||
});
|
||||
|
||||
book.add('Just four stickers', () => {
|
||||
const title = text('title', 'Foo');
|
||||
const author = text('author', 'Foo McBarrington');
|
||||
|
||||
const pack = {
|
||||
id: 'foo',
|
||||
key: 'foo',
|
||||
lastUsed: Date.now(),
|
||||
cover: abeSticker,
|
||||
title,
|
||||
isBlessed: true,
|
||||
author,
|
||||
status: 'downloaded' as const,
|
||||
stickerCount: 101,
|
||||
stickers: [abeSticker, abeSticker, abeSticker, abeSticker],
|
||||
};
|
||||
|
||||
return (
|
||||
<StickerPreviewModal
|
||||
onClose={action('onClose')}
|
||||
installStickerPack={action('installStickerPack')}
|
||||
uninstallStickerPack={action('uninstallStickerPack')}
|
||||
downloadStickerPack={action('downloadStickerPack')}
|
||||
i18n={i18n}
|
||||
pack={pack}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
book.add('Initial download', () => {
|
||||
return (
|
||||
<StickerPreviewModal
|
||||
onClose={action('onClose')}
|
||||
installStickerPack={action('installStickerPack')}
|
||||
uninstallStickerPack={action('uninstallStickerPack')}
|
||||
downloadStickerPack={action('downloadStickerPack')}
|
||||
i18n={i18n}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
pack={{} as any}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
book.add('Pack deleted', () => {
|
||||
return (
|
||||
<StickerPreviewModal
|
||||
onClose={action('onClose')}
|
||||
installStickerPack={action('installStickerPack')}
|
||||
uninstallStickerPack={action('uninstallStickerPack')}
|
||||
downloadStickerPack={action('downloadStickerPack')}
|
||||
i18n={i18n}
|
||||
pack={undefined}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -28,6 +28,10 @@ export type OwnProps = {
|
|||
export type Props = OwnProps;
|
||||
|
||||
function renderBody({ pack, i18n }: Props) {
|
||||
if (!pack) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (pack && pack.status === 'error') {
|
||||
return (
|
||||
<div className="module-sticker-manager__preview-modal__container__error">
|
||||
|
@ -36,7 +40,7 @@ function renderBody({ pack, i18n }: Props) {
|
|||
);
|
||||
}
|
||||
|
||||
if (!pack || pack.stickerCount === 0 || !isNumber(pack.stickerCount)) {
|
||||
if (pack.stickerCount === 0 || !isNumber(pack.stickerCount)) {
|
||||
return <Spinner svgSize="normal" />;
|
||||
}
|
||||
|
||||
|
@ -54,15 +58,16 @@ function renderBody({ pack, i18n }: Props) {
|
|||
/>
|
||||
</div>
|
||||
))}
|
||||
{range(pack.stickerCount - pack.stickers.length).map(i => (
|
||||
<div
|
||||
key={`placeholder-${i}`}
|
||||
className={classNames(
|
||||
'module-sticker-manager__preview-modal__container__sticker-grid__cell',
|
||||
'module-sticker-manager__preview-modal__container__sticker-grid__cell--placeholder'
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
{pack.status === 'pending' &&
|
||||
range(pack.stickerCount - pack.stickers.length).map(i => (
|
||||
<div
|
||||
key={`placeholder-${i}`}
|
||||
className={classNames(
|
||||
'module-sticker-manager__preview-modal__container__sticker-grid__cell',
|
||||
'module-sticker-manager__preview-modal__container__sticker-grid__cell--placeholder'
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -110,6 +115,12 @@ export const StickerPreviewModal = React.memo((props: Props) => {
|
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!pack) {
|
||||
onClose();
|
||||
}
|
||||
}, [pack, onClose]);
|
||||
|
||||
const isInstalled = Boolean(pack && pack.status === 'installed');
|
||||
const handleToggleInstall = React.useCallback(() => {
|
||||
if (!pack) {
|
||||
|
|
|
@ -10,6 +10,7 @@ import { dropNull } from '../util/dropNull';
|
|||
import { makeLookup } from '../util/makeLookup';
|
||||
import { maybeParseUrl } from '../util/url';
|
||||
import * as Bytes from '../Bytes';
|
||||
import * as Errors from './errors';
|
||||
import { deriveStickerPackKey, decryptAttachment } from '../Crypto';
|
||||
import type { MIMEType } from './MIME';
|
||||
import { IMAGE_WEBP } from './MIME';
|
||||
|
@ -224,20 +225,17 @@ function doesPackNeedDownload(pack?: StickerPackType): boolean {
|
|||
}
|
||||
|
||||
const { status, stickerCount } = pack;
|
||||
const stickersDownloaded = Object.keys(pack.stickers || {}).length;
|
||||
|
||||
if (
|
||||
(status === 'installed' || status === 'downloaded') &&
|
||||
stickerCount > 0 &&
|
||||
stickersDownloaded >= stickerCount
|
||||
) {
|
||||
if ((status === 'installed' || status === 'downloaded') && stickerCount > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we don't understand a pack's status, we'll download it
|
||||
// If a pack has any other status, we'll download it
|
||||
// If a pack has zero stickers in it, we'll download it
|
||||
// If a pack doesn't have enough downloaded stickers, we'll download it
|
||||
|
||||
// Note: If a pack downloaded with less than the expected number of stickers, we're
|
||||
// okay with that.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -439,10 +437,20 @@ export async function downloadEphemeralPack(
|
|||
|
||||
const downloadStickerJob = async (
|
||||
stickerProto: Proto.StickerPack.ISticker
|
||||
): Promise<void> => {
|
||||
const stickerInfo = await downloadSticker(packId, packKey, stickerProto, {
|
||||
ephemeral: true,
|
||||
});
|
||||
): Promise<boolean> => {
|
||||
let stickerInfo;
|
||||
try {
|
||||
stickerInfo = await downloadSticker(packId, packKey, stickerProto, {
|
||||
ephemeral: true,
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
log.error(
|
||||
`downloadEphemeralPack/downloadStickerJob error: ${Errors.toLogFormat(
|
||||
error
|
||||
)}`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
const sticker = {
|
||||
...stickerInfo,
|
||||
isCoverOnly: !coverIncludedInList && stickerInfo.id === coverStickerId,
|
||||
|
@ -458,15 +466,21 @@ export async function downloadEphemeralPack(
|
|||
}
|
||||
|
||||
stickerAdded(sticker);
|
||||
return true;
|
||||
};
|
||||
|
||||
// Download the cover first
|
||||
await downloadStickerJob(coverProto);
|
||||
|
||||
// Then the rest
|
||||
await pMap(nonCoverStickers, downloadStickerJob, {
|
||||
const jobResults = await pMap(nonCoverStickers, downloadStickerJob, {
|
||||
concurrency: 3,
|
||||
});
|
||||
|
||||
const successfulStickerCount = jobResults.filter(item => item).length;
|
||||
if (successfulStickerCount === 0) {
|
||||
throw new Error('downloadEphemeralPack: All stickers failed to download');
|
||||
}
|
||||
} catch (error) {
|
||||
// Because the user could install this pack while we are still downloading this
|
||||
// ephemeral pack, we don't want to go change its status unless we're still in
|
||||
|
@ -657,24 +671,44 @@ async function doDownloadStickerPack(
|
|||
try {
|
||||
const downloadStickerJob = async (
|
||||
stickerProto: Proto.StickerPack.ISticker
|
||||
): Promise<void> => {
|
||||
const stickerInfo = await downloadSticker(packId, packKey, stickerProto);
|
||||
const sticker = {
|
||||
...stickerInfo,
|
||||
isCoverOnly: !coverIncludedInList && stickerInfo.id === coverStickerId,
|
||||
};
|
||||
await Data.createOrUpdateSticker(sticker);
|
||||
stickerAdded(sticker);
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
const stickerInfo = await downloadSticker(
|
||||
packId,
|
||||
packKey,
|
||||
stickerProto
|
||||
);
|
||||
const sticker = {
|
||||
...stickerInfo,
|
||||
isCoverOnly:
|
||||
!coverIncludedInList && stickerInfo.id === coverStickerId,
|
||||
};
|
||||
await Data.createOrUpdateSticker(sticker);
|
||||
stickerAdded(sticker);
|
||||
return true;
|
||||
} catch (error: unknown) {
|
||||
log.error(
|
||||
`doDownloadStickerPack/downloadStickerJob error: ${Errors.toLogFormat(
|
||||
error
|
||||
)}`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Download the cover first
|
||||
await downloadStickerJob(coverProto);
|
||||
|
||||
// Then the rest
|
||||
await pMap(nonCoverStickers, downloadStickerJob, {
|
||||
const jobResults = await pMap(nonCoverStickers, downloadStickerJob, {
|
||||
concurrency: 3,
|
||||
});
|
||||
|
||||
const successfulStickerCount = jobResults.filter(item => item).length;
|
||||
if (successfulStickerCount === 0) {
|
||||
throw new Error('doDownloadStickerPack: All stickers failed to download');
|
||||
}
|
||||
|
||||
// Allow for the user marking this pack as installed in the middle of our download;
|
||||
// don't overwrite that status.
|
||||
const existingStatus = getStickerPackStatus(packId);
|
||||
|
|
Loading…
Add table
Reference in a new issue