radames commited on
Commit
3b048e4
β€’
1 Parent(s): f9856f3

block painting on ongoing frames

Browse files
frontend/src/lib/App.svelte CHANGED
@@ -5,7 +5,7 @@
5
  import PaintCanvas from '$lib/PaintCanvas.svelte';
6
  import Menu from '$lib/Menu.svelte';
7
  import PromptModal from '$lib/PromptModal.svelte';
8
- import { COLORS } from '$lib/constants';
9
  import { PUBLIC_WS_INPAINTING } from '$env/static/public';
10
  import type { PromptImgKey } from '$lib/types';
11
  import { Status } from '$lib/types';
@@ -21,39 +21,72 @@
21
 
22
  const myPresence = useMyPresence({ addToHistory: true });
23
  const others = useOthers();
24
-
25
  function getKey(position: { x: number; y: number }): PromptImgKey {
26
  return `${position.x}_${position.y}`;
27
  }
28
 
29
  const promptImgStorage = useObject('promptImgStorage');
30
 
31
- let showModal = false;
32
-
33
  $: isLoading = $myPresence?.status === Status.loading || $isRenderingCanvas || false;
34
-
35
- function onPrompt() {
36
- if (!isLoading && !showModal) {
37
- showModal = true;
38
  myPresence.update({
39
  status: Status.prompting
40
  });
 
 
 
 
41
  }
42
  }
43
- function onClose() {
44
- showModal = false;
45
- }
46
 
47
  function onPaint() {
48
- generateImage();
49
  showModal = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  }
