From 4ef13daa852814d54f4ee91041394f3afc4a99d4 Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Wed, 17 Jan 2024 19:28:02 +0800 Subject: [PATCH 01/13] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 0fab8b7..4298f2d 100644 --- a/README.md +++ b/README.md @@ -33,15 +33,13 @@ 选择接收模式后会出现一个二维码,使用手机扫描二维码会通过默认浏览器打开一个页面,同时 PC 端的页面也会变化。 -| PC 端扫描前 | 手机端 | PC 端扫描后 | -| ------------------------------------------- | ---------------------------------------------- | --------------------------------------------- | -| ![output](./docs/images/receive-qrcode.png) | ![output](./docs/images/mobile-send-index.jpg) | ![output](./docs/images/pc-receive-empty.png) | - 在手机上点击页面最下面的的`选择文件`按钮即可上传多个文件,同时 PC 端也能看到收取文件的进度。 -| 手机端上传 | PC端接收 | -| --------------------------------------------- | ----------------------------------------- | -| ![output](./docs/images/mobile-uploading.png) | ![output](./docs/images/pc-receiving.png) | +> 点击图片可查看大图。 + +| PC 端扫描前 | 手机端 | PC 端扫描后 | 手机上传 | PC端接收 | +| ------------------------------------------- | ---------------------------------------------- | --------------------------------------------- | --------------------------------------------- | ----------------------------------------- | +| ![output](./docs/images/receive-qrcode.png) | ![output](./docs/images/mobile-send-index.jpg) | ![output](./docs/images/pc-receive-empty.png) | ![output](./docs/images/mobile-uploading.png) | ![output](./docs/images/pc-receiving.png) | 所有平台的 PC 端接收到的文件默认保存路径均为`~/Downloads/alley`,你可以自行修改保存目录。 @@ -51,6 +49,8 @@ _受限于手机操作系统的限制,手机浏览器无法实现批量下载,只能逐个下载。_ +> 点击图片可查看大图。 + | PC 端待选文件 | PC 端待发文件列表 | PC 端发送二维码 | 手机端接收页 | | ------------------------------------------- | ------------------------------------- | ---------------------------------------- | ------------------------------------------------- | | ![output](./docs/images/wait-selecting.png) | ![output](./docs/images/selected.png) | ![output](./docs/images/send-qrcode.png) | ![output](./docs/images/mobile-download-list.png) | From dbd0e1e21fac3461ad17a061ff579d580f144cfd Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Wed, 17 Jan 2024 20:29:52 +0800 Subject: [PATCH 02/13] =?UTF-8?q?feat:=20=E5=AE=A2=E6=88=B7=E7=AB=AF?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=9B=9E=E5=88=B0=E4=B8=BB=E9=A1=B5=E6=B5=AE?= =?UTF-8?q?=E5=8A=A8=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 22 ++++--- src/advance/index.tsx | 6 ++ src/components/homeButton.tsx | 12 ++++ src/components/loading.tsx | 20 ++++++ src/lazy.ts | 7 +++ src/pages/receive/fileListItem.tsx | 25 ++++++++ src/pages/receive/index.tsx | 25 +------- src/pages/send/avatar.tsx | 88 ++++++++++++++++++++++++++ src/pages/send/index.tsx | 99 ++---------------------------- src/pages/send/utils.ts | 9 +++ 10 files changed, 188 insertions(+), 125 deletions(-) create mode 100644 src/advance/index.tsx create mode 100644 src/components/homeButton.tsx create mode 100644 src/components/loading.tsx create mode 100644 src/lazy.ts create mode 100644 src/pages/receive/fileListItem.tsx create mode 100644 src/pages/send/avatar.tsx create mode 100644 src/pages/send/utils.ts diff --git a/src/App.tsx b/src/App.tsx index 829cc03..7bbbb77 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,8 +1,8 @@ -import { Button, Space } from "antd"; -import "./App.scss"; import { useState } from "react"; -import Receive from "./pages/receive"; -import Send from "./pages/send"; +import { Button, Space } from "antd"; +import { suspense } from "~/advance/index"; +import { LazyHomeButton, LazyReceive, LazySend } from "~/lazy"; +import "~/App.scss"; enum Mode { Send, @@ -12,7 +12,7 @@ enum Mode { const App = () => { const [mode, setMode] = useState(null); - console.log(mode); + const backToHome = () => setMode(null); if (mode === null) return ( @@ -28,8 +28,16 @@ const App = () => { ); - else if (mode === Mode.Receive) return ; - else return ; + else + return ( + <> + {mode === Mode.Send + ? suspense() + : suspense()} + + {suspense()} + + ); }; export default App; diff --git a/src/advance/index.tsx b/src/advance/index.tsx new file mode 100644 index 0000000..070bcf8 --- /dev/null +++ b/src/advance/index.tsx @@ -0,0 +1,6 @@ +import React, { Suspense } from "react"; +import Loading from "~/components/loading"; + +export const suspense = (component: React.ReactNode) => ( + }>{component} +); diff --git a/src/components/homeButton.tsx b/src/components/homeButton.tsx new file mode 100644 index 0000000..72f66a3 --- /dev/null +++ b/src/components/homeButton.tsx @@ -0,0 +1,12 @@ +import { HomeOutlined } from "@ant-design/icons"; +import { FloatButton } from "antd"; + +interface HomeButtonProps { + onClick: () => void; +} + +const HomeButton = ({ onClick }: HomeButtonProps) => ( + } onClick={onClick} /> +); + +export default HomeButton; diff --git a/src/components/loading.tsx b/src/components/loading.tsx new file mode 100644 index 0000000..d883ac7 --- /dev/null +++ b/src/components/loading.tsx @@ -0,0 +1,20 @@ +import { Spin } from "antd"; + +const Loading = () => { + return ( +
+ +
+ ); +}; + +export default Loading; diff --git a/src/lazy.ts b/src/lazy.ts new file mode 100644 index 0000000..2a17906 --- /dev/null +++ b/src/lazy.ts @@ -0,0 +1,7 @@ +import { lazy } from "react"; + +export const LazySend = lazy(() => import("~/pages/send")); + +export const LazyReceive = lazy(() => import("~/pages/receive")); + +export const LazyHomeButton = lazy(() => import("~/components/homeButton")); diff --git a/src/pages/receive/fileListItem.tsx b/src/pages/receive/fileListItem.tsx new file mode 100644 index 0000000..84d3b68 --- /dev/null +++ b/src/pages/receive/fileListItem.tsx @@ -0,0 +1,25 @@ +import { Progress } from "antd"; + +interface FileListItemProps { + name: string; + percent: number; + speed?: number; +} + +const FileListItem = ({ name, percent, speed }: FileListItemProps) => ( +
+
+ {name} + {speed ? `(${speed.toFixed(1)} MB/s)` : ""} +
+ +
+); + +export default FileListItem; diff --git a/src/pages/receive/index.tsx b/src/pages/receive/index.tsx index f04f822..55e0cfa 100644 --- a/src/pages/receive/index.tsx +++ b/src/pages/receive/index.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { Button, Empty, Progress, Dropdown, Row, Col } from "antd"; +import { Button, Empty, Dropdown, Row, Col } from "antd"; import type { MenuProps } from "antd"; import { appWindow } from "@tauri-apps/api/window"; import { OrderedSet } from "~/utils"; @@ -11,30 +11,9 @@ import { } from "~/api"; import { open } from "@tauri-apps/api/shell"; import { open as pick } from "@tauri-apps/api/dialog"; +import FileListItem from "./fileListItem"; import "./index.scss"; -interface FileListItemProps { - name: string; - percent: number; - speed?: number; -} - -const FileListItem = ({ name, percent, speed }: FileListItemProps) => ( -
-
- {name} - {speed ? `(${speed.toFixed(1)} MB/s)` : ""} -
- -
-); - const Receive = () => { const [downloadDir, setDownloadDir] = useState(undefined); diff --git a/src/pages/send/avatar.tsx b/src/pages/send/avatar.tsx new file mode 100644 index 0000000..ef2153d --- /dev/null +++ b/src/pages/send/avatar.tsx @@ -0,0 +1,88 @@ +import { + AndroidOutlined, + AppleOutlined, + CodeOutlined, + CustomerServiceOutlined, + FileExcelOutlined, + FileGifOutlined, + FileImageOutlined, + FileJpgOutlined, + FileMarkdownOutlined, + FilePdfOutlined, + FilePptOutlined, + FileTextOutlined, + FileUnknownOutlined, + FileWordOutlined, + FileZipOutlined, + VideoCameraOutlined, + WindowsOutlined, +} from "@ant-design/icons"; + +const avatar = (ext: string) => { + switch (ext) { + case "MP4": + case "MOV": + case "AVI": + case "WEBM": + return ; + case "JPG": + case "JPEG": + return ; + case "GIF": + return ; + case "PNG": + case "WEBP": + case "AVIF": + case "SVG": + return ; + case "PDF": + return ; + case "MP3": + return ; + case "MD": + return ; + case "PPT": + return ; + case "XLS": + case "XLSX": + return ; + case "DOC": + case "DOCX": + return ; + case "ZIP": + case "RAR": + case "7Z": + case "TAR": + return ; + case "DMG": + case "IPA": + return ; + case "EXE": + case "MSI": + return ; + case "APK": + return ; + case "PY": + case "JS": + case "JSX": + case "TS": + case "TSX": + case "RS": + case "CPP": + case "CSS": + case "SCSS": + return ; + case "TXT": + case "JSON": + case "YAML": + case "TOML": + case "HTML": + case "XML": + case "YML": + return ; + default: + return ; + } +}; + +export default avatar; diff --git a/src/pages/send/index.tsx b/src/pages/send/index.tsx index 25bdea0..4057b2e 100644 --- a/src/pages/send/index.tsx +++ b/src/pages/send/index.tsx @@ -3,112 +3,21 @@ import { appWindow } from "@tauri-apps/api/window"; import { TauriEvent } from "@tauri-apps/api/event"; import { Avatar, Button, Empty, Flex, List, Space } from "antd"; import "./index.scss"; -import { - AndroidOutlined, - AppleOutlined, - CodeOutlined, - CustomerServiceOutlined, - DeleteOutlined, - FileExcelOutlined, - FileGifOutlined, - FileImageOutlined, - FileJpgOutlined, - FileMarkdownOutlined, - FilePdfOutlined, - FilePptOutlined, - FileTextOutlined, - FileUnknownOutlined, - FileWordOutlined, - FileZipOutlined, - VideoCameraOutlined, - WindowsOutlined, -} from "@ant-design/icons"; +import { DeleteOutlined } from "@ant-design/icons"; import { getFilesMetadata, getSendFilesUrlQrCode, getQrCodeState } from "~/api"; - -const avatar = (ext: string) => { - switch (ext) { - case "MP4": - case "MOV": - case "AVI": - case "WEBM": - return ; - case "JPG": - case "JPEG": - return ; - case "GIF": - return ; - case "PNG": - case "WEBP": - case "AVIF": - case "SVG": - return ; - case "PDF": - return ; - case "MP3": - return ; - case "MD": - return ; - case "PPT": - return ; - case "XLS": - case "XLSX": - return ; - case "DOC": - case "DOCX": - return ; - case "ZIP": - case "RAR": - case "7Z": - case "TAR": - return ; - case "DMG": - case "IPA": - return ; - case "EXE": - case "MSI": - return ; - case "APK": - return ; - case "PY": - case "JS": - case "JSX": - case "TS": - case "TSX": - case "RS": - case "CPP": - case "CSS": - case "SCSS": - return ; - case "TXT": - case "JSON": - case "YAML": - case "TOML": - case "HTML": - case "XML": - case "YML": - return ; - default: - return ; - } -}; +import avatar from "./avatar"; +import { deleteRepetition } from "./utils"; const Send = () => { const [files, setFiles] = useState(null); const [qrcode, setQrcode] = useState(null); - const deleteRepetition = (paths: string[]): string[] => { - return paths.filter((p) => { - const index = files?.findIndex((f) => f.path === p); - return index === undefined ? true : index === -1; - }); - }; - useEffect(() => { const unlisten = appWindow.listen( TauriEvent.WINDOW_FILE_DROP, async (e) => { - const paths = deleteRepetition(e.payload); + const paths = deleteRepetition(e.payload, files ?? []); const sendFiles = await getFilesMetadata(paths); setFiles((pre) => { diff --git a/src/pages/send/utils.ts b/src/pages/send/utils.ts new file mode 100644 index 0000000..4ec7063 --- /dev/null +++ b/src/pages/send/utils.ts @@ -0,0 +1,9 @@ +export const deleteRepetition = ( + paths: string[], + files: SendFile[], +): string[] => { + return paths.filter((p) => { + const index = files?.findIndex((f) => f.path === p); + return index === undefined ? true : index === -1; + }); +}; From d93b334b479ffe705c108290da273b6f5d3fe005 Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Wed, 17 Jan 2024 20:33:27 +0800 Subject: [PATCH 03/13] =?UTF-8?q?chore(static):=20=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E8=BF=87=E5=A4=9A=E6=97=B6=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=BB=9A=E5=8A=A8=E6=9D=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/src/components/upload/index.scss | 1 + static/src/components/upload/index.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/static/src/components/upload/index.scss b/static/src/components/upload/index.scss index 96b29f4..90228a8 100644 --- a/static/src/components/upload/index.scss +++ b/static/src/components/upload/index.scss @@ -9,6 +9,7 @@ height: 80%; border-radius: 5px; flex-grow: 14; + overflow-y: auto; .file-list-item { list-style-type: none; diff --git a/static/src/components/upload/index.tsx b/static/src/components/upload/index.tsx index 246db4c..02f8a9a 100644 --- a/static/src/components/upload/index.tsx +++ b/static/src/components/upload/index.tsx @@ -116,7 +116,7 @@ const Upload = ({ action, headers, withCredentials, method }: UploadProps) => { return (
-
+
{!fileItems?.length ? (
Date: Wed, 17 Jan 2024 20:45:02 +0800 Subject: [PATCH 04/13] =?UTF-8?q?chore:=20=E4=BF=AE=E5=A4=8D=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E6=BA=A2=E5=87=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/src/App.scss | 2 +- static/src/pages/receive/index.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/static/src/App.scss b/static/src/App.scss index c34e611..1713662 100644 --- a/static/src/App.scss +++ b/static/src/App.scss @@ -1,5 +1,5 @@ #root { - width: 100vw; + // width: 100vw; height: 100vh; margin: 0 auto; display: flex; diff --git a/static/src/pages/receive/index.tsx b/static/src/pages/receive/index.tsx index 074c194..ecd19a1 100644 --- a/static/src/pages/receive/index.tsx +++ b/static/src/pages/receive/index.tsx @@ -60,12 +60,12 @@ const Receive = () => { } extra={ - + } > - + {f.name} From 8b5ab7a0d920b2ffea7d8407bcde0c57cb4d5f45 Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Wed, 17 Jan 2024 20:51:05 +0800 Subject: [PATCH 05/13] =?UTF-8?q?chore:=20=E6=B7=BB=E5=8A=A0=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E5=90=8E=E7=BC=80=E5=90=8D=E7=9A=84=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/src/components/upload/fileItem.tsx | 4 +--- static/src/pages/receive/fileType.ts | 6 +++++- static/src/pages/receive/index.tsx | 4 +--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/static/src/components/upload/fileItem.tsx b/static/src/components/upload/fileItem.tsx index 0433178..9df20bc 100644 --- a/static/src/components/upload/fileItem.tsx +++ b/static/src/components/upload/fileItem.tsx @@ -44,9 +44,7 @@ const FileItem = ({ file, speed, percent }: FileItemProps) => {

{file.name}

大小:{formatFileSize(file.size)} - - 类型:{fileType(extension)} - {extension} - + 类型:{fileType(extension)} diff --git a/static/src/pages/receive/fileType.ts b/static/src/pages/receive/fileType.ts index 0a7fd22..5a0cfb3 100644 --- a/static/src/pages/receive/fileType.ts +++ b/static/src/pages/receive/fileType.ts @@ -5,7 +5,7 @@ interface FileType { const FILE_TYPES: FileType[] = [ { - extensions: ["JPG", "JPEG", "PNG", "GIF", "WEBP", "BMP"], + extensions: ["JPG", "JPEG", "PNG", "GIF", "WEBP", "BMP", "SVG", "ICNS"], name: "图片", }, { @@ -60,6 +60,10 @@ const FILE_TYPES: FileType[] = [ ], name: "代码文件", }, + { + extensions: ["APK", "EXE", "MSI", "DMG", "IPA", "DEB", "RPM", "APPIMAGE"], + name: "应用程序", + }, ]; const fileType = (extension: string) => { diff --git a/static/src/pages/receive/index.tsx b/static/src/pages/receive/index.tsx index ecd19a1..813da14 100644 --- a/static/src/pages/receive/index.tsx +++ b/static/src/pages/receive/index.tsx @@ -54,9 +54,7 @@ const Receive = () => { description={ 大小:{f.size} - - 类型:{fileType(f.extension) + ` - ${f.extension}`} - + 类型:{fileType(f.extension)} } extra={ From 808b966832225a1368a5df9c712efba872c397c4 Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Wed, 17 Jan 2024 22:42:04 +0800 Subject: [PATCH 06/13] =?UTF-8?q?refactor(pages/receive):=20=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E6=8E=A5=E6=94=B6=E9=A1=B5=EF=BC=8C=E6=94=B9=E8=BF=9B?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=88=97=E8=A1=A8=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/src/server/mod.rs | 11 ++- src/App.scss | 19 ---- src/lazy.ts | 6 +- src/pages/receive/fileListItem.tsx | 20 ++-- src/pages/receive/header.tsx | 80 ++++++++++++++++ src/pages/receive/index.scss | 39 ++++++++ src/pages/receive/index.tsx | 141 ++++++++--------------------- src/pages/receive/qrcode.tsx | 26 ++++++ src/styles.scss | 7 +- types/index.d.ts | 1 + 10 files changed, 214 insertions(+), 136 deletions(-) create mode 100644 src/pages/receive/header.tsx create mode 100644 src/pages/receive/qrcode.tsx diff --git a/src-tauri/src/server/mod.rs b/src-tauri/src/server/mod.rs index 0511d94..524cf22 100644 --- a/src-tauri/src/server/mod.rs +++ b/src-tauri/src/server/mod.rs @@ -86,14 +86,16 @@ struct Task<'a> { name: &'a str, percent: f64, speed: f64, // MB/s + size: &'a str, } impl<'a> Task<'a> { - fn new(name: &'a str, percent: f64, speed: f64) -> Self { + fn new(name: &'a str, size: &'a str, percent: f64, speed: f64) -> Self { Self { name, percent, speed, + size, } } } @@ -287,6 +289,8 @@ async fn upload(req: &mut Request) -> Result<()> { let start = Instant::now(); + let formatted_size = format_file_size(size); + let body = req.take_body(); let stream = ReadProgressStream::new( body, @@ -304,7 +308,10 @@ async fn upload(req: &mut Request) -> Result<()> { let speed = progress / cost_senconds; if let Some(w) = MAIN_WINDOW.get() { - let _ = w.emit(UPLOAD_EVENT, Task::new(&name, percent, speed)); + let _ = w.emit( + UPLOAD_EVENT, + Task::new(&name, &formatted_size, percent, speed), + ); } } }), diff --git a/src/App.scss b/src/App.scss index bfcf7f4..45ba026 100644 --- a/src/App.scss +++ b/src/App.scss @@ -15,22 +15,3 @@ justify-content: center; align-items: center; } - -.header { - .directory-button-label { - display: flex; - justify-content: center; - align-items: center; - } - - .directory-button { - max-width: 100%; - padding-left: 0; - - span { - max-width: 100%; - overflow-wrap: break-word; - white-space: normal; - } - } -} diff --git a/src/lazy.ts b/src/lazy.ts index 2a17906..5f39737 100644 --- a/src/lazy.ts +++ b/src/lazy.ts @@ -1,7 +1,9 @@ import { lazy } from "react"; +export const LazyHomeButton = lazy(() => import("~/components/homeButton")); + export const LazySend = lazy(() => import("~/pages/send")); export const LazyReceive = lazy(() => import("~/pages/receive")); - -export const LazyHomeButton = lazy(() => import("~/components/homeButton")); +export const LazyReceiveHeader = lazy(() => import("~/pages/receive/header")); +export const LazyReceiveQrCode = lazy(() => import("~/pages/receive/qrcode")); diff --git a/src/pages/receive/fileListItem.tsx b/src/pages/receive/fileListItem.tsx index 84d3b68..67514a9 100644 --- a/src/pages/receive/fileListItem.tsx +++ b/src/pages/receive/fileListItem.tsx @@ -1,13 +1,14 @@ -import { Progress } from "antd"; +import { Col, Progress, Row } from "antd"; interface FileListItemProps { name: string; percent: number; speed?: number; + size: string; } -const FileListItem = ({ name, percent, speed }: FileListItemProps) => ( -
+const FileListItem = ({ name, percent, speed, size }: FileListItemProps) => ( +
  • ( color: percent < 100 ? "#959595" : "var(--ant-color-text-base)", }} > - {name} - {speed ? `(${speed.toFixed(1)} MB/s)` : ""} + + +

    {name}

    + + + {speed ? {`${speed.toFixed(1)} MB/s`} : null} + + {size} +
    -
  • + ); export default FileListItem; diff --git a/src/pages/receive/header.tsx b/src/pages/receive/header.tsx new file mode 100644 index 0000000..710558a --- /dev/null +++ b/src/pages/receive/header.tsx @@ -0,0 +1,80 @@ +import { useState, useEffect } from "react"; +import { Row, Col, Dropdown, Button } from "antd"; +import type { MenuProps } from "antd"; +import { open as pick } from "@tauri-apps/api/dialog"; +import { open } from "@tauri-apps/api/shell"; +import { changeDownloadsDir, getDownloadsDir } from "~/api"; +import Loading from "~/components/loading"; + +const Header = () => { + const [downloadDir, setDownloadDir] = useState(undefined); + const [openDropDown, setOpenDropDown] = useState(false); + + useEffect(() => { + if (downloadDir) return; + + getDownloadsDir().then((d) => setDownloadDir(d)); + }, []); + + const pickDirectory = async () => { + const dir = (await pick({ + directory: true, + defaultPath: downloadDir, + multiple: false, + })) as string | null; + + if (!dir) return; + + await changeDownloadsDir(dir); + + setDownloadDir(dir); + }; + + const DirectoryDropdownItems: MenuProps["items"] = [ + { + key: "1", + label: 打开, + onClick: () => open(downloadDir!), + }, + { + key: "2", + label: 修改, + onClick: () => pickDirectory(), + }, + ]; + + if (!downloadDir) return ; + + return ( + + + 保存目录: + + + + setOpenDropDown((pre) => !pre)} + menu={{ items: DirectoryDropdownItems }} + placement="bottomRight" + arrow + overlayStyle={{ minWidth: 0 }} + > + + + + + ); +}; + +export default Header; diff --git a/src/pages/receive/index.scss b/src/pages/receive/index.scss index a70c219..4ac14ee 100644 --- a/src/pages/receive/index.scss +++ b/src/pages/receive/index.scss @@ -1,3 +1,42 @@ +.header { + width: 100vw; + + .directory-button-label { + display: flex; + justify-content: right; + align-items: center; + } + + .directory-button { + max-width: 100%; + padding-left: 0; + + span { + max-width: 100%; + overflow-wrap: break-word; + white-space: normal; + } + } +} + +.receive-file-list { + flex-grow: 14; + overflow-y: auto; + max-width: 100vw; + margin: 10px; + padding: 10px; + border: 1px #666 dashed; + border-radius: 20px; + + &-item { + max-width: 100vw; + + .ant-progress-line { + margin-inline-end: 0; + } + } +} + .send-button { white-space: normal; word-wrap: normal; diff --git a/src/pages/receive/index.tsx b/src/pages/receive/index.tsx index 55e0cfa..4c30302 100644 --- a/src/pages/receive/index.tsx +++ b/src/pages/receive/index.tsx @@ -1,22 +1,14 @@ import { useEffect, useState } from "react"; -import { Button, Empty, Dropdown, Row, Col } from "antd"; -import type { MenuProps } from "antd"; +import { Empty, Flex } from "antd"; import { appWindow } from "@tauri-apps/api/window"; import { OrderedSet } from "~/utils"; -import { - changeDownloadsDir, - getDownloadsDir, - getUploadQrCode, - getQrCodeState, -} from "~/api"; -import { open } from "@tauri-apps/api/shell"; -import { open as pick } from "@tauri-apps/api/dialog"; +import { getUploadQrCode, getQrCodeState } from "~/api"; import FileListItem from "./fileListItem"; import "./index.scss"; +import { suspense } from "~/advance"; +import { LazyReceiveHeader, LazyReceiveQrCode } from "~/lazy"; const Receive = () => { - const [downloadDir, setDownloadDir] = useState(undefined); - const [qrcode, setQrcode] = useState(null); const [progressList, setProgressList] = useState>( @@ -24,21 +16,13 @@ const Receive = () => { ); const [fileList, setFileList] = useState[]>([]); - const [openDropDown, setOpenDropDown] = useState(false); - - useEffect(() => { - if (downloadDir) return; - - getDownloadsDir().then((d) => setDownloadDir(d)); - }, []); - useEffect(() => { const unlisten = appWindow.listen("upload://progress", (e) => { if (qrcode) setQrcode(null); setProgressList((pre) => pre.push(e.payload)); - const { name, percent } = e.payload; + const { name, percent, size } = e.payload; if (percent === 100) { setProgressList((pre) => pre.remove(e.payload)); @@ -46,7 +30,7 @@ const Receive = () => { setFileList((pre) => { const t = pre.find((v) => v.name === name); - return t ? pre : [...pre, { name, percent }]; + return t ? pre : [...pre, { name, percent, size }]; }); } }); @@ -77,74 +61,36 @@ const Receive = () => { return () => clearTimeout(timer); }, [qrcode]); - const pickDirectory = async () => { - const dir = (await pick({ - directory: true, - defaultPath: downloadDir, - multiple: false, - })) as string | null; - - if (!dir) return; - - await changeDownloadsDir(dir); - - setDownloadDir(dir); - }; - - const DirectoryDropdownItems: MenuProps["items"] = [ - { - key: "1", - label: 打开, - onClick: () => open(downloadDir!), - }, - { - key: "2", - label: 修改, - onClick: () => pickDirectory(), - }, - ]; + if (qrcode) + return ( +
    + {suspense()} +
    + ); + else if (progressList.empty() && !fileList.length) { + return ( + + {suspense()} + + + + + ); + } return ( - <> - {downloadDir && !qrcode ? ( - - - 保存目录: - - - - setOpenDropDown((pre) => !pre)} - menu={{ items: DirectoryDropdownItems }} - placement="bottomRight" - arrow - overlayStyle={{ minWidth: 0 }} - > - - - - - ) : null} + +
    {suspense()}
    -
    - {progressList.empty() && !qrcode && !fileList.length ? ( - - ) : ( - fileList.map((t) => ( - - )) - )} +
      + {fileList.map((t) => ( + + ))} {progressList.map((progress) => ( { name={progress.name} percent={Math.round(progress.percent)} speed={progress.speed} + size={progress.size} /> ))} - - {qrcode ? ( - <> -

      扫码连接

      -
      - -
      或在另一台电脑中通过浏览器中访问
      - - - ) : null} -
      - +
    + ); }; diff --git a/src/pages/receive/qrcode.tsx b/src/pages/receive/qrcode.tsx new file mode 100644 index 0000000..c475094 --- /dev/null +++ b/src/pages/receive/qrcode.tsx @@ -0,0 +1,26 @@ +import { Button } from "antd"; +import { open } from "@tauri-apps/api/shell"; + +interface QRCodeProps { + qrcode: QrCode; +} + +const QRCode = ({ qrcode }: QRCodeProps) => { + return ( + <> +

    扫码连接

    +
    + +
    或在另一台电脑中通过浏览器中访问
    + + + ); +}; + +export default QRCode; diff --git a/src/styles.scss b/src/styles.scss index 6ccacab..e6eac7e 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -6,10 +6,13 @@ -webkit-text-size-adjust: 100%; } -html, -body { +* { margin: 0; padding: 0; +} + +html, +body { height: 100%; width: 100%; } diff --git a/types/index.d.ts b/types/index.d.ts index 0dec9fe..6296cb1 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -2,6 +2,7 @@ interface TaskMessage { name: string; percent: number; speed: number; + size: string; } interface QrCode { From 086d0fe5aed8d26cdd497e66df43b570d99cf7c5 Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Wed, 17 Jan 2024 22:55:42 +0800 Subject: [PATCH 07/13] =?UTF-8?q?chore(pages):=20=E6=94=B9=E8=BF=9B?= =?UTF-8?q?=E6=BB=9A=E5=8A=A8=E6=9D=A1=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/send/avatar.tsx | 1 + src/styles.scss | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/pages/send/avatar.tsx b/src/pages/send/avatar.tsx index ef2153d..8c0fb8e 100644 --- a/src/pages/send/avatar.tsx +++ b/src/pages/send/avatar.tsx @@ -31,6 +31,7 @@ const avatar = (ext: string) => { case "GIF": return ; case "PNG": + case "APNG": case "WEBP": case "AVIF": case "SVG": diff --git a/src/styles.scss b/src/styles.scss index e6eac7e..4fd456b 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -17,6 +17,24 @@ body { width: 100%; } +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-thumb { + border-radius: 10px; + background: rgba(0, 0, 0, 0.1); +} + +::-webkit-scrollbar-thumb:hover { + background: rgba(0, 0, 0, 0.3); +} + +::-webkit-scrollbar-track { + background-color: #fff0; +} + @media (prefers-color-scheme: dark) { :root { color: #f6f6f6; From ab55bd2b989b84d477f94c14fe08c9e4fa4c7248 Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Wed, 17 Jan 2024 23:02:28 +0800 Subject: [PATCH 08/13] =?UTF-8?q?chore(pages/send):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E4=BB=A3=E7=A0=81=E6=96=87=E4=BB=B6=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/send/avatar.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/pages/send/avatar.tsx b/src/pages/send/avatar.tsx index 8c0fb8e..0fd8c56 100644 --- a/src/pages/send/avatar.tsx +++ b/src/pages/send/avatar.tsx @@ -70,8 +70,15 @@ const avatar = (ext: string) => { case "TSX": case "RS": case "CPP": + case "C": + case "JAVA": + case "LUA": case "CSS": + case "GO": case "SCSS": + case "PHP": + case "SQL": + case "CS": return ; case "TXT": case "JSON": From 6656bb22f3c121071aa7762e4920e9a5fafa4fcf Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Thu, 18 Jan 2024 13:31:30 +0800 Subject: [PATCH 09/13] =?UTF-8?q?chore(pages/receive):=20=E7=BC=A9?= =?UTF-8?q?=E5=B0=8F=20Header=20=E5=92=8C=20List=20=E7=9A=84=E8=B7=9D?= =?UTF-8?q?=E7=A6=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/receive/index.scss | 2 +- src/pages/receive/index.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/receive/index.scss b/src/pages/receive/index.scss index 4ac14ee..bcc3282 100644 --- a/src/pages/receive/index.scss +++ b/src/pages/receive/index.scss @@ -26,7 +26,7 @@ margin: 10px; padding: 10px; border: 1px #666 dashed; - border-radius: 20px; + border-radius: 10px; &-item { max-width: 100vw; diff --git a/src/pages/receive/index.tsx b/src/pages/receive/index.tsx index 4c30302..6abf238 100644 --- a/src/pages/receive/index.tsx +++ b/src/pages/receive/index.tsx @@ -80,7 +80,7 @@ const Receive = () => { return ( -
    {suspense()}
    + {suspense()}
      {fileList.map((t) => ( From 1a4701986c5422681112bb682c789a77d89d4c2f Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Thu, 18 Jan 2024 13:32:22 +0800 Subject: [PATCH 10/13] =?UTF-8?q?chore(static/upload):=20=E7=AD=89?= =?UTF-8?q?=E5=BE=85=E4=BB=BB=E5=8A=A1=E6=B7=BB=E5=8A=A0=E7=AD=89=E5=BE=85?= =?UTF-8?q?=E5=8A=A8=E6=80=81=E5=9B=BE=E6=A0=87=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/src/components/upload/fileItem.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/static/src/components/upload/fileItem.tsx b/static/src/components/upload/fileItem.tsx index 9df20bc..9c1b991 100644 --- a/static/src/components/upload/fileItem.tsx +++ b/static/src/components/upload/fileItem.tsx @@ -1,4 +1,4 @@ -import { Grid, Space } from "antd-mobile"; +import { Grid, Space, DotLoading } from "antd-mobile"; import fileType from "~/pages/receive/fileType"; import formatFileSize from "./fileSize"; @@ -48,11 +48,9 @@ const FileItem = ({ file, speed, percent }: FileItemProps) => { - {percent ? ( - - {Math.round(percent)}% - - ) : null} + + {percent ? Math.round(percent) + "%" : } + {uploading && speed ? ( From 996e4554d638bda5a7dbcff889dd823ba7abc8e0 Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Thu, 18 Jan 2024 13:45:13 +0800 Subject: [PATCH 11/13] =?UTF-8?q?chore(pages/receive):=20=E6=94=B9?= =?UTF-8?q?=E8=BF=9B=E6=96=87=E4=BB=B6=E5=88=97=E8=A1=A8=E9=A1=B9=E9=80=9F?= =?UTF-8?q?=E5=BA=A6=E5=92=8C=E5=A4=A7=E5=B0=8F=E7=9A=84=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/receive/fileListItem.tsx | 8 ++++++-- src/pages/receive/index.scss | 10 ++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/pages/receive/fileListItem.tsx b/src/pages/receive/fileListItem.tsx index 67514a9..07023d9 100644 --- a/src/pages/receive/fileListItem.tsx +++ b/src/pages/receive/fileListItem.tsx @@ -21,9 +21,13 @@ const FileListItem = ({ name, percent, speed, size }: FileListItemProps) => (

      {name}

      - {speed ? {`${speed.toFixed(1)} MB/s`} : null} + {speed ? ( + {`${speed.toFixed(1)} MB/s`} + ) : null} - {size} + + {size} +
    diff --git a/src/pages/receive/index.scss b/src/pages/receive/index.scss index bcc3282..6e1de69 100644 --- a/src/pages/receive/index.scss +++ b/src/pages/receive/index.scss @@ -31,6 +31,16 @@ &-item { max-width: 100vw; + .filename { + white-space: normal; + word-break: break-all; + } + + .speed, + .filesize { + text-align: right; + } + .ant-progress-line { margin-inline-end: 0; } From 10a6afa8907dedb7be82c63439fe782293886719 Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Thu, 18 Jan 2024 14:25:09 +0800 Subject: [PATCH 12/13] =?UTF-8?q?feat:=20=E6=89=80=E6=9C=89=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=88=97=E8=A1=A8=E7=BB=84=E4=BB=B6=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=B8=85=E7=A9=BA=E6=8C=89=E9=92=AE=E6=88=96=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 16 ++--- src/components/floatButtons.tsx | 29 +++++++++ src/components/homeButton.tsx | 12 ---- src/lazy.ts | 3 +- src/pages/receive/index.tsx | 84 ++++++++++++++++---------- src/pages/send/index.tsx | 52 ++++++++-------- src/pages/send/list.tsx | 36 +++++++++++ static/src/components/upload/index.tsx | 2 + 8 files changed, 151 insertions(+), 83 deletions(-) create mode 100644 src/components/floatButtons.tsx delete mode 100644 src/components/homeButton.tsx create mode 100644 src/pages/send/list.tsx diff --git a/src/App.tsx b/src/App.tsx index 7bbbb77..51348c5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,7 +1,7 @@ import { useState } from "react"; import { Button, Space } from "antd"; import { suspense } from "~/advance/index"; -import { LazyHomeButton, LazyReceive, LazySend } from "~/lazy"; +import { LazyReceive, LazySend } from "~/lazy"; import "~/App.scss"; enum Mode { @@ -12,7 +12,7 @@ enum Mode { const App = () => { const [mode, setMode] = useState(null); - const backToHome = () => setMode(null); + const toHome = () => setMode(null); if (mode === null) return ( @@ -29,15 +29,9 @@ const App = () => {
    ); else - return ( - <> - {mode === Mode.Send - ? suspense() - : suspense()} - - {suspense()} - - ); + return mode === Mode.Send + ? suspense() + : suspense(); }; export default App; diff --git a/src/components/floatButtons.tsx b/src/components/floatButtons.tsx new file mode 100644 index 0000000..bf5f21b --- /dev/null +++ b/src/components/floatButtons.tsx @@ -0,0 +1,29 @@ +import { HomeOutlined, ClearOutlined } from "@ant-design/icons"; +import { FloatButton } from "antd"; + +interface HomeButtonProps { + onClick: () => void; + clear?: () => void; +} + +const HomeButton = ({ onClick, clear }: HomeButtonProps) => { + const homeBtn = ( + } onClick={onClick} /> + ); + + if (!clear) return homeBtn; + + return ( + + } + tooltip="清空文件列表" + onClick={clear} + /> + + {homeBtn} + + ); +}; + +export default HomeButton; diff --git a/src/components/homeButton.tsx b/src/components/homeButton.tsx deleted file mode 100644 index 72f66a3..0000000 --- a/src/components/homeButton.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { HomeOutlined } from "@ant-design/icons"; -import { FloatButton } from "antd"; - -interface HomeButtonProps { - onClick: () => void; -} - -const HomeButton = ({ onClick }: HomeButtonProps) => ( - } onClick={onClick} /> -); - -export default HomeButton; diff --git a/src/lazy.ts b/src/lazy.ts index 5f39737..70539f2 100644 --- a/src/lazy.ts +++ b/src/lazy.ts @@ -1,8 +1,9 @@ import { lazy } from "react"; -export const LazyHomeButton = lazy(() => import("~/components/homeButton")); +export const LazyFloatButtons = lazy(() => import("~/components/floatButtons")); export const LazySend = lazy(() => import("~/pages/send")); +export const LazySendFileList = lazy(() => import("~/pages/send/list")); export const LazyReceive = lazy(() => import("~/pages/receive")); export const LazyReceiveHeader = lazy(() => import("~/pages/receive/header")); diff --git a/src/pages/receive/index.tsx b/src/pages/receive/index.tsx index 6abf238..7d28d0a 100644 --- a/src/pages/receive/index.tsx +++ b/src/pages/receive/index.tsx @@ -6,9 +6,13 @@ import { getUploadQrCode, getQrCodeState } from "~/api"; import FileListItem from "./fileListItem"; import "./index.scss"; import { suspense } from "~/advance"; -import { LazyReceiveHeader, LazyReceiveQrCode } from "~/lazy"; +import { LazyReceiveHeader, LazyReceiveQrCode, LazyFloatButtons } from "~/lazy"; -const Receive = () => { +interface ReceiveProps { + toHome: () => void; +} + +const Receive = ({ toHome }: ReceiveProps) => { const [qrcode, setQrcode] = useState(null); const [progressList, setProgressList] = useState>( @@ -65,44 +69,62 @@ const Receive = () => { return (
    {suspense()} + + {suspense()}
    ); else if (progressList.empty() && !fileList.length) { return ( - - {suspense()} - - + <> + + {suspense()} + + + - + + {suspense()} + ); } return ( - - {suspense()} - -
      - {fileList.map((t) => ( - - ))} - - {progressList.map((progress) => ( - - ))} -
    -
    + <> + + {suspense()} + +
      + {fileList.map((t) => ( + + ))} + + {progressList.map((progress) => ( + + ))} +
    +
    + + {suspense( + { + setProgressList(new OrderedSet("name")); + setFileList([]); + }} + />, + )} + ); }; diff --git a/src/pages/send/index.tsx b/src/pages/send/index.tsx index 4057b2e..0b171b4 100644 --- a/src/pages/send/index.tsx +++ b/src/pages/send/index.tsx @@ -1,14 +1,18 @@ import { useState, useEffect } from "react"; import { appWindow } from "@tauri-apps/api/window"; import { TauriEvent } from "@tauri-apps/api/event"; -import { Avatar, Button, Empty, Flex, List, Space } from "antd"; +import { Button, Empty, Flex } from "antd"; +import { suspense } from "~/advance"; +import { LazyFloatButtons, LazySendFileList } from "~/lazy"; import "./index.scss"; -import { DeleteOutlined } from "@ant-design/icons"; import { getFilesMetadata, getSendFilesUrlQrCode, getQrCodeState } from "~/api"; -import avatar from "./avatar"; import { deleteRepetition } from "./utils"; -const Send = () => { +interface SendProps { + toHome: () => void; +} + +const Send = ({ toHome }: SendProps) => { const [files, setFiles] = useState(null); const [qrcode, setQrcode] = useState(null); @@ -62,6 +66,8 @@ const Send = () => {

    扫码连接

    + + {suspense()}
    ); } @@ -77,30 +83,7 @@ const Send = () => { vertical > {files && files.length ? ( - ( - removeFile(item.path)} - > - {}{" "} - , - ]} - > - } - title={item.name} - description={大小:{item.size}} - /> - - )} - /> + suspense() ) : ( )} @@ -114,6 +97,19 @@ const Send = () => { 确认 + + {suspense( + { + setFiles(null); + } + : undefined + } + />, + )} ); }; diff --git a/src/pages/send/list.tsx b/src/pages/send/list.tsx new file mode 100644 index 0000000..412dc10 --- /dev/null +++ b/src/pages/send/list.tsx @@ -0,0 +1,36 @@ +import { List, Avatar, Space } from "antd"; +import { DeleteOutlined } from "@ant-design/icons"; +import avatar from "./avatar"; + +interface SendFileListProps { + data: SendFile[]; + removeFile: (path: string) => void; +} + +const SendFileList = ({ data, removeFile }: SendFileListProps) => { + return ( + ( + removeFile(item.path)}> + {}{" "} + , + ]} + > + } + title={item.name} + description={大小:{item.size}} + /> + + )} + /> + ); +}; + +export default SendFileList; diff --git a/static/src/components/upload/index.tsx b/static/src/components/upload/index.tsx index 02f8a9a..aa13d8c 100644 --- a/static/src/components/upload/index.tsx +++ b/static/src/components/upload/index.tsx @@ -56,6 +56,8 @@ const Upload = ({ action, headers, withCredentials, method }: UploadProps) => { const target = e.target as HTMLElement; if (target && target.tagName === "BUTTON") { + setFileItems([]); + setRequestTasks([]); fileInput.current?.click(); target.blur(); } From 1c5a1e0c327d9416bb4c6a981dac23ba88d480d3 Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Thu, 18 Jan 2024 14:26:46 +0800 Subject: [PATCH 13/13] =?UTF-8?q?chore:=20=E4=BF=AE=E6=94=B9=20releaseName?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 994b536..e488e77 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -50,7 +50,7 @@ jobs: TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} with: tagName: v__VERSION__ - releaseName: "Alley v__VERSION__" + releaseName: "v__VERSION__" releaseBody: "See the assets to download this version and install." releaseDraft: true prerelease: false