master
icechen 2022-03-02 04:52:36 +08:00
parent be3da0a45d
commit b55af04082
9 changed files with 220 additions and 44 deletions

View File

@ -15,6 +15,7 @@
"@types/node": "^16.11.25", "@types/node": "^16.11.25",
"@types/react": "^17.0.39", "@types/react": "^17.0.39",
"@types/react-dom": "^17.0.11", "@types/react-dom": "^17.0.11",
"filesize": "^8.0.7",
"mtproton": "6.0.0", "mtproton": "6.0.0",
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",

View File

@ -1,7 +1,19 @@
import style from "./style.module.css"; import style from "./style.module.css";
import { useEffect, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { Close } from "@mui/icons-material"; import { Close } from "@mui/icons-material";
import { IconButton } from "@mui/material"; import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
IconButton,
} from "@mui/material";
import fileSize from "filesize";
import SendIcon from "@mui/icons-material/Send";
import { inputFile, sendFile, uploadBigFile } from "../../telegram/telegram";
import { useDispatch } from "react-redux";
import { addFileOfStorage } from "../../store/fileList";
enum Status { enum Status {
normal, normal,
@ -18,6 +30,11 @@ export function HomeButton(props: Props) {
let [status, setStatus] = useState(Status.normal); let [status, setStatus] = useState(Status.normal);
let [boxStyle, setBoxStyle] = useState([style.box]); let [boxStyle, setBoxStyle] = useState([style.box]);
let [isReceive, setIsReceive] = useState(false); let [isReceive, setIsReceive] = useState(false);
let [waitedFileList, setWaitedFileList] = useState<any[]>([]);
let [uploadRatio, setUploadRatio] = useState(0);
let [isFinish, setIsFinish] = useState(false);
const dispatch = useDispatch();
let onNormal = () => { let onNormal = () => {
setStatus(Status.normal); setStatus(Status.normal);
}; };
@ -42,6 +59,43 @@ export function HomeButton(props: Props) {
} }
}, [status]); }, [status]);
let addFileInput = useRef<HTMLInputElement>(null);
let OnChangeFileInput = (e: any) => {
setWaitedFileList(e.target.files);
};
let handleFileUpload = () => {
setUploadRatio(1);
const reader = new FileReader();
reader.onload = function (event) {
if (event.target && event.target.result) {
let bytes = event.target.result;
uploadBigFile(bytes as ArrayBuffer, setUploadRatio)
.then((file) => {
console.log("uploadFile ret:", file);
sendFile(
// @ts-ignore
inputFile(file.file_id, file.total_part, waitedFileList[0].name),
waitedFileList[0].type
).then((result) => {
console.log("sendFile ret:", result);
result.updates[1].message.media.document.file_name =
waitedFileList[0].name;
dispatch(
addFileOfStorage(result.updates[1].message.media.document)
);
setIsFinish(true);
});
})
.catch((error) => {
console.log("uploadFile error:", error);
alert(error);
});
}
};
reader.readAsArrayBuffer(waitedFileList[0]);
};
return ( return (
<div className={boxStyle.join(" ")}> <div className={boxStyle.join(" ")}>
{!isReceive ? ( {!isReceive ? (
@ -51,8 +105,15 @@ export function HomeButton(props: Props) {
className={style.addFile} className={style.addFile}
onMouseEnter={onAddFile} onMouseEnter={onAddFile}
onMouseLeave={onNormal} onMouseLeave={onNormal}
onClick={() => addFileInput.current?.click()}
> >
<input
ref={addFileInput}
type="file"
style={{ display: "none" }}
onChange={OnChangeFileInput}
/>
</div> </div>
<button <button
className={style.receive} className={style.receive}
@ -87,6 +148,44 @@ export function HomeButton(props: Props) {
</IconButton> </IconButton>
</> </>
)} )}
<Dialog open={waitedFileList.length !== 0}>
<DialogTitle></DialogTitle>
<DialogContent sx={{ minWidth: 300 }}>
?
<br />
<br />
: {waitedFileList.length > 0 ? waitedFileList[0].name : ""}
<br />
:{" "}
{waitedFileList.length > 0 ? fileSize(waitedFileList[0].size) : ""}
<br />
{uploadRatio !== 0 && <>: {uploadRatio}%</>}
<br />
{isFinish && <></>}
</DialogContent>
<DialogActions>
<Button
variant="outlined"
onClick={() => {
setWaitedFileList([]);
setUploadRatio(0);
setIsFinish(false);
}}
>
</Button>
{uploadRatio === 0 && (
<Button
variant="contained"
onClick={handleFileUpload}
endIcon={<SendIcon />}
>
</Button>
)}
</DialogActions>
</Dialog>
</div> </div>
); );
} }

