adding loading indicator for sealed assets

This commit is contained in:
Roland Osborne 2023-05-05 16:08:56 -07:00
parent da8b7e6bab
commit a30f1f3e4e
10 changed files with 34 additions and 8 deletions

View File

@ -1,9 +1,10 @@
import React, { useEffect, useState, useRef } from 'react'; import React, { useEffect, useState, useRef } from 'react';
import { Modal, Spin } from 'antd'; import { Progress, Modal, Spin } from 'antd';
import ReactResizeDetector from 'react-resize-detector'; import ReactResizeDetector from 'react-resize-detector';
import { PlayCircleOutlined, MinusCircleOutlined, SoundOutlined } from '@ant-design/icons'; import { PlayCircleOutlined, MinusCircleOutlined, SoundOutlined } from '@ant-design/icons';
import { AudioAssetWrapper, AudioModalWrapper } from './AudioAsset.styled'; import { AudioAssetWrapper, AudioModalWrapper } from './AudioAsset.styled';
import { useAudioAsset } from './useAudioAsset.hook'; import { useAudioAsset } from './useAudioAsset.hook';
import Colors from 'constants/Colors';
import background from 'images/audio.png'; import background from 'images/audio.png';
@ -56,6 +57,9 @@ export function AudioAsset({ asset }) {
{ state.loading && !state.error && ( { state.loading && !state.error && (
<div class="loading"> <div class="loading">
<Spin size="large" delay={250} /> <Spin size="large" delay={250} />
{ state.total != 0 && (
<Progress percent={Math.floor(100 * state.block / state.total)} size="small" showInfo={false} trailColor={Colors.white} strokeColor={Colors.background} />
)}
</div> </div>
)} )}
{ !state.ready && !state.loading && ( { !state.ready && !state.loading && (

View File

@ -80,6 +80,8 @@ export const AudioModalWrapper = styled.div`
position: absolute; position: absolute;
color: white; color: white;
border-radius: 8px; border-radius: 8px;
display: flex;
flex-direction: column;
.ant-spin-dot-item { .ant-spin-dot-item {
background-color: ${Colors.white}; background-color: ${Colors.white};

View File

@ -11,6 +11,8 @@ export function useAudioAsset(asset) {
error: false, error: false,
ready: false, ready: false,
url: null, url: null,
block: 0,
total: 0,
}); });
const updateState = (value) => { const updateState = (value) => {
@ -23,7 +25,7 @@ export function useAudioAsset(asset) {
try { try {
const view = index.current; const view = index.current;
updateState({ active: true, ready: false, error: false, loading: true, url: null }); updateState({ active: true, ready: false, error: false, loading: true, url: null });
const blob = await asset.getDecryptedBlob(() => view != index.current); const blob = await asset.getDecryptedBlob(() => view != index.current, (block, total) => updateState({ block, total }));
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
revoke.current = url; revoke.current = url;
updateState({ loading: false, url }); updateState({ loading: false, url });

View File

@ -1,8 +1,9 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Modal, Spin } from 'antd'; import { Progress, Modal, Spin } from 'antd';
import ReactResizeDetector from 'react-resize-detector'; import ReactResizeDetector from 'react-resize-detector';
import { ImageAssetWrapper, ImageModalWrapper } from './ImageAsset.styled'; import { ImageAssetWrapper, ImageModalWrapper } from './ImageAsset.styled';
import { useImageAsset } from './useImageAsset.hook'; import { useImageAsset } from './useImageAsset.hook';
import Colors from 'constants/Colors';
export function ImageAsset({ asset }) { export function ImageAsset({ asset }) {
@ -42,6 +43,9 @@ export function ImageAsset({ asset }) {
{ !state.error && ( { !state.error && (
<div class="loading"> <div class="loading">
<Spin size="large" delay={250} /> <Spin size="large" delay={250} />
{ state.total != 0 && (
<Progress percent={Math.floor(100 * state.block / state.total)} size="small" showInfo={false} trailColor={Colors.white} strokeColor={Colors.background} />
)}
</div> </div>
)} )}
{ state.error && ( { state.error && (

View File

@ -76,6 +76,8 @@ export const ImageModalWrapper = styled.div`
position: absolute; position: absolute;
color: white; color: white;
border-radius: 8px; border-radius: 8px;
display: flex;
flex-direction: column;
.ant-spin-dot-item { .ant-spin-dot-item {
background-color: ${Colors.white}; background-color: ${Colors.white};

View File

@ -12,6 +12,8 @@ export function useImageAsset(asset) {
loading: false, loading: false,
error: false, error: false,
url: null, url: null,
block: 0,
total: 0,
}); });
const updateState = (value) => { const updateState = (value) => {
@ -24,7 +26,7 @@ export function useImageAsset(asset) {
try { try {
const view = index.current; const view = index.current;
updateState({ popout: true, width, height, error: false, loading: true, url: null }); updateState({ popout: true, width, height, error: false, loading: true, url: null });
const blob = await asset.getDecryptedBlob(() => view != index.current); const blob = await asset.getDecryptedBlob(() => view != index.current, (block, total) => updateState({ block, total }));
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
updateState({ loading: false, url }); updateState({ loading: false, url });
revoke.current = url; revoke.current = url;

View File

@ -30,7 +30,7 @@ export function useTopicItem(topic, contentKey) {
if (asset.encrypted) { if (asset.encrypted) {
const encrypted = true; const encrypted = true;
const { type, thumb, label, parts } = asset.encrypted; const { type, thumb, label, parts } = asset.encrypted;
const getDecryptedBlob = async (abort) => { const getDecryptedBlob = async (abort, progress) => {
let pos = 0; let pos = 0;
let len = 0; let len = 0;
@ -39,6 +39,7 @@ export function useTopicItem(topic, contentKey) {
if (abort()) { if (abort()) {
throw new Error("asset unseal aborted"); throw new Error("asset unseal aborted");
} }
progress(i, parts.length);
const part = parts[i]; const part = parts[i];
const url = topic.assetUrl(part.partId, topic.id); const url = topic.assetUrl(part.partId, topic.id);
const response = await fetchWithTimeout(url, { method: 'GET' }); const response = await fetchWithTimeout(url, { method: 'GET' });
@ -48,6 +49,7 @@ export function useTopicItem(topic, contentKey) {
slices.push(slice); slices.push(slice);
len += slice.byteLength; len += slice.byteLength;
}; };
progress(parts.length, parts.length);
const data = new Uint8Array(len) const data = new Uint8Array(len)
for (let i = 0; i < slices.length; i++) { for (let i = 0; i < slices.length; i++) {

View File

@ -1,8 +1,9 @@
import { Modal, Spin } from 'antd'; import { Modal, Spin, Progress } from 'antd';
import ReactResizeDetector from 'react-resize-detector'; import ReactResizeDetector from 'react-resize-detector';
import { VideoCameraOutlined } from '@ant-design/icons'; import { VideoCameraOutlined } from '@ant-design/icons';
import { VideoAssetWrapper, VideoModalWrapper } from './VideoAsset.styled'; import { VideoAssetWrapper, VideoModalWrapper } from './VideoAsset.styled';
import { useVideoAsset } from './useVideoAsset.hook'; import { useVideoAsset } from './useVideoAsset.hook';
import Colors from 'constants/Colors';
export function VideoAsset({ asset }) { export function VideoAsset({ asset }) {
@ -51,6 +52,9 @@ export function VideoAsset({ asset }) {
{ !state.error && ( { !state.error && (
<div class="loading"> <div class="loading">
<Spin size="large" delay={250} /> <Spin size="large" delay={250} />
{ state.total != 0 && (
<Progress percent={Math.floor(100 * state.block / state.total)} size="small" showInfo={false} trailColor={Colors.white} strokeColor={Colors.background} />
)}
</div> </div>
)} )}
</div> </div>

View File

@ -48,6 +48,8 @@ export const VideoModalWrapper = styled.div`
position: absolute; position: absolute;
color: white; color: white;
border-radius: 8px; border-radius: 8px;
display: flex;
flex-direction: column;
.ant-spin-dot-item { .ant-spin-dot-item {
background-color: ${Colors.white}; background-color: ${Colors.white};

View File

@ -14,6 +14,8 @@ export function useVideoAsset(asset) {
error: false, error: false,
url: null, url: null,
loaded: false, loaded: false,
block: 0,
total: 0,
}); });
const updateState = (value) => { const updateState = (value) => {
@ -26,7 +28,7 @@ export function useVideoAsset(asset) {
try { try {
const view = index.current; const view = index.current;
updateState({ active: true, width, height, error: false, loaded: false, loading: true, url: null }); updateState({ active: true, width, height, error: false, loaded: false, loading: true, url: null });
const blob = await asset.getDecryptedBlob(() => view != index.current); const blob = await asset.getDecryptedBlob(() => view != index.current, (block, total) => updateState({ block, total }));
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
revoke.current = url; revoke.current = url;
updateState({ url, loading: false }); updateState({ url, loading: false });