51
 
 
 
 
 
 
52
  async function generateImage() {
53
  if (isLoading) return;
54
- $loadingState = 'Pending';
55
  const prompt = $myPresence.currentPrompt;
56
  const position = $myPresence.frame;
 
 
 
 
 
 
 
 
 
57
  const imageKey = getKey(position);
58
  const room = $selectedRoomID || 'default';
59
  console.log('Generating...', prompt, position);
@@ -137,9 +170,7 @@
137
  $promptImgStorage.set(imageKey, promptImgParams);
138
  console.log(params.image.url);
139
  $loadingState = data.success ? 'Complete' : 'Error';
140
- setTimeout(() => {
141
- $loadingState = '';
142
- }, 2000);
143
  myPresence.update({
144
  status: Status.ready,
145
  currentPrompt: ''
@@ -150,9 +181,7 @@
150
  myPresence.update({
151
  status: Status.ready
152
  });
153
- setTimeout(() => {
154
- $loadingState = '';
155
- }, 10000);
156
  }
157
  websocket.close();
158
  return;
@@ -173,14 +202,16 @@
173
  {$loadingState}
174
  </div>
175
  {#if showModal}
176
- <PromptModal on:paint={onPaint} on:close={onClose} initPrompt={$myPresence?.currentPrompt} />
 
 
 
 
177
  {/if}
178
  <div class="fixed top-0 left-0 z-0 w-screen h-screen min-h-[600px]">
179
  <PaintCanvas />
180
 
181
  <main class="z-10 relative">
182
- <PaintFrame on:prompt={onPrompt} transform={$currZoomTransform} />
183
-
184
  <!-- When others connected, iterate through others and show their cursors -->
185
  {#if $others}
186
  {#each [...$others] as { connectionId, presence } (connectionId)}
@@ -201,10 +232,11 @@
201
  {/if}
202
  {/each}
203
  {/if}
 
204
  </main>
205
  </div>
206
  <div class="fixed bottom-0 md:bottom-16 left-0 right-0 z-10 my-2">
207
- <Menu on:prompt={onPrompt} {isLoading} />
208
  </div>
209
 
210
  <style lang="postcss" scoped>
 
5
  import PaintCanvas from '$lib/PaintCanvas.svelte';
6
  import Menu from '$lib/Menu.svelte';
7
  import PromptModal from '$lib/PromptModal.svelte';
8
+ import { COLORS, FRAME_SIZE } from '$lib/constants';
9
  import { PUBLIC_WS_INPAINTING } from '$env/static/public';
10
  import type { PromptImgKey } from '$lib/types';
11
  import { Status } from '$lib/types';
 
21
 
22
  const myPresence = useMyPresence({ addToHistory: true });
23
  const others = useOthers();
24
+ let showModal = false;
25
  function getKey(position: { x: number; y: number }): PromptImgKey {
26
  return `${position.x}_${position.y}`;
27
  }
28
 
29
  const promptImgStorage = useObject('promptImgStorage');
30
 
 
 
31
  $: isLoading = $myPresence?.status === Status.loading || $isRenderingCanvas || false;
32
+ function onShowModal(e: CustomEvent) {
33
+ if (isLoading) return;
34
+ showModal = e.detail.showModal;
35
+ if (showModal) {
36
  myPresence.update({
37
  status: Status.prompting
38
  });
39
+ } else {
40
+ myPresence.update({
41
+ status: Status.ready
42
+ });
43
  }
44
  }
 
 
 
45
 
46
  function onPaint() {
 
47
  showModal = false;
48
+ generateImage();
49
+ }
50
+ function canPaint(position: { x: number; y: number }): boolean {
51
+ if (!$others) return true;
52
+ console.log('P', position);
53
+ let canPaint = true;
54
+ for (const { presence } of $others) {
55
+ if (
56
+ position.x < presence.frame.x + FRAME_SIZE &&
57
+ position.x + FRAME_SIZE > presence.frame.x &&
58
+ position.y < presence.frame.y + FRAME_SIZE &&
59
+ position.y + FRAME_SIZE > presence.frame.y
60
+ ) {
61
+ // can paint if presence is only dragging
62
+ if (presence.status === Status.ready || presence.status === Status.dragging) {
63
+ canPaint = true;
64
+ }
65
+ canPaint = false;
66
+ break;
67
+ }
68
+ }
69
+ return canPaint;
70
  }
71
 
72
+ function clearStateMsg(t = 5000) {
73
+ setTimeout(() => {
74
+ $loadingState = '';
75
+ }, t);
76
+ }
77
  async function generateImage() {
78
  if (isLoading) return;
 
79
  const prompt = $myPresence.currentPrompt;
80
  const position = $myPresence.frame;
81
+ $loadingState = 'Pending';
82
+ if (!canPaint(position)) {
83
+ $loadingState = 'Someone is already painting here';
84
+ myPresence.update({
85
+ status: Status.ready
86
+ });
87
+ clearStateMsg();
88
+ return;
89
+ }
90
  const imageKey = getKey(position);
91
  const room = $selectedRoomID || 'default';
92
  console.log('Generating...', prompt, position);
 
170
  $promptImgStorage.set(imageKey, promptImgParams);
171
  console.log(params.image.url);
172
  $loadingState = data.success ? 'Complete' : 'Error';
173
+ clearStateMsg();
 
 
174
  myPresence.update({
175
  status: Status.ready,
176
  currentPrompt: ''
 
181
  myPresence.update({
182
  status: Status.ready
183
  });
184
+ clearStateMsg(10000);
 
 
185
  }
186
  websocket.close();
187
  return;
 
202
  {$loadingState}
203
  </div>
204
  {#if showModal}
205
+ <PromptModal
206
+ on:paint={onPaint}
207
+ initPrompt={$myPresence?.currentPrompt}
208
+ on:showModal={onShowModal}
209
+ />
210
  {/if}
211
  <div class="fixed top-0 left-0 z-0 w-screen h-screen min-h-[600px]">
212
  <PaintCanvas />
213
 
214
  <main class="z-10 relative">
 
 
215
  <!-- When others connected, iterate through others and show their cursors -->
216
  {#if $others}
217
  {#each [...$others] as { connectionId, presence } (connectionId)}
 
232
  {/if}
233
  {/each}
234
  {/if}
235
+ <PaintFrame transform={$currZoomTransform} on:showModal={onShowModal} />
236
  </main>
237
  </div>
238
  <div class="fixed bottom-0 md:bottom-16 left-0 right-0 z-10 my-2">
239
+ <Menu {isLoading} on:showModal={onShowModal} />
240
  </div>
241
 
242
  <style lang="postcss" scoped>
frontend/src/lib/Menu.svelte CHANGED
@@ -1,17 +1,21 @@
1
  <script lang="ts">
2
- import { createEventDispatcher } from 'svelte';
3
  import RoomsSelector from '$lib/Buttons/RoomsSelector.svelte';
4
  import AboutButton from '$lib/Buttons/AboutButton.svelte';
5
  import { toggleAbout } from '$lib/store';
6
- // const broadcast = useBroadcastEvent();
7
 
8
  const dispatch = createEventDispatcher();
 
9
 
10
  export let isLoading = false;
11
  </script>
12
 
13
  <svelte:window
14
- on:keyup|preventDefault|stopPropagation={(e) => e.key === 'Enter' && dispatch('prompt')}
 
 
 
 
15
  />
16
  <div class="flex flex-col md:flex-row items-center justify-between px-4 md:px-12 gap-3 md:gap-0">
17
  <AboutButton
@@ -21,7 +25,7 @@
21
  />
22
 
23
  <button
24
- on:click={() => dispatch('prompt')}
25
  title="Click to prompt, and paint. The generated image will show up in the frame."
26
  disabled={isLoading}
27
  class="{isLoading
@@ -48,7 +52,5 @@
48
  Enter</span
49
  ></button
50
  >
51
-
52
  <RoomsSelector {isLoading} />
53
- <!-- <PPButton {isLoading} on:click={() => dispatch('prompt')} /> -->
54
  </div>
 
1
  <script lang="ts">
 
2
  import RoomsSelector from '$lib/Buttons/RoomsSelector.svelte';
3
  import AboutButton from '$lib/Buttons/AboutButton.svelte';
4
  import { toggleAbout } from '$lib/store';
5
+ import { createEventDispatcher } from 'svelte';
6
 
7
  const dispatch = createEventDispatcher();
8
+ // const broadcast = useBroadcastEvent();
9
 
10
  export let isLoading = false;
11
  </script>
12
 
13
  <svelte:window
14
+ on:keypress={(e) => {
15
+ if (e.key === 'Enter') {
16
+ dispatch('showModal', { showModal: true });
17
+ }
18
+ }}
19
  />
20
  <div class="flex flex-col md:flex-row items-center justify-between px-4 md:px-12 gap-3 md:gap-0">
21
  <AboutButton
 
25
  />
26
 
27
  <button
28
+ on:click={() => dispatch('showModal', { showModal: true })}
29
  title="Click to prompt, and paint. The generated image will show up in the frame."
30
  disabled={isLoading}
31
  class="{isLoading
 
52
  Enter</span
53
  ></button
54
  >
 
55
  <RoomsSelector {isLoading} />
 
56
  </div>
frontend/src/lib/PaintFrame.svelte CHANGED
@@ -7,10 +7,11 @@
7
  import { round } from '$lib/utils';
8
 
9
  import type { ZoomTransform } from 'd3-zoom';
10
- import { onMount , createEventDispatcher} from 'svelte';
11
 
12
  import { useMyPresence } from '$lib/liveblocks';
13
  import { canvasEl, maskEl, loadingState, isRenderingCanvas } from '$lib/store';
 
14
 
15
  import { Status } from './types';
16
  const myPresence = useMyPresence({ addToHistory: true });
@@ -274,7 +275,7 @@
274
  <div class="mx-4 flex flex-col gap-2">
275
  <button
276
  title="Click to prompt and paint"
277
- on:click={() => dispatch('prompt')}
278
  class="w-10 h-10 bg-blue-600 hover:saturate-150 shadow-2xl shadow-blue-500 rounded-lg flex items-center justify-center text-3xl"
279
  >
280
  πŸ–
 
7
  import { round } from '$lib/utils';
8
 
9
  import type { ZoomTransform } from 'd3-zoom';
10
+ import { onMount } from 'svelte';
11
 
12
  import { useMyPresence } from '$lib/liveblocks';
13
  import { canvasEl, maskEl, loadingState, isRenderingCanvas } from '$lib/store';
14
+ import { createEventDispatcher } from 'svelte';
15
 
16
  import { Status } from './types';
17
  const myPresence = useMyPresence({ addToHistory: true });
 
275
  <div class="mx-4 flex flex-col gap-2">
276
  <button
277
  title="Click to prompt and paint"
278
+ on:click={() => dispatch('showModal', { showModal: true })}
279
  class="w-10 h-10 bg-blue-600 hover:saturate-150 shadow-2xl shadow-blue-500 rounded-lg flex items-center justify-center text-3xl"
280
  >
281
  πŸ–
frontend/src/lib/PromptModal.svelte CHANGED
@@ -4,18 +4,18 @@
4
  import { Status } from '$lib/types';
5
 
6
  const dispatch = createEventDispatcher();
 
7
  export let initPrompt = '';
 
8
  let prompt: string;
9
  let inputEl: HTMLInputElement;
10
  let boxEl: HTMLDivElement;
11
- const myPresence = useMyPresence({ addToHistory: true });
12
 
13
  const onKeyup = (e: KeyboardEvent) => {
14
  if (e.key === 'Escape') {
15
- myPresence.update({
16
- status: Status.ready
17
- });
18
- dispatch('close');
19
  }
20
  };
21
 
@@ -41,10 +41,13 @@
41
  });
42
  }, 100);
43
  }
44
- function onPrompt() {
 
 
 
 
45
  if (prompt.trim() !== '') {
46
  dispatch('paint');
47
- dispatch('close');
48
  }
49
  }
50
  function onInput(event: Event) {
@@ -58,13 +61,13 @@
58
  myPresence.update({
59
  status: Status.ready
60
  });
61
- dispatch('close');
62
  }
63
  </script>
64
 
65
  <form
66
  class="fixed w-screen top-0 left-0 bottom-0 right-0 h-screen z-50 flex items-center justify-center bg-black bg-opacity-80"
67
- on:submit|preventDefault|stopPropagation={onPrompt}
68
  >
69
  <div
70
  class="flex bg-white overflow-hidden rounded-2xl w-full max-w-lg 2xl:max-w-xl"
 
4
  import { Status } from '$lib/types';
5
 
6
  const dispatch = createEventDispatcher();
7
+
8
  export let initPrompt = '';
9
+
10
  let prompt: string;
11
  let inputEl: HTMLInputElement;
12
  let boxEl: HTMLDivElement;
13
+ const myPresence = useMyPresence({ addToHistory: true });
14
 
15
  const onKeyup = (e: KeyboardEvent) => {
16
  if (e.key === 'Escape') {
17
+ dispatch('showModal', { showModal: false });
18
+ console.log('Escape');
 
 
19
  }
20
  };
21
 
 
41
  });
42
  }, 100);
43
  }
