164 lines
4.4 KiB
JavaScript
164 lines
4.4 KiB
JavaScript
import { useTheme } from "@/hooks";
|
|
import { cancelUploads, clearUploadError } from "@/redux/photos/photos.actions";
|
|
import { formatBytes } from "@/util/uploadUtils";
|
|
import { useMemo } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { ScrollView, StyleSheet, View } from "react-native";
|
|
import {
|
|
Button,
|
|
Divider,
|
|
Modal,
|
|
Portal,
|
|
ProgressBar,
|
|
Text,
|
|
} from "react-native-paper";
|
|
import { connect } from "react-redux";
|
|
import { createStructuredSelector } from "reselect";
|
|
import {
|
|
selectPhotos,
|
|
selectUploadError,
|
|
selectUploadProgress,
|
|
} from "../../redux/photos/photos.selectors";
|
|
|
|
const mapStateToProps = createStructuredSelector({
|
|
photos: selectPhotos,
|
|
photoUploadProgress: selectUploadProgress,
|
|
uploadError: selectUploadError,
|
|
});
|
|
const mapDispatchToProps = (dispatch) => ({
|
|
clearError: () => dispatch(clearUploadError()),
|
|
cancelUploads: () => dispatch(cancelUploads()),
|
|
});
|
|
|
|
export default connect(mapStateToProps, mapDispatchToProps)(UploadProgress);
|
|
|
|
export function UploadProgress({
|
|
photos,
|
|
photoUploadProgress,
|
|
uploadError,
|
|
clearError,
|
|
cancelUploads,
|
|
}) {
|
|
const { t } = useTranslation();
|
|
const theme = useTheme();
|
|
|
|
const completion = useMemo(() => {
|
|
const total = Object.keys(photoUploadProgress).length;
|
|
if (total === 0) return 0;
|
|
const completed = Object.values(photoUploadProgress).filter(
|
|
(p) => p.progress === 1
|
|
).length;
|
|
return completed / total;
|
|
}, [photoUploadProgress]);
|
|
|
|
const handleCancelUploads = () => {
|
|
cancelUploads();
|
|
};
|
|
|
|
return (
|
|
<Portal>
|
|
<Modal
|
|
visible={photos?.length > 0}
|
|
style={styles.modalOuter} // add
|
|
contentContainerStyle={[
|
|
styles.modalContainer,
|
|
{ backgroundColor: theme.colors.elevation.level1 },
|
|
]}
|
|
>
|
|
<ScrollView style={styles.modalFill}>
|
|
<Text variant="titleLarge" style={styles.title}>
|
|
{t("general.labels.upload")}
|
|
</Text>
|
|
<Text variant="labelLarge">
|
|
{`${t("general.labels.uploadprogress")} ${Math.round(
|
|
completion * 100
|
|
)}%`}
|
|
</Text>
|
|
<ProgressBar
|
|
progress={completion}
|
|
style={styles.progress}
|
|
color={completion === 1 ? "green" : "blue"}
|
|
/>
|
|
<Divider style={{ marginVertical: 12 }} />
|
|
{Object.keys(photoUploadProgress).map((key) => (
|
|
<View key={key} style={styles.progressItem}>
|
|
<Text
|
|
style={styles.progressText}
|
|
numberOfLines={1}
|
|
ellipsizeMode="tail"
|
|
>
|
|
{photoUploadProgress[key].fileName}
|
|
</Text>
|
|
<View style={styles.progressBarContainer}>
|
|
<ProgressBar
|
|
progress={photoUploadProgress[key].progress || 0}
|
|
style={styles.progress}
|
|
color={
|
|
photoUploadProgress[key].progress === 1 ? "green" : "blue"
|
|
}
|
|
/>
|
|
<View style={styles.speedRow}>
|
|
<Text>{`${formatBytes(
|
|
photoUploadProgress[key].loaded /
|
|
(((photoUploadProgress[key].endTime || new Date()) -
|
|
photoUploadProgress[key].startTime) /
|
|
1000)
|
|
)}/sec`}</Text>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
))}
|
|
<Button onPress={handleCancelUploads}>
|
|
{t("general.actions.cancel")}
|
|
</Button>
|
|
</ScrollView>
|
|
</Modal>
|
|
</Portal>
|
|
);
|
|
}
|
|
const styles = StyleSheet.create({
|
|
modalOuter: {
|
|
flex: 1, // ensure outer container can grow,
|
|
paddingHorizontal: 24,
|
|
paddingVertical: 72,
|
|
},
|
|
modalContainer: {
|
|
width: "100%",
|
|
height: "50%", // force full area (important for iOS)
|
|
padding: 24,
|
|
justifyContent: "center",
|
|
borderRadius: 24,
|
|
},
|
|
modalFill: {
|
|
flex: 1,
|
|
},
|
|
speedRow: {
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
},
|
|
title: {
|
|
alignSelf: "center",
|
|
alignItems: "center",
|
|
marginBottom: 12,
|
|
paddingLeft: 12,
|
|
paddingRight: 12,
|
|
},
|
|
progressItem: {
|
|
display: "flex",
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
marginBottom: 12,
|
|
marginLeft: 12,
|
|
marginRight: 12,
|
|
},
|
|
progressText: {
|
|
flex: 1,
|
|
flexShrink: 1,
|
|
},
|
|
progressBarContainer: {
|
|
flex: 3,
|
|
marginLeft: 12,
|
|
marginRight: 12,
|
|
},
|
|
});
|