about summary refs log tree commit diff
path: root/src/view/com/composer/state.ts
diff options
context:
space:
mode:
authordan <dan.abramov@gmail.com>2024-10-02 00:08:46 +0900
committerGitHub <noreply@github.com>2024-10-02 00:08:46 +0900
commitd2fd5589dc93831cda625ad91083b8b051878d39 (patch)
tree0bb56467eece49028d70ebe5402f4792630d433a /src/view/com/composer/state.ts
parenta7ee561e4074f839f340c77a1f21c8f5657865c7 (diff)
downloadvoidsky-d2fd5589dc93831cda625ad91083b8b051878d39.tar.zst
Introduce a composer reducer and move image state there (#5547)
* Add composer reducer

* Support adding images

Co-authored-by: Mary <git@mary.my.id>

* Support updating and deleting images

Co-authored-by: Mary <git@mary.my.id>

* Derive images state from composer state

Co-authored-by: Mary <git@mary.my.id>

---------

Co-authored-by: Mary <git@mary.my.id>
Diffstat (limited to 'src/view/com/composer/state.ts')
-rw-r--r--src/view/com/composer/state.ts131
1 files changed, 131 insertions, 0 deletions
diff --git a/src/view/com/composer/state.ts b/src/view/com/composer/state.ts
new file mode 100644
index 000000000..5588de1aa
--- /dev/null
+++ b/src/view/com/composer/state.ts
@@ -0,0 +1,131 @@
+import {ComposerImage, createInitialImages} from '#/state/gallery'
+import {ComposerOpts} from '#/state/shell/composer'
+
+type PostRecord = {
+  uri: string
+}
+
+type ImagesMedia = {
+  type: 'images'
+  images: ComposerImage[]
+  labels: string[]
+}
+
+type ComposerEmbed = {
+  // TODO: Other record types.
+  record: PostRecord | undefined
+  // TODO: Other media types.
+  media: ImagesMedia | undefined
+}
+
+export type ComposerState = {
+  // TODO: Other draft data.
+  embed: ComposerEmbed
+}
+
+export type ComposerAction =
+  | {type: 'embed_add_images'; images: ComposerImage[]}
+  | {type: 'embed_update_image'; image: ComposerImage}
+  | {type: 'embed_remove_image'; image: ComposerImage}
+
+const MAX_IMAGES = 4
+
+export function composerReducer(
+  state: ComposerState,
+  action: ComposerAction,
+): ComposerState {
+  switch (action.type) {
+    case 'embed_add_images': {
+      const prevMedia = state.embed.media
+      let nextMedia = prevMedia
+      if (!prevMedia) {
+        nextMedia = {
+          type: 'images',
+          images: action.images.slice(0, MAX_IMAGES),
+          labels: [],
+        }
+      } else if (prevMedia.type === 'images') {
+        nextMedia = {
+          ...prevMedia,
+          images: [...prevMedia.images, ...action.images].slice(0, MAX_IMAGES),
+        }
+      }
+      return {
+        ...state,
+        embed: {
+          ...state.embed,
+          media: nextMedia,
+        },
+      }
+    }
+    case 'embed_update_image': {
+      const prevMedia = state.embed.media
+      if (prevMedia?.type === 'images') {
+        const updatedImage = action.image
+        const nextMedia = {
+          ...prevMedia,
+          images: prevMedia.images.map(img => {
+            if (img.source.id === updatedImage.source.id) {
+              return updatedImage
+            }
+            return img
+          }),
+        }
+        return {
+          ...state,
+          embed: {
+            ...state.embed,
+            media: nextMedia,
+          },
+        }
+      }
+      return state
+    }
+    case 'embed_remove_image': {
+      const prevMedia = state.embed.media
+      if (prevMedia?.type === 'images') {
+        const removedImage = action.image
+        let nextMedia: ImagesMedia | undefined = {
+          ...prevMedia,
+          images: prevMedia.images.filter(img => {
+            return img.source.id !== removedImage.source.id
+          }),
+        }
+        if (nextMedia.images.length === 0) {
+          nextMedia = undefined
+        }
+        return {
+          ...state,
+          embed: {
+            ...state.embed,
+            media: nextMedia,
+          },
+        }
+      }
+      return state
+    }
+    default:
+      return state
+  }
+}
+
+export function createComposerState({
+  initImageUris,
+}: {
+  initImageUris: ComposerOpts['imageUris']
+}): ComposerState {
+  let media: ImagesMedia | undefined
+  if (initImageUris?.length) {
+    media = {
+      type: 'images',
+      images: createInitialImages(initImageUris),
+      labels: [],
+    }
+  }
+  return {
+    embed: {
+      record: undefined,
+      media,
+    },
+  }
+}