44
+ function onPrompt(event: Event) {
45
+ event.stopPropagation();
46
+ event.preventDefault();
47
+ event.stopImmediatePropagation();
48
+
49
  if (prompt.trim() !== '') {
50
  dispatch('paint');
 
51
  }
52
  }
53
  function onInput(event: Event) {
 
61
  myPresence.update({
62
  status: Status.ready
63
  });
64
+ dispatch('showModal', { showModal: false });
65
  }
66
  </script>
67
 
68
  <form
69
  class="fixed w-screen top-0 left-0 bottom-0 right-0 h-screen z-50 flex items-center justify-center bg-black bg-opacity-80"
70
+ on:submit={onPrompt}
71
  >
72
  <div
73
  class="flex bg-white overflow-hidden rounded-2xl w-full max-w-lg 2xl:max-w-xl"
frontend/src/lib/liveblocks/useRooms.ts CHANGED
@@ -3,7 +3,7 @@ import { writable, type Writable } from "svelte/store";
3
  import type { RoomResponse } from '$lib/types';
4
  import { PUBLIC_API_BASE } from '$env/static/public';
5
 
6
- const INTERVAL = 3000
7
 
8
  export function useRooms(): Writable<RoomResponse[]> {
9
  const roomsStorage = writable<RoomResponse[]>([]);
 
3
  import type { RoomResponse } from '$lib/types';
4
  import { PUBLIC_API_BASE } from '$env/static/public';
5
 
6
+ const INTERVAL = 10000
7
 
8
  export function useRooms(): Writable<RoomResponse[]> {
9
  const roomsStorage = writable<RoomResponse[]>([]);
frontend/src/lib/store.ts CHANGED
@@ -7,4 +7,5 @@ export const canvasEl = writable<HTMLCanvasElement>();
7
  export const maskEl = writable<HTMLCanvasElement>();
8
  export const selectedRoomID = writable<string | null>();
9
  export const toggleAbout = writable<boolean>(false);
10
- export const isRenderingCanvas = writable<boolean>(true);
 
 
7
  export const maskEl = writable<HTMLCanvasElement>();
8
  export const selectedRoomID = writable<string | null>();
9
  export const toggleAbout = writable<boolean>(false);
10
+ export const isRenderingCanvas = writable<boolean>(true);
11
+ export const showModal = writable<boolean>(false);
frontend/src/lib/types.ts CHANGED
@@ -15,7 +15,7 @@ export type Presence = {
15
  frame: {
16
  x: number;
17
  y: number;
18
- } | null;
19
  status: Status;
20
  currentPrompt: string
21
  }
 
15
  frame: {
16
  x: number;
17
  y: number;
18
+ };
19
  status: Status;
20
  currentPrompt: string
21
  }