Loading .vscode/settings.json +1 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ "DESERIALIZERS", "ebml", "Embedder", "fflate", "fluentui", "genymobile", "Genymobile's", Loading apps/demo/package.json +1 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ "@yume-chan/stream-extra": "workspace:^0.0.18", "@yume-chan/stream-saver": "^2.0.6", "@yume-chan/struct": "workspace:^0.0.18", "fflate": "^0.7.4", "mobx": "^6.7.0", "mobx-react-lite": "^3.4.3", "next": "13.2.4", Loading apps/demo/src/pages/file-manager.tsx +179 −53 Original line number Diff line number Diff line Loading @@ -29,8 +29,15 @@ import { } from "@fluentui/react-file-type-icons"; import { useConst } from "@fluentui/react-hooks"; import { getIcon } from "@fluentui/style-utilities"; import { AdbFeature, LinuxFileType, type AdbSyncEntry } from "@yume-chan/adb"; import { WrapConsumableStream } from "@yume-chan/stream-extra"; import { AdbFeature, AdbSync, LinuxFileType, type AdbSyncEntry, } from "@yume-chan/adb"; import { WrapConsumableStream, WritableStream } from "@yume-chan/stream-extra"; import { EMPTY_UINT8_ARRAY } from "@yume-chan/struct"; import { Zip, ZipPassThrough } from "fflate"; import { action, autorun, Loading Loading @@ -174,9 +181,9 @@ class FileManagerState { }, }); break; case 1: if (this.selectedItems[0].type === LinuxFileType.File) { result.push({ default: result.push( { key: "download", text: "Download", iconProps: { Loading @@ -188,40 +195,20 @@ class FileManagerState { }, }, onClick: () => { (async () => { const sync = await GLOBAL_STATE.device!.sync(); try { const item = this.selectedItems[0]; const itemPath = path.resolve( this.path, item.name ); await sync .read(itemPath) .pipeTo( saveFile( item.name, Number(item.size) ) ); } catch (e: any) { GLOBAL_STATE.showErrorDialog(e); } finally { sync.dispose(); } })(); void this.download(); return false; }, }); } // fall through default: result.push({ }, { key: "delete", text: "Delete", iconProps: { iconName: Icons.Delete, style: { height: 20, fontSize: 20, lineHeight: 1.5 }, style: { height: 20, fontSize: 20, lineHeight: 1.5, }, }, onClick: () => { (async () => { Loading @@ -229,10 +216,15 @@ class FileManagerState { for (const item of this.selectedItems) { const output = await GLOBAL_STATE.device!.rm( path.resolve(this.path, item.name!) path.resolve( this.path, item.name! ) ); if (output) { GLOBAL_STATE.showErrorDialog(output); GLOBAL_STATE.showErrorDialog( output ); return; } } Loading @@ -244,7 +236,8 @@ class FileManagerState { })(); return false; }, }); } ); break; } Loading Loading @@ -459,6 +452,139 @@ class FileManagerState { }); } private getFileStream(sync: AdbSync, basePath: string, name: string) { return sync.read(path.resolve(basePath, name)); } private async addDirectory( sync: AdbSync, zip: Zip, basePath: string, relativePath: string ) { if (relativePath !== ".") { // Add empty directory const file = new ZipPassThrough(relativePath + "/"); zip.add(file); file.push(EMPTY_UINT8_ARRAY, true); } for (const entry of await sync.readdir( path.resolve(basePath, relativePath) )) { if (entry.name === "." || entry.name === "..") { continue; } switch (entry.type) { case LinuxFileType.Directory: await this.addDirectory( sync, zip, basePath, path.resolve(relativePath, entry.name) ); break; case LinuxFileType.File: await this.addFile( sync, zip, basePath, path.resolve(relativePath, entry.name) ); break; } } } private async addFile( sync: AdbSync, zip: Zip, basePath: string, name: string ) { const file = new ZipPassThrough(name); zip.add(file); await this.getFileStream(sync, basePath, name).pipeTo( new WritableStream({ write(chunk) { file.push(chunk); }, close() { file.push(EMPTY_UINT8_ARRAY, true); }, }) ); } private async download() { const sync = await GLOBAL_STATE.device!.sync(); try { if (this.selectedItems.length === 1) { const item = this.selectedItems[0]; switch (item.type) { case LinuxFileType.Directory: { const stream = saveFile( `${this.selectedItems[0].name}.zip` ); const writer = stream.getWriter(); const zip = new Zip((err, data, final) => { writer.write(data); if (final) { writer.close(); } }); await this.addDirectory( sync, zip, path.resolve(this.path, item.name), "." ); zip.end(); break; } case LinuxFileType.File: await this.getFileStream( sync, this.path, item.name ).pipeTo(saveFile(item.name, Number(item.size))); break; } return; } const stream = saveFile(`${path.basename(this.path)}.zip`); const writer = stream.getWriter(); const zip = new Zip((err, data, final) => { writer.write(data); if (final) { writer.close(); } }); for (const item of this.selectedItems) { switch (item.type) { case LinuxFileType.Directory: await this.addDirectory( sync, zip, this.path, item.name ); break; case LinuxFileType.File: await this.addFile(sync, zip, this.path, item.name); break; } } zip.end(); } catch (e: any) { GLOBAL_STATE.showErrorDialog(e); } finally { sync.dispose(); } } pushPathQuery = (path: string) => { Router.push({ query: { ...Router.query, path } }); }; Loading common/config/rush/pnpm-lock.yaml +6 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ importers: '@yume-chan/struct': workspace:^0.0.18 eslint: ^8.36.0 eslint-config-next: 13.2.4 fflate: ^0.7.4 mobx: ^6.7.0 mobx-react-lite: ^3.4.3 next: 13.2.4 Loading Loading @@ -73,6 +74,7 @@ importers: '@yume-chan/stream-extra': link:../../libraries/stream-extra '@yume-chan/stream-saver': 2.0.6 '@yume-chan/struct': link:../../libraries/struct fflate: 0.7.4 mobx: 6.8.0 mobx-react-lite: 3.4.3_woojb62cqeyk443mbl7msrwu2e next: 13.2.4_biqbaboplfbrettd7655fr4n2y Loading Loading @@ -4325,6 +4327,10 @@ packages: pend: 1.2.0 dev: true /fflate/0.7.4: resolution: {integrity: sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==} dev: false /file-entry-cache/6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} Loading common/config/rush/repo-state.json +1 −1 Original line number Diff line number Diff line // DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush. { "pnpmShrinkwrapHash": "0fcefb11b89cf49ba2dbecc264e8ee43ce30d539", "pnpmShrinkwrapHash": "c04ca9a2ee7db66f447f8fb3e6277592fe5b45e7", "preferredVersionsHash": "bf21a9e8fbc5a3846fb05b4fa0859e0917b2202f" } Loading
.vscode/settings.json +1 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ "DESERIALIZERS", "ebml", "Embedder", "fflate", "fluentui", "genymobile", "Genymobile's", Loading
apps/demo/package.json +1 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ "@yume-chan/stream-extra": "workspace:^0.0.18", "@yume-chan/stream-saver": "^2.0.6", "@yume-chan/struct": "workspace:^0.0.18", "fflate": "^0.7.4", "mobx": "^6.7.0", "mobx-react-lite": "^3.4.3", "next": "13.2.4", Loading
apps/demo/src/pages/file-manager.tsx +179 −53 Original line number Diff line number Diff line Loading @@ -29,8 +29,15 @@ import { } from "@fluentui/react-file-type-icons"; import { useConst } from "@fluentui/react-hooks"; import { getIcon } from "@fluentui/style-utilities"; import { AdbFeature, LinuxFileType, type AdbSyncEntry } from "@yume-chan/adb"; import { WrapConsumableStream } from "@yume-chan/stream-extra"; import { AdbFeature, AdbSync, LinuxFileType, type AdbSyncEntry, } from "@yume-chan/adb"; import { WrapConsumableStream, WritableStream } from "@yume-chan/stream-extra"; import { EMPTY_UINT8_ARRAY } from "@yume-chan/struct"; import { Zip, ZipPassThrough } from "fflate"; import { action, autorun, Loading Loading @@ -174,9 +181,9 @@ class FileManagerState { }, }); break; case 1: if (this.selectedItems[0].type === LinuxFileType.File) { result.push({ default: result.push( { key: "download", text: "Download", iconProps: { Loading @@ -188,40 +195,20 @@ class FileManagerState { }, }, onClick: () => { (async () => { const sync = await GLOBAL_STATE.device!.sync(); try { const item = this.selectedItems[0]; const itemPath = path.resolve( this.path, item.name ); await sync .read(itemPath) .pipeTo( saveFile( item.name, Number(item.size) ) ); } catch (e: any) { GLOBAL_STATE.showErrorDialog(e); } finally { sync.dispose(); } })(); void this.download(); return false; }, }); } // fall through default: result.push({ }, { key: "delete", text: "Delete", iconProps: { iconName: Icons.Delete, style: { height: 20, fontSize: 20, lineHeight: 1.5 }, style: { height: 20, fontSize: 20, lineHeight: 1.5, }, }, onClick: () => { (async () => { Loading @@ -229,10 +216,15 @@ class FileManagerState { for (const item of this.selectedItems) { const output = await GLOBAL_STATE.device!.rm( path.resolve(this.path, item.name!) path.resolve( this.path, item.name! ) ); if (output) { GLOBAL_STATE.showErrorDialog(output); GLOBAL_STATE.showErrorDialog( output ); return; } } Loading @@ -244,7 +236,8 @@ class FileManagerState { })(); return false; }, }); } ); break; } Loading Loading @@ -459,6 +452,139 @@ class FileManagerState { }); } private getFileStream(sync: AdbSync, basePath: string, name: string) { return sync.read(path.resolve(basePath, name)); } private async addDirectory( sync: AdbSync, zip: Zip, basePath: string, relativePath: string ) { if (relativePath !== ".") { // Add empty directory const file = new ZipPassThrough(relativePath + "/"); zip.add(file); file.push(EMPTY_UINT8_ARRAY, true); } for (const entry of await sync.readdir( path.resolve(basePath, relativePath) )) { if (entry.name === "." || entry.name === "..") { continue; } switch (entry.type) { case LinuxFileType.Directory: await this.addDirectory( sync, zip, basePath, path.resolve(relativePath, entry.name) ); break; case LinuxFileType.File: await this.addFile( sync, zip, basePath, path.resolve(relativePath, entry.name) ); break; } } } private async addFile( sync: AdbSync, zip: Zip, basePath: string, name: string ) { const file = new ZipPassThrough(name); zip.add(file); await this.getFileStream(sync, basePath, name).pipeTo( new WritableStream({ write(chunk) { file.push(chunk); }, close() { file.push(EMPTY_UINT8_ARRAY, true); }, }) ); } private async download() { const sync = await GLOBAL_STATE.device!.sync(); try { if (this.selectedItems.length === 1) { const item = this.selectedItems[0]; switch (item.type) { case LinuxFileType.Directory: { const stream = saveFile( `${this.selectedItems[0].name}.zip` ); const writer = stream.getWriter(); const zip = new Zip((err, data, final) => { writer.write(data); if (final) { writer.close(); } }); await this.addDirectory( sync, zip, path.resolve(this.path, item.name), "." ); zip.end(); break; } case LinuxFileType.File: await this.getFileStream( sync, this.path, item.name ).pipeTo(saveFile(item.name, Number(item.size))); break; } return; } const stream = saveFile(`${path.basename(this.path)}.zip`); const writer = stream.getWriter(); const zip = new Zip((err, data, final) => { writer.write(data); if (final) { writer.close(); } }); for (const item of this.selectedItems) { switch (item.type) { case LinuxFileType.Directory: await this.addDirectory( sync, zip, this.path, item.name ); break; case LinuxFileType.File: await this.addFile(sync, zip, this.path, item.name); break; } } zip.end(); } catch (e: any) { GLOBAL_STATE.showErrorDialog(e); } finally { sync.dispose(); } } pushPathQuery = (path: string) => { Router.push({ query: { ...Router.query, path } }); }; Loading
common/config/rush/pnpm-lock.yaml +6 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ importers: '@yume-chan/struct': workspace:^0.0.18 eslint: ^8.36.0 eslint-config-next: 13.2.4 fflate: ^0.7.4 mobx: ^6.7.0 mobx-react-lite: ^3.4.3 next: 13.2.4 Loading Loading @@ -73,6 +74,7 @@ importers: '@yume-chan/stream-extra': link:../../libraries/stream-extra '@yume-chan/stream-saver': 2.0.6 '@yume-chan/struct': link:../../libraries/struct fflate: 0.7.4 mobx: 6.8.0 mobx-react-lite: 3.4.3_woojb62cqeyk443mbl7msrwu2e next: 13.2.4_biqbaboplfbrettd7655fr4n2y Loading Loading @@ -4325,6 +4327,10 @@ packages: pend: 1.2.0 dev: true /fflate/0.7.4: resolution: {integrity: sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==} dev: false /file-entry-cache/6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} Loading
common/config/rush/repo-state.json +1 −1 Original line number Diff line number Diff line // DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush. { "pnpmShrinkwrapHash": "0fcefb11b89cf49ba2dbecc264e8ee43ce30d539", "pnpmShrinkwrapHash": "c04ca9a2ee7db66f447f8fb3e6277592fe5b45e7", "preferredVersionsHash": "bf21a9e8fbc5a3846fb05b4fa0859e0917b2202f" }