From de3a8d422144a95037e4e98b4d413a3727c66941 Mon Sep 17 00:00:00 2001 From: "oAnblu 194724113+oAnblu@users.noreply.github.com" <194724113+oAnblu@users.noreply.github.com> Date: Wed, 24 Dec 2025 02:15:38 +0200 Subject: [PATCH 1/4] Proof of concept implementation of local filesystem drives --- src/ts/drives/localfs.ts | 190 ++++++++++++++++++ .../server/user/daemon/contexts/filesystem.ts | 27 +++ 2 files changed, 217 insertions(+) create mode 100644 src/ts/drives/localfs.ts diff --git a/src/ts/drives/localfs.ts b/src/ts/drives/localfs.ts new file mode 100644 index 00000000..64146150 --- /dev/null +++ b/src/ts/drives/localfs.ts @@ -0,0 +1,190 @@ +import type { + DirectoryReadReturn, + DriveCapabilities, + FileEntry, + FilesystemProgressCallback, + FilesystemStat, + FolderEntry, + UserQuota, +} from "$types/fs"; +import { FilesystemDrive } from "./drive"; + +export class LocalFilesystemDrive extends FilesystemDrive { + override FILESYSTEM_LONG: string = "Local Filesystem Folder"; + override FILESYSTEM_SHORT: string = "lfsf"; + override IDENTIFIES_AS: string = "lfsf"; + override REMOVABLE: boolean = true; + + root: FileSystemDirectoryHandle; + + // todo: finnish implementing stuff + protected override CAPABILITIES: Record = { + readDir: true, + makeDir: true, + readFile: true, + writeFile: true, + tree: false, + copyItem: false, + moveItem: false, + deleteItem: true, + direct: true, + quota: true, + bulk: false, + stat: true, + }; + + constructor(uuid: string, letter: string, root: FileSystemDirectoryHandle) { + super(uuid, letter); + this.root = root; + this.label = `${root.name} (Local)`; + } + + async quota(): Promise { + return { + max: 0, + free: 0, + percentage: 0, + used: 0, + unknown: true, + }; + } + + private async getItemHandle(path: string, create?: "directory" | "file") { + const parts = path.split("/").filter(Boolean); + if (parts.length === 0) return this.root; + let dir: FileSystemDirectoryHandle = this.root; + + try { + for (let i = 0; i < parts.length - 1; i++) dir = await dir.getDirectoryHandle(parts[i]); + const lastPart = parts[parts.length - 1]; + + try { + return await dir.getDirectoryHandle(lastPart, { create: create === "directory" }); + } catch { + return await dir.getFileHandle(lastPart, { create: create === "file" }); + } + } catch { + return undefined; + } + } + + async readDir(path: string): Promise { + const dir = (await this.getItemHandle(path)) as FileSystemDirectoryHandle; + if (!dir || dir.kind !== "directory") return undefined; + + const children = await Array.fromAsync(dir.values()); + const dirs: FolderEntry[] = []; + const files: FileEntry[] = []; + + for (const child of children) { + if (child.kind === "file") { + const file = await (child as FileSystemFileHandle).getFile(); + files.push({ + name: file.name, + itemId: path + "/" + file.name, // fixme: don't do this + dateCreated: new Date(file.lastModified), + dateModified: new Date(file.lastModified), + mimeType: file.type, + size: file.size, + }); + + continue; + } + + if (child.kind === "directory") { + const dir = child as FileSystemDirectoryHandle; + dirs.push({ + name: dir.name, + itemId: path + "/" + dir.name, // fixme: don't do this + + // we don't know these + dateCreated: new Date(0), + dateModified: new Date(0), + }); + continue; + } + + continue; + } + + return { + dirs, + files, + shortcuts: {}, + totalFiles: files.length, + totalFolders: dirs.length, + totalSize: files.map((f) => f.size).reduce((a, b) => a + b), + }; + } + + async createDirectory(path: string): Promise { + const handle = (await this.getItemHandle(path, "directory")) as FileSystemDirectoryHandle; + if (!handle || handle.kind !== "directory") return false; + + return true; + } + + async readFile(path: string, onProgress?: FilesystemProgressCallback): Promise { + const handle = (await this.getItemHandle(path)) as FileSystemFileHandle; + if (handle.kind !== "file") return undefined; + + const file = await handle.getFile(); + return await file.arrayBuffer(); + } + + async writeFile(path: string, data: Blob, onProgress?: FilesystemProgressCallback): Promise { + const handle = (await this.getItemHandle(path, "file")) as FileSystemFileHandle; + if (handle.kind !== "file") return false; + + const writer = await handle.createWritable(); + await writer.write(data); + await writer.close(); + + return true; + } + + async deleteItem(path: string): Promise { + const split = path.split("/"); + + const parent = (await this.getItemHandle(split.slice(0, split.length - 1).join("/"))) as FileSystemDirectoryHandle; + if (!parent || parent.kind !== "directory") return false; + + try { + await parent.removeEntry(split[split.length - 1]); + return true; + } catch (e) { + return false; + } + } + + async direct(path: string): Promise { + const handle = (await this.getItemHandle(path)) as FileSystemFileHandle; + const file = await handle.getFile(); + return URL.createObjectURL(file); + } + + async stat(path: string): Promise { + const handle = (await this.getItemHandle(path))!; + if (!handle) return undefined; + + if (handle.kind === "file") { + const file = await (handle as FileSystemFileHandle).getFile(); + return { + isFile: true, + isDirectory: false, + created: file.lastModified, + modified: file.lastModified, + size: file.size, + }; + } else if (handle.kind === "directory") + return { + isFile: false, + isDirectory: true, + created: 0, + modified: 0, + size: -1, + }; + + return undefined; + } +} diff --git a/src/ts/server/user/daemon/contexts/filesystem.ts b/src/ts/server/user/daemon/contexts/filesystem.ts index 0783c6b4..2ba28d29 100644 --- a/src/ts/server/user/daemon/contexts/filesystem.ts +++ b/src/ts/server/user/daemon/contexts/filesystem.ts @@ -7,6 +7,7 @@ import { import type { LoadSaveDialogData } from "$apps/user/filemanager/types"; import { MessageBox } from "$ts/dialog"; import { LegacyServerDrive } from "$ts/drives/legacy"; +import { LocalFilesystemDrive } from "$ts/drives/localfs"; import type { MemoryFilesystemDrive } from "$ts/drives/temp"; import { ZIPDrive } from "$ts/drives/zipdrive"; import { Env, Fs, Stack, SysDispatch } from "$ts/env"; @@ -523,6 +524,32 @@ export class FilesystemUserContext extends UserContext { ); } + async mountLocalFilesystem() { + if (!("showDirectoryPicker" in window)) return; + + let handle: FileSystemDirectoryHandle | undefined; + + try { + handle = await (window.showDirectoryPicker as any)({ + id: "arcos", + mode: "readwrite", + startIn: "desktop", + }); + } catch (e) { + if ((e as any).name === "AbortError") { + } else throw e; + } + + if (!handle) return; + return await Fs.mountDrive( + btoa(`${handle.name}`), // fixme: use something better as id + LocalFilesystemDrive, + undefined, + undefined, + handle + ); + } + /** * Deletes the specified item WITH SUPPORT FOR RECYCLING * @param path The file or folder to delete From 02355fde0577877ad1fed7d2c3cd54aff8c7eb79 Mon Sep 17 00:00:00 2001 From: allucat1000 <79474282+allucat1000@users.noreply.github.com> Date: Tue, 23 Dec 2025 23:52:19 +0200 Subject: [PATCH 2/4] Added a christmas logo, that renders between the 24th and 26th --- src/assets/branding/christmas.png | Bin 0 -> 29229 bytes src/ts/branding/index.ts | 6 ++++++ src/ts/images/branding.ts | 1 + 3 files changed, 7 insertions(+) create mode 100644 src/assets/branding/christmas.png diff --git a/src/assets/branding/christmas.png b/src/assets/branding/christmas.png new file mode 100644 index 0000000000000000000000000000000000000000..ca17e0f358fbf1a6df46ba974f465beca6a17f25 GIT binary patch literal 29229 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 B&%poy literal 0 HcmV?d00001 diff --git a/src/ts/branding/index.ts b/src/ts/branding/index.ts index 48d987d6..3fbb1414 100755 --- a/src/ts/branding/index.ts +++ b/src/ts/branding/index.ts @@ -1,10 +1,16 @@ import { ReleaseLogo } from "$ts/images/branding"; +import { ChristmasLogo } from "$ts/images/branding"; import { ArcMode } from "$ts/metadata/mode"; import { TryGetDaemon } from "$ts/server/user/daemon"; import { ALIASED_MODES, MODES } from "./stores"; export const Logo = () => { const daemon = TryGetDaemon(); + + const d = new Date(); + if (d.getDate() >= 24 && d.getDate() <= 26 && d.getMonth() === 11) // Check whether to enable the Christmas logo + return ChristmasLogo; + const defaultLogo = daemon?.icons!.getIconCached?.("ReleaseLogo") || ReleaseLogo; return (daemon ? daemon.icons!.getIconCached(ALIASED_MODES[ArcMode()]) : MODES[ArcMode()]) || defaultLogo; diff --git a/src/ts/images/branding.ts b/src/ts/images/branding.ts index 3b38279b..0dc8d1e0 100755 --- a/src/ts/images/branding.ts +++ b/src/ts/images/branding.ts @@ -6,3 +6,4 @@ export { default as NightlyLogo } from "$assets/branding/nightly.svg"; export { default as RcLogo } from "$assets/branding/rc.svg"; export { default as ReleaseLogo } from "$assets/branding/release.svg"; export { default as UnstableLogo } from "$assets/branding/unstable.svg"; +export { default as ChristmasLogo } from "$assets/branding/christmas.png" \ No newline at end of file From fe471f469df0b10b809091c2fbf7a92a1dfa2ea7 Mon Sep 17 00:00:00 2001 From: allucat1000 <79474282+allucat1000@users.noreply.github.com> Date: Wed, 24 Dec 2025 00:37:33 +0200 Subject: [PATCH 3/4] Now we have christmas cheer until the new year --- src/ts/branding/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ts/branding/index.ts b/src/ts/branding/index.ts index 3fbb1414..1eeb9c95 100755 --- a/src/ts/branding/index.ts +++ b/src/ts/branding/index.ts @@ -8,7 +8,7 @@ export const Logo = () => { const daemon = TryGetDaemon(); const d = new Date(); - if (d.getDate() >= 24 && d.getDate() <= 26 && d.getMonth() === 11) // Check whether to enable the Christmas logo + if (d.getDate() >= 24 && d.getDate() <= 31 && d.getMonth() === 11) // Check whether to enable the Christmas logo return ChristmasLogo; const defaultLogo = daemon?.icons!.getIconCached?.("ReleaseLogo") || ReleaseLogo; From f5716a0e12fbb53c513d4666e28dc9b2aa408339 Mon Sep 17 00:00:00 2001 From: Izaak Kuipers Date: Wed, 24 Dec 2025 08:32:56 +0100 Subject: [PATCH 4/4] Update About.svelte --- src/apps/user/settings/Settings/Page/About.svelte | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/apps/user/settings/Settings/Page/About.svelte b/src/apps/user/settings/Settings/Page/About.svelte index 0dababe6..09ac9728 100755 --- a/src/apps/user/settings/Settings/Page/About.svelte +++ b/src/apps/user/settings/Settings/Page/About.svelte @@ -16,13 +16,12 @@ {/if}

- Thank you for using ArcOS! I'm working really hard to give you the best experience possible. Want to learn more about ArcOS? Go + Thank you for using ArcOS! We're working really hard to give you the best experience possible. Want to learn more about ArcOS? Go ahead and visit our GitHub organization, there's some useful stuff there.

-

- Want to contact me? Here you go. + Want to contact us? Here you go.