From f0c01a66ce12ae3b61144c0fda3e4d32612d3f90 Mon Sep 17 00:00:00 2001 From: space-nuko <24979496+space-nuko@users.noreply.github.com> Date: Wed, 31 May 2023 22:25:53 -0500 Subject: [PATCH] Mobile queue --- src/lib/components/ComfyApp.ts | 3 + .../nodes/actions/ComfySendOutputAction.ts | 31 +---- src/lib/notify.ts | 1 - src/lib/stores/interfaceState.ts | 58 +++++++- src/lib/stores/queueState.ts | 1 - src/lib/utils.ts | 11 +- src/main-desktop.ts | 9 +- src/mobile/GenToolbar.svelte | 49 ++----- src/mobile/MainToolbar.svelte | 13 +- src/mobile/routes/gallery.svelte | 17 ++- src/mobile/routes/queue.svelte | 127 +++++++++++++++++- src/mobile/routes/workflow.svelte | 34 ++++- src/mobile/routes/workflows.svelte | 21 ++- 13 files changed, 277 insertions(+), 98 deletions(-) diff --git a/src/lib/components/ComfyApp.ts b/src/lib/components/ComfyApp.ts index 72d96b7..2c77775 100644 --- a/src/lib/components/ComfyApp.ts +++ b/src/lib/components/ComfyApp.ts @@ -403,6 +403,9 @@ export default class ComfyApp { return false; const workflows = state.workflows as SerializedAppState[]; + if (workflows.length === 0) + return false; + await Promise.all(workflows.map(w => { return this.openWorkflow(w, { refreshCombos: defs, warnMissingNodeTypes: false, setActive: false }).catch(error => { console.error("Failed restoring previous workflow", error) diff --git a/src/lib/nodes/actions/ComfySendOutputAction.ts b/src/lib/nodes/actions/ComfySendOutputAction.ts index 1f6fece..7b744b2 100644 --- a/src/lib/nodes/actions/ComfySendOutputAction.ts +++ b/src/lib/nodes/actions/ComfySendOutputAction.ts @@ -8,6 +8,7 @@ import notify from "$lib/notify"; import workflowState from "$lib/stores/workflowState"; import { get } from "svelte/store"; import type ComfyApp from "$lib/components/ComfyApp"; +import interfaceState from "$lib/stores/interfaceState"; export interface ComfySendOutputActionProperties extends ComfyGraphNodeProperties { } @@ -41,36 +42,8 @@ export default class ComfySendOutputAction extends ComfyGraphNode { this.isActive = true; - const doSend = (modal: ModalData) => { + interfaceState.querySendOutput(value, type, receiveTargets, () => { this.isActive = false; - - const { workflow, targetNode } = get(modal.state) as SendOutputModalResult; - console.warn("send", workflow, targetNode); - - if (workflow == null || targetNode == null) - return - - const app = (window as any).app as ComfyApp; - if (app == null) { - console.error("Couldn't get app!") - return - } - - targetNode.receiveOutput(value); - workflowState.setActiveWorkflow(app.lCanvas, workflow.id) - } - - modalState.pushModal({ - title: "Send Output", - closeOnClick: true, - showCloseButton: true, - svelteComponent: SendOutputModal, - svelteProps: { - value, - type, - receiveTargets - }, - onClose: doSend }) }; } diff --git a/src/lib/notify.ts b/src/lib/notify.ts index 1246045..80a0f2c 100644 --- a/src/lib/notify.ts +++ b/src/lib/notify.ts @@ -18,7 +18,6 @@ function notifyf7(text: string, options: NotifyOptions) { if (!f7) return; - console.error(options) let closeTimeout = options.timeout if (closeTimeout === undefined) closeTimeout = 3000; diff --git a/src/lib/stores/interfaceState.ts b/src/lib/stores/interfaceState.ts index 0d70b14..ec1c04a 100644 --- a/src/lib/stores/interfaceState.ts +++ b/src/lib/stores/interfaceState.ts @@ -1,7 +1,12 @@ -import { debounce } from '$lib/utils'; +import { debounce, isMobileBrowser } from '$lib/utils'; import { get, writable } from 'svelte/store'; import type { Readable, Writable } from 'svelte/store'; -import type { WorkflowInstID } from './workflowState'; +import type { WorkflowInstID, WorkflowReceiveOutputTargets } from './workflowState'; +import modalState, { type ModalData } from './modalState'; +import type { SlotType } from '@litegraph-ts/core'; +import type ComfyApp from '$lib/components/ComfyApp'; +import SendOutputModal, { type SendOutputModalResult } from "$lib/components/modal/SendOutputModal.svelte"; +import workflowState from './workflowState'; export type InterfaceState = { // Show a large indicator of the currently editing number value for mobile @@ -15,13 +20,16 @@ export type InterfaceState = { isJumpingToNode: boolean, selectedWorkflowIndex: number | null - showingWorkflow: boolean + showingWorkflow: boolean, + selectedTab: number, + showSheet: boolean, isDarkMode: boolean } type InterfaceStateOps = { showIndicator: (pointerX: number, pointerY: number, value: any) => void, + querySendOutput: (value: any, type: SlotType, receiveTargets: WorkflowReceiveOutputTargets[], cb: (modal: ModalData) => void) => void, } export type WritableInterfaceStateStore = Writable & InterfaceStateOps; @@ -34,6 +42,8 @@ const store: Writable = writable( graphTransitioning: false, isJumpingToNode: false, + selectedTab: 1, + showSheet: false, selectedWorkflowIndex: null, showingWorkflow: false, @@ -57,9 +67,49 @@ function showIndicator(pointerX: number, pointerY: number, value: any) { debounceDrag(); } +function querySendOutput(value: any, type: SlotType, receiveTargets: WorkflowReceiveOutputTargets[], cb: (modal: ModalData) => void) { + if (isMobileBrowser(navigator.userAgent)) { + store.update(s => { s.showSheet = true; return s; }) + } + else { + const doSend = (modal: ModalData) => { + cb(modal) + + const { workflow, targetNode } = get(modal.state) as SendOutputModalResult; + console.warn("send", workflow, targetNode); + + if (workflow == null || targetNode == null) + return + + const app = (window as any).app as ComfyApp; + if (app == null) { + console.error("Couldn't get app!") + return + } + + targetNode.receiveOutput(value); + workflowState.setActiveWorkflow(app.lCanvas, workflow.id) + } + + modalState.pushModal({ + title: "Send Output", + closeOnClick: true, + showCloseButton: true, + svelteComponent: SendOutputModal, + svelteProps: { + value, + type, + receiveTargets + }, + onClose: doSend + }) + } +} + const interfaceStateStore: WritableInterfaceStateStore = { ...store, - showIndicator + showIndicator, + querySendOutput } export default interfaceStateStore; diff --git a/src/lib/stores/queueState.ts b/src/lib/stores/queueState.ts index eda8da3..f50048a 100644 --- a/src/lib/stores/queueState.ts +++ b/src/lib/stores/queueState.ts @@ -445,7 +445,6 @@ function queueCleared(type: QueueItemType) { store.update(s => { if (type === "queue") { s.queuePending.set([]); - s.queueRunning.set([]); s.queueRemaining = 0; s.runningNodeID = null; s.progress = null; diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 76906d7..68bdff3 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -4,10 +4,11 @@ import type { FileData as GradioFileData } from "@gradio/upload"; import { Subgraph, type LGraph, type LGraphNode, type LLink, type SerializedLGraph, type UUID, type NodeID, type SlotType, type Vector4, type SerializedLGraphNode } from "@litegraph-ts/core"; import { get } from "svelte/store"; import type { ComfyNodeID } from "./api"; -import { type SerializedPrompt } from "./components/ComfyApp"; -import workflowState from "./stores/workflowState"; +import ComfyApp, { type SerializedPrompt } from "./components/ComfyApp"; +import workflowState, { type WorkflowReceiveOutputTargets } from "./stores/workflowState"; import { ImageViewer } from "./ImageViewer"; import configState from "$lib/stores/configState"; +import SendOutputModal, { type SendOutputModalResult } from "$lib/components/modal/SendOutputModal.svelte"; export function clamp(n: number, min: number, max: number): number { if (max <= min) @@ -734,3 +735,9 @@ export function partition(myArray: T[], chunkSize: number): T[] { return tempArray; } + +const MOBILE_USER_AGENTS = ["iPhone", "iPad", "Android", "BlackBerry", "WebOs"].map(a => new RegExp(a, "i")) + +export function isMobileBrowser(userAgent: string): boolean { + return MOBILE_USER_AGENTS.some(a => userAgent.match(a)) +} diff --git a/src/main-desktop.ts b/src/main-desktop.ts index 77e0916..998ed84 100644 --- a/src/main-desktop.ts +++ b/src/main-desktop.ts @@ -1,13 +1,8 @@ -const params = new URLSearchParams(window.location.search) - -const MOBILE_USER_AGENTS = ["iPhone", "iPad", "Android", "BlackBerry", "WebOs"].map(a => new RegExp(a, "i")) - -function isMobileBrowser(userAgent: string): boolean { - return MOBILE_USER_AGENTS.some(a => userAgent.match(a)) -} +import { isMobileBrowser } from "$lib/utils" const isMobile = isMobileBrowser(navigator.userAgent); +const params = new URLSearchParams(window.location.search) if (params.get("desktop") !== "true") { if (isMobile) { window.location.href = "/mobile/" diff --git a/src/mobile/GenToolbar.svelte b/src/mobile/GenToolbar.svelte index 91edc85..2abf932 100644 --- a/src/mobile/GenToolbar.svelte +++ b/src/mobile/GenToolbar.svelte @@ -1,21 +1,11 @@ {#if workflow != null && workflow.attrs.queuePromptButtonName != ""} - - {workflow.attrs.queuePromptButtonName} - +
+ + {workflow.attrs.queuePromptButtonName} + +
{/if} - 🔄 - Save Local - Load -
diff --git a/src/mobile/routes/workflow.svelte b/src/mobile/routes/workflow.svelte index 91984d1..4cc6dcb 100644 --- a/src/mobile/routes/workflow.svelte +++ b/src/mobile/routes/workflow.svelte @@ -1,13 +1,15 @@ @@ -50,6 +65,10 @@ (No workflows opened.) {/if} - +

+ + +

+