From ac5dea602a7f5be68fd2d96b2cc7509c272b7d44 Mon Sep 17 00:00:00 2001 From: Der_Googler <54764558+DerGoogler@users.noreply.github.com> Date: Sun, 18 Aug 2024 15:23:00 +0200 Subject: [PATCH] module download improvements --- src/activitys/ModuleViewActivity/index.tsx | 58 +++----------- .../ModuleViewActivity/tabs/VersionsTab.tsx | 22 ++++-- src/components/AvatarWithProgress.tsx | 75 +++++++++++++++++++ src/hooks/useDownloadModule.ts | 47 ++++++++++++ src/native/Download.ts | 3 + src/native/Environment.ts | 20 ++++- src/native/IsolatedEval/index.ts | 4 + 7 files changed, 170 insertions(+), 59 deletions(-) create mode 100644 src/components/AvatarWithProgress.tsx create mode 100644 src/hooks/useDownloadModule.ts diff --git a/src/activitys/ModuleViewActivity/index.tsx b/src/activitys/ModuleViewActivity/index.tsx index 91251361..d7e17525 100644 --- a/src/activitys/ModuleViewActivity/index.tsx +++ b/src/activitys/ModuleViewActivity/index.tsx @@ -34,6 +34,8 @@ import { useFormatBytes } from "@Hooks/useFormatBytes"; import LinearProgress from "@mui/material/LinearProgress"; import { Download } from "@Native/Download"; import { Environment } from "@Native/Environment"; +import { useDownloadModule } from "@Hooks/useDownloadModule"; +import { AvatarWithProgress } from "@Components/AvatarWithProgress"; function a11yProps(index: number) { return { @@ -137,7 +139,7 @@ const ModuleViewActivity = () => { const cconfirm = useConfirm(); - const [downloadProgress, setDownloadProgress] = React.useState(0); + const [startDL, progress] = useDownloadModule(); return ( <Page @@ -217,7 +219,8 @@ const ModuleViewActivity = () => { width: "100%", }} > - <Avatar + <AvatarWithProgress + value={progress} alt={name} sx={(theme) => ({ bgcolor: theme.palette.primary.dark, @@ -225,15 +228,15 @@ const ModuleViewActivity = () => { height: 100, boxShadow: "0 -1px 5px rgba(0,0,0,.09), 0 3px 5px rgba(0,0,0,.06), 0 1px 2px rgba(0,0,0,.3), 0 1px 3px rgba(0,0,0,.15)", borderRadius: "20%", - mr: 1.5, fontSize: 50, })} src={icon} + progressTextVariant="body2" > {name.charAt(0).toUpperCase()} - </Avatar> + </AvatarWithProgress> - <Box sx={{ alignSelf: "center", ml: 0.5, mr: 0.5, width: "100%" }}> + <Box sx={{ alignSelf: "center", ml: 2, mr: 0.5, width: "100%" }}> <Stack direction="row" justifyContent="flex-start" alignItems="center" spacing={0.5}> <Disappear as={Typography} variant="body1" fontWeight="bold" onDisappear={(visible) => setIsNameVisible(!visible)}> {name} @@ -344,17 +347,6 @@ const ModuleViewActivity = () => { </Stack> <Stack direction="column" justifyContent="center" alignItems="stretch" spacing={1}> - {downloadProgress !== 0 && ( - <Box sx={{ display: "flex", alignItems: "center" }}> - <Box sx={{ width: "100%", mr: 1 }}> - <LinearProgress variant="determinate" value={downloadProgress} /> - </Box> - <Box sx={{ minWidth: 35 }}> - <Typography variant="body2" color="text.secondary">{`${Math.round(downloadProgress)}%`}</Typography> - </Box> - </Box> - )} - <DropdownButton sx={{ width: "100%", @@ -372,39 +364,7 @@ const ModuleViewActivity = () => { onClick: () => { const lasSeg = new URL(latestVersion.zipUrl).pathname.split("/").pop(); const dlPath = Environment.getPublicDir(Environment.DIRECTORY_DOWNLOADS) + "/" + lasSeg; - const dl = new Download(latestVersion.zipUrl, dlPath); - - dl.onChange = (obj) => { - switch (obj.type) { - case "downloading": - setDownloadProgress(obj.state); - break; - case "finished": - setDownloadProgress(0); - cconfirm({ - title: strings("download"), - description: strings("file_downloaded", { path: dlPath }), - }) - .then(() => {}) - .catch(() => {}); - - break; - } - }; - - dl.onError = (err) => { - setDownloadProgress(0); - os.toast("finsish: " + err, Toast.LENGTH_SHORT); - }; - - dl.start(); - - // os.open(latestVersion.zipUrl, { - // target: "_blank", - // features: { - // color: theme.palette.primary.main, - // }, - // }); + startDL(latestVersion.zipUrl, dlPath); }, }, { diff --git a/src/activitys/ModuleViewActivity/tabs/VersionsTab.tsx b/src/activitys/ModuleViewActivity/tabs/VersionsTab.tsx index bd3d51c1..90e60772 100644 --- a/src/activitys/ModuleViewActivity/tabs/VersionsTab.tsx +++ b/src/activitys/ModuleViewActivity/tabs/VersionsTab.tsx @@ -2,9 +2,11 @@ import FetchTextActivity from "@Activitys/FetchTextActivity"; import InstallTerminalActivity from "@Activitys/InstallTerminalActivity"; import InstallTerminalV2Activity from "@Activitys/InstallTerminalV2Activity"; import { useActivity } from "@Hooks/useActivity"; +import { useDownloadModule } from "@Hooks/useDownloadModule"; import { useFormatDate } from "@Hooks/useFormatDate"; import { useStrings } from "@Hooks/useStrings"; import { useTheme } from "@Hooks/useTheme"; +import { Environment } from "@Native/Environment"; import { os } from "@Native/Os"; import { Shell } from "@Native/Shell"; import DownloadIcon from "@mui/icons-material/Download"; @@ -12,6 +14,7 @@ import InstallMobileIcon from "@mui/icons-material/InstallMobile"; import ManageHistoryIcon from "@mui/icons-material/ManageHistory"; import Chip from "@mui/material/Chip"; import IconButton from "@mui/material/IconButton"; +import LinearProgress from "@mui/material/LinearProgress"; import List from "@mui/material/List"; import ListItem from "@mui/material/ListItem"; import ListItemText from "@mui/material/ListItemText"; @@ -46,6 +49,8 @@ const VersionItem = React.memo<VersionItemProps>(({ id, version, index }) => { const { strings } = useStrings(); const { theme } = useTheme(); + const [startDL, progress] = useDownloadModule(); + const { track, support } = extra; const versionName = `${version.version} (${version.versionCode})`; @@ -71,6 +76,11 @@ const VersionItem = React.memo<VersionItemProps>(({ id, version, index }) => { return ( <ListItem + sx={{ + "& .MuiListItem-root": { + position: "relative", + }, + }} secondaryAction={ <Stack direction="row" justifyContent="center" alignItems="center" spacing={0.5}> {version.changelog && ( @@ -102,12 +112,9 @@ const VersionItem = React.memo<VersionItemProps>(({ id, version, index }) => { <IconButton disabled={!version.zipUrl} onClick={() => { - os.open(version.zipUrl, { - target: "_blank", - features: { - color: theme.palette.primary.main, - }, - }); + const lasSeg = new URL(version.zipUrl).pathname.split("/").pop(); + const dlPath = Environment.getPublicDir(Environment.DIRECTORY_DOWNLOADS) + "/" + lasSeg; + startDL(version.zipUrl, dlPath); }} edge="end" aria-label="download" @@ -126,6 +133,9 @@ const VersionItem = React.memo<VersionItemProps>(({ id, version, index }) => { } secondary={ts} /> + {progress !== 0 && ( + <LinearProgress sx={{ position: "absolute", bottom: 0, left: 0, right: 0, width: "100%" }} variant="determinate" value={progress} /> + )} </ListItem> ); }); diff --git a/src/components/AvatarWithProgress.tsx b/src/components/AvatarWithProgress.tsx new file mode 100644 index 00000000..15a551cc --- /dev/null +++ b/src/components/AvatarWithProgress.tsx @@ -0,0 +1,75 @@ +import { Avatar, Box, CircularProgress, SxProps, Typography, TypographyProps } from "@mui/material"; +import React from "react"; + +interface AvatarWithProgressProps extends React.PropsWithChildren { + value: number; + src?: string; + sx?: SxProps<MMRLTheme>; + alt?: string; + progressTextVariant?: TypographyProps["variant"]; +} + +const AvatarWithProgress = (props: AvatarWithProgressProps) => { + const isActive = React.useMemo(() => props.value > 0, [props.value]); + + return ( + <Box + sx={{ + position: "relative", + display: "inline-flex", + borderRadius: "20%", + // overflow: "hidden", + // @ts-ignore + ...props.sx["& container"], + }} + > + <Avatar src={props.src} sx={props.sx} alt={props.alt} children={props.children} /> + {isActive && ( + <> + <Box + sx={(theme) => ({ + position: "absolute", + top: 0, + left: 0, + right: 0, + bottom: 0, + backgroundColor: theme.palette.background.paper, + opacity: isActive ? 0.6 : 0, + zIndex: 0, + // @ts-ignore + borderRadius: props.sx.borderRadius, + })} + /> + + <CircularProgress + sx={{ + position: "absolute", + top: 0, + left: 0, + right: 0, + bottom: 0, + margin: "auto", + zIndex: 1, + }} + variant="determinate" + value={props.value} + size={87} + thickness={1.8} + /> + <Typography + sx={{ + position: "absolute", + top: "50%", + left: "50%", + transform: "translate(-50%, -50%)", + zIndex: 2, + }} + variant={props.progressTextVariant || "caption"} + >{`${Math.round(props.value)}%`}</Typography> + </> + )} + </Box> + ); +}; + +export { AvatarWithProgress }; diff --git a/src/hooks/useDownloadModule.ts b/src/hooks/useDownloadModule.ts new file mode 100644 index 00000000..1f35e805 --- /dev/null +++ b/src/hooks/useDownloadModule.ts @@ -0,0 +1,47 @@ +import React from "react"; +import { useStrings } from "./useStrings"; +import { useConfirm } from "material-ui-confirm"; +import { os } from "@Native/Os"; +import { Download } from "@Native/Download"; + +const useDownloadModule = (): [(url?: string, dest?: string) => void, number] => { + const { strings } = useStrings(); + const konfirm = useConfirm(); + + const [progress, setProgress] = React.useState(0); + + const start = (url?: string, dest?: string) => { + if (!url || !dest) return; + + const dl = new Download(url, dest); + + dl.onChange = (obj) => { + switch (obj.type) { + case "downloading": + setProgress(obj.state); + break; + case "finished": + setProgress(0); + konfirm({ + title: strings("download"), + description: strings("file_downloaded", { path: dest }), + }) + .then(() => {}) + .catch(() => {}); + + break; + } + }; + + dl.onError = (err) => { + setProgress(0); + os.toast(err, Toast.LENGTH_SHORT); + }; + + dl.start(); + }; + + return [start, progress]; +}; + +export { useDownloadModule }; diff --git a/src/native/Download.ts b/src/native/Download.ts index c4aa4454..14de8205 100644 --- a/src/native/Download.ts +++ b/src/native/Download.ts @@ -1,4 +1,5 @@ import { Native } from "./Native"; +import { os } from "./Os"; type DownloadState = { type: "downloading"; state: number } | { type: "finished"; state: null }; @@ -43,6 +44,8 @@ class Download extends Native<DownloadNative> { onChange: this._onChange, onError: this._onError, }); + } else { + os.openURL(this._url, "_blank"); } } } diff --git a/src/native/Environment.ts b/src/native/Environment.ts index 611e61d9..0622e970 100644 --- a/src/native/Environment.ts +++ b/src/native/Environment.ts @@ -30,19 +30,31 @@ class EnvironmentClass extends Native<NativeEnvironment> { public readonly DIRECTORY_RECORDINGS: string = "Recordings"; public getExternalStorageDir(): string { - return this.interface.getExternalStorageDir(); + if (this.isAndroid) { + return this.interface.getExternalStorageDir(); + } + return ""; } public getPackageDataDir(): string { - return this.interface.getPackageDataDir(); + if (this.isAndroid) { + return this.interface.getPackageDataDir(); + } + return ""; } public getPublicDir(type: string): string { - return this.interface.getPublicDir(type); + if (this.isAndroid) { + return this.interface.getPublicDir(type); + } + return ""; } public getDataDir(): string { - return this.interface.getDataDir(); + if (this.isAndroid) { + return this.interface.getDataDir(); + } + return ""; } } diff --git a/src/native/IsolatedEval/index.ts b/src/native/IsolatedEval/index.ts index 259bd0b7..0e0f8f3b 100644 --- a/src/native/IsolatedEval/index.ts +++ b/src/native/IsolatedEval/index.ts @@ -72,6 +72,10 @@ class IsolatedEval<T = any> { Build: Build, Native: Native, React: React, + setInterval: setInterval, + clearInterval: clearInterval, + clearTimeout: clearTimeout, + setTimeout: setTimeout, eval() { throw new IsolatedFunctionBlockError("eval()"); },