Skip to content

Commit

Permalink
Add local-only gallery and upgrade to synced
Browse files Browse the repository at this point in the history
  • Loading branch information
bgins committed Aug 21, 2023
1 parent 13aa49e commit fdc14ef
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 44 deletions.
19 changes: 15 additions & 4 deletions src/lib/auth/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { filesystemStore, sessionStore } from '../../stores'
import { getBackupStatus } from '$lib/auth/backup'
import { ACCOUNT_SETTINGS_DIR } from '$lib/account-settings'
import { AREAS } from '$routes/gallery/stores'
import { GALLERY_DIRS } from '$routes/gallery/lib/gallery'
import { GALLERY_DIRS, getImagesExport, type ImagesExport } from '$routes/gallery/lib/gallery'

export const USERNAME_STORAGE_KEY = 'fullUsername'

Expand Down Expand Up @@ -69,11 +69,14 @@ export const register = async (hashedUsername: string): Promise<boolean> => {

if (!success) return success

// Load images from local-only file system
const imageMap = await getImagesExport()

const session = await authStrategy.session()
filesystemStore.set(session.fs)

// TODO Remove if only public and private directories are needed
await initializeFilesystem(session.fs)
// Create gallery directories and write local-only images to file system
await initializeFilesystem(session.fs, imageMap)

const fullUsername = await storage.getItem(USERNAME_STORAGE_KEY) as string

Expand All @@ -95,10 +98,18 @@ export const register = async (hashedUsername: string): Promise<boolean> => {
*
* @param fs FileSystem
*/
const initializeFilesystem = async (fs: FileSystem): Promise<void> => {
const initializeFilesystem = async (fs: FileSystem, imagesExport: ImagesExport): Promise<void> => {
await fs.mkdir(GALLERY_DIRS[ AREAS.PUBLIC ])
await fs.mkdir(GALLERY_DIRS[ AREAS.PRIVATE ])
await fs.mkdir(ACCOUNT_SETTINGS_DIR)

for (const image of imagesExport.public) {
await fs.write(image.path, image.file)
}

for (const image of imagesExport.private) {
await fs.write(image.path, image.file)
}
}

export const loadAccount = async (hashedUsername: string, fullUsername: string): Promise<void> => {
Expand Down
49 changes: 17 additions & 32 deletions src/routes/gallery/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
<script lang="ts">
import { onDestroy } from 'svelte'
import { goto } from '$app/navigation'
import { sessionStore } from '$src/stores'
import { AREAS, galleryStore } from '$routes/gallery/stores'
import Dropzone from '$routes/gallery/components/upload/Dropzone.svelte'
import ImageGallery from '$routes/gallery/components/imageGallery/ImageGallery.svelte'
Expand All @@ -16,38 +12,27 @@
...store,
selectedArea: area
}))
// If the user is not authed redirect them to the home page
const unsubscribe = sessionStore.subscribe(newState => {
if (!newState.loading && !newState.session) {
goto('/')
}
})
onDestroy(unsubscribe)
</script>

<div class="mt-6 p-2 mb-14">
<h1 class="text-heading-lg mb-4">Photo Gallery</h1>
{#if $sessionStore.session}
<div class="flex justify-content-start">
<div class="tabs border-2 overflow-hidden border-base-content">
{#each Object.keys(AREAS) as area}
<button
on:click={() => handleChangeTab(AREAS[area])}
class="tab font-sans uppercase text-heading-sm ease-in {$galleryStore.selectedArea ===
AREAS[area]
? 'tab-active bg-base-content text-base-100'
: 'bg-base-100 text-base-content'}"
>
{AREAS[area]}
</button>
{/each}
</div>
<div class="flex justify-content-start">
<div class="tabs border-2 overflow-hidden border-base-content">
{#each Object.keys(AREAS) as area}
<button
on:click={() => handleChangeTab(AREAS[area])}
class="tab font-sans uppercase text-heading-sm ease-in {$galleryStore.selectedArea ===
AREAS[area]
? 'tab-active bg-base-content text-base-100'
: 'bg-base-100 text-base-content'}"
>
{AREAS[area]}
</button>
{/each}
</div>
</div>

<Dropzone>
<ImageGallery />
</Dropzone>
{/if}
<Dropzone>
<ImageGallery />
</Dropzone>
</div>
11 changes: 3 additions & 8 deletions src/routes/gallery/components/imageGallery/ImageGallery.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,21 @@
}
})
// Once the user has been authed, fetch the images from their file system
// Fetch images from user's file system
let imagesFetched = false
const unsubscribeSessionStore = sessionStore.subscribe((newState) => {
if (newState.session && $filesystemStore && !imagesFetched) {
if ($filesystemStore && !imagesFetched) {
imagesFetched = true
// Get images from the user's public WNFS
getImagesFromWNFS()
}
})
onDestroy(() => {
unsubscribeGalleryStore()
unsubscribeSessionStore()
})
</script>

<section class="mt-8 overflow-hidden">
<div
class="grid grid-cols-2 lg:grid-cols-4 xl:lg:grid-cols-6 gap-4"
>
<div class="grid grid-cols-2 lg:grid-cols-4 xl:lg:grid-cols-6 gap-4">
<FileUploadCard />
{#each $galleryStore.selectedArea === AREAS.PRIVATE ? $galleryStore.privateImages : $galleryStore.publicImages as image}
<ImageCard {image} openModal={setSelectedImage} />
Expand Down
40 changes: 40 additions & 0 deletions src/routes/gallery/lib/gallery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,46 @@ export const getImagesFromWNFS: () => Promise<void> = async () => {
}
}

export type ImagesExport = {
public: { path: odd.path.FilePath<odd.path.PartitionedNonEmpty<odd.path.Public>>; file: Uint8Array }[]
private: { path: odd.path.FilePath<odd.path.PartitionedNonEmpty<odd.path.Private>>; file: Uint8Array }[]
}

export async function getImagesExport(): Promise<ImagesExport> {
const fs = getStore(filesystemStore)

const publicLinks = await fs.ls(GALLERY_DIRS[ 'Public' ])
const privateLinks = await fs.ls(GALLERY_DIRS[ 'Private' ])

const publicImages = await Promise.all(
Object.entries(publicLinks).map(async ([ name ]) => {
const path = odd.path.combine(GALLERY_DIRS[ 'Public' ], odd.path.file(`${name}`))
const file = await fs.get(path)

if (!isFile(file)) return null

return { path, file: file.content }
})
)

const privateImages = await Promise.all(
Object.entries(privateLinks).map(async ([ name ]) => {
const path = odd.path.combine(GALLERY_DIRS[ 'Private' ], odd.path.file(`${name}`))
const file = await fs.get(path)

if (!isFile(file)) return null

return { path, file: file.content }
})
)

return {
public: [ ...publicImages],
private: [ ...privateImages]
}
}


/**
* Upload an image to the user's private or public WNFS
* @param image
Expand Down

0 comments on commit fdc14ef

Please sign in to comment.