View File

@ -1,3 +1,5 @@
// @ts-nocheck
import React from "react"; import React from "react";
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
import reportWebVitals from "./reportWebVitals"; import reportWebVitals from "./reportWebVitals";
@ -6,6 +8,33 @@ import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./pages/home"; import Home from "./pages/home";
import { Provider } from "react-redux"; import { Provider } from "react-redux";
import store from "./store"; import store from "./store";
import { updateOfStorage } from "./store/fileList";
store.dispatch(updateOfStorage());
Date.prototype.Format = function (fmt) {
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小时
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
S: this.getMilliseconds(), //毫秒
};
if (/(y+)/.test(fmt))
fmt = fmt.replace(
RegExp.$1,
(this.getFullYear() + "").substr(4 - RegExp.$1.length)
);
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt))
fmt = fmt.replace(
RegExp.$1,
RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length)
);
return fmt;
};
ReactDOM.render( ReactDOM.render(
<React.StrictMode> <React.StrictMode>

View File

@ -15,6 +15,9 @@ import {
TableRow, TableRow,
} from "@mui/material"; } from "@mui/material";
import MoreHorizIcon from "@mui/icons-material/MoreHoriz"; import MoreHorizIcon from "@mui/icons-material/MoreHoriz";
import { useSelectorFileList } from "../../store/fileList";
import fileSize from "filesize";
import { downloadFile } from "../../telegram/telegram";
enum ContentType { enum ContentType {
File, File,
@ -56,14 +59,34 @@ function Login() {
function File() { function File() {
let [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null); let [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
let [waitDownloadFile, setWaitDownloadFile] = useState(null);
let fileList = useSelectorFileList();
const open = Boolean(anchorEl); const open = Boolean(anchorEl);
let handleClick = (event: React.MouseEvent<HTMLButtonElement>) => { let handleClick = (index: number) => {
setAnchorEl(event.currentTarget); return (event: React.MouseEvent<HTMLButtonElement>) => {
console.log("index", index);
setWaitDownloadFile(fileList[index]);
setAnchorEl(event.currentTarget);
};
}; };
let handleClose = () => { let handleClose = () => {
setAnchorEl(null); setAnchorEl(null);
}; };
let Download = () => {
// @ts-ignore
console.log("waitDownloadFile", waitDownloadFile?.file_name);
downloadFile(waitDownloadFile)
.then((res) => {
console.log("res", res);
})
.catch((error) => {
console.log("download error:", error);
alert(error);
});
};
return ( return (
<div <div
style={{ style={{
@ -74,7 +97,7 @@ function File() {
}} }}
> >
<Paper sx={{ padding: "100px", width: "100%" }}> <Paper sx={{ padding: "100px", width: "100%" }}>
<TableContainer sx={{ backgroundColor: "#f2f2f2" }}> <TableContainer sx={{ backgroundColor: "#f2f2f2", height: 500 }}>
<Table aria-label={"文件列表"}> <Table aria-label={"文件列表"}>
<TableHead> <TableHead>
<TableRow> <TableRow>
@ -84,19 +107,33 @@ function File() {
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
<TableRow> {fileList.map((item: any, index: number) => {
<TableCell sx={{ position: "relative" }}> return (
xxx <TableRow key={item.id} sx={{ cursor: "pointer" }}>
<IconButton <TableCell sx={{ position: "relative" }}>
sx={{ position: "absolute", right: 20 }} {item.attributes[0].file_name}
onClick={handleClick} <IconButton
> sx={{
<MoreHorizIcon /> position: "absolute",
</IconButton> right: 20,
</TableCell> top: "50%",
<TableCell>2020-01-01 12:12:12</TableCell> transform: "translate(-50%,-50%)",
<TableCell>128MB</TableCell> }}
</TableRow> onClick={handleClick(index)}
>
<MoreHorizIcon />
</IconButton>
</TableCell>
<TableCell>
{
// @ts-ignore
new Date(item.date * 1000).Format("yyyy-MM-dd hh:mm:ss")
}
</TableCell>
<TableCell>{fileSize(item.size)}</TableCell>
</TableRow>
);
})}
</TableBody> </TableBody>
</Table> </Table>
</TableContainer> </TableContainer>
@ -107,7 +144,7 @@ function File() {
anchorEl={anchorEl} anchorEl={anchorEl}
onClose={handleClose} onClose={handleClose}
> >
<MenuItem onClick={handleClose}></MenuItem> <MenuItem onClick={Download}></MenuItem>
<MenuItem onClick={handleClose}></MenuItem> <MenuItem onClick={handleClose}></MenuItem>
<Divider /> <Divider />
<MenuItem onClick={handleClose}></MenuItem> <MenuItem onClick={handleClose}></MenuItem>

View File

@ -9,11 +9,19 @@ function getLocalStorage() {
}, },
setObject(key: string, value: any) { setObject(key: string, value: any) {
console.log("setObject", key, value);
return window.localStorage.setItem(key, JSON.stringify(value)); return window.localStorage.setItem(key, JSON.stringify(value));
}, },
getObject(key: string) { getObject(key: string, defaultValue?: any) {
return JSON.parse(window.localStorage.getItem(key)?.toString() || "{}"); let value = window.localStorage.getItem(key);
if (value) {
return JSON.parse(value);
}
if (defaultValue) {
return defaultValue;
}
return {};
}, },
}; };
} }

View File

@ -1,8 +1,13 @@
import { configureStore } from "@reduxjs/toolkit"; import { configureStore, getDefaultMiddleware } from "@reduxjs/toolkit";
import userReducer from "./store/user"; import userReducer from "./store/user";
import fileListReducer from "./store/fileList";
export default configureStore({ export default configureStore({
reducer: { reducer: {
user: userReducer, user: userReducer,
fileList: fileListReducer,
}, },
middleware: getDefaultMiddleware({
serializableCheck: false,
}),
}); });

View File

@ -4,18 +4,16 @@ import storage from "../storage";
const FileList = createSlice({ const FileList = createSlice({
name: "fileList", name: "fileList",
initialState: { initialState: [] as any[],
fileList: [],
},
reducers: { reducers: {
updateOfStorage: (state) => { updateOfStorage: (state) => {
state.fileList = storage().getObject("fileList"); state = storage().getObject("fileList", []);
return state;
}, },
addFileOfStorage: (state, action) => { addFileOfStorage: (state, action) => {
// @ts-ignore state.push(action.payload);
state.fileList.push(action.payload); storage().setObject("fileList", state);
storage().setObject("fileList", state.fileList);
}, },
}, },
}); });
@ -24,6 +22,6 @@ export function useSelectorFileList() {
return useSelector((state: any) => state.fileList); return useSelector((state: any) => state.fileList);
} }
export const { updateOfStorage } = FileList.actions; export const { updateOfStorage, addFileOfStorage } = FileList.actions;
export default FileList.reducer; export default FileList.reducer;

View File

@ -16,7 +16,7 @@ class TelegramHelper {
this.client = new Client({ this.client = new Client({
api_id: appID, api_id: appID,
api_hash: appHash, api_hash: appHash,
test: true, test: false,
}); });
} else { } else {
let createTransport = function (dc: any, crypto: any) { let createTransport = function (dc: any, crypto: any) {
@ -86,7 +86,8 @@ class TelegramHelper {
} }
async function uploadBigFile( async function uploadBigFile(
bytes: ArrayBuffer bytes: ArrayBuffer,
callback?: (ratio: number) => void
): Promise<{ file_id: number; total_part: number }> { ): Promise<{ file_id: number; total_part: number }> {
let file_id = rand_id(); let file_id = rand_id();
console.log("file_id", file_id); console.log("file_id", file_id);
@ -109,10 +110,8 @@ async function uploadBigFile(
file_total_parts: file_total_parts, file_total_parts: file_total_parts,
bytes: tempBytes, bytes: tempBytes,
}); });
if (finished) { if (callback) {
console.log("finished"); callback(((i + 1) / file_total_parts) * 100);
} else {
console.log("not finished");
} }
} catch (error) { } catch (error) {
return Promise.reject(error); return Promise.reject(error);
@ -157,7 +156,7 @@ function sendFile(inputFile: any, type: string) {
async function downloadFile(fileDocument: any) { async function downloadFile(fileDocument: any) {
let partSize = 1024 * 1024; let partSize = 1024 * 1024;
const file_total_parts = Math.ceil(fileDocument.document.size / partSize); const file_total_parts = Math.ceil(fileDocument.size / partSize);
let results = []; let results = [];
for (let i = 0; i < file_total_parts; i++) { for (let i = 0; i < file_total_parts; i++) {
@ -165,9 +164,9 @@ async function downloadFile(fileDocument: any) {
let result = await Telegram.call("upload.getFile", { let result = await Telegram.call("upload.getFile", {
location: { location: {
_: "inputDocumentFileLocation", _: "inputDocumentFileLocation",
id: fileDocument.document.id, id: fileDocument.id,
access_hash: fileDocument.document.access_hash, access_hash: fileDocument.access_hash,
file_reference: fileDocument.document.file_reference, file_reference: fileDocument.file_reference,
thumb_size: "", thumb_size: "",
}, },
limit: partSize, limit: partSize,
@ -181,7 +180,7 @@ async function downloadFile(fileDocument: any) {
} }
console.log("messages.getDocument:", results); console.log("messages.getDocument:", results);
let bytes = new Uint8Array(fileDocument.document.size); let bytes = new Uint8Array(fileDocument.size);
for (let i = 0; i < results.length; i++) { for (let i = 0; i < results.length; i++) {
for (let j = 0; j < results[i].bytes.length; j++) { for (let j = 0; j < results[i].bytes.length; j++) {
bytes[i * partSize + j] = results[i].bytes[j]; bytes[i * partSize + j] = results[i].bytes[j];
@ -190,12 +189,12 @@ async function downloadFile(fileDocument: any) {
let downloadBytes = bytes; let downloadBytes = bytes;
console.log("downloadBytes", downloadBytes); console.log("downloadBytes", downloadBytes);
let blob = new Blob([downloadBytes], { let blob = new Blob([downloadBytes], {
type: fileDocument.document.mime_type, type: fileDocument.mime_type,
}); });
let url = window.URL.createObjectURL(blob); let url = window.URL.createObjectURL(blob);
let a = document.createElement("a"); let a = document.createElement("a");
a.href = url; a.href = url;
a.download = fileDocument.document.attributes[0].file_name; a.download = fileDocument.file_name;
a.click(); a.click();
return Promise.resolve(true); return Promise.resolve(true);
} }

View File

@ -4440,7 +4440,7 @@ filelist@^1.0.1:
dependencies: dependencies:
minimatch "^3.0.4" minimatch "^3.0.4"
filesize@^8.0.6: filesize@^8.0.6, filesize@^8.0.7:
version "8.0.7" version "8.0.7"
resolved "https://registry.yarnpkg.com/filesize/-/filesize-8.0.7.tgz#695e70d80f4e47012c132d57a059e80c6b580bd8" resolved "https://registry.yarnpkg.com/filesize/-/filesize-8.0.7.tgz#695e70d80f4e47012c132d57a059e80c6b580bd8"
integrity sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ== integrity sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==