Updates for mobile

This commit is contained in:
space-nuko
2023-05-07 11:54:54 -05:00
parent 5018200266
commit 71c9617133
15 changed files with 162 additions and 54 deletions

View File

@@ -22,6 +22,7 @@
import ComfyUnlockUIButton from "./ComfyUnlockUIButton.svelte";
import ComfyGraphView from "./ComfyGraphView.svelte";
import { download } from "$lib/utils";
import notify from "$lib/notify";
export let app: ComfyApp = undefined;
let imageViewer: ImageViewer;
@@ -141,7 +142,7 @@
return;
app.saveStateToLocalStorage();
toast.push("Saved to local storage.")
notify("Saved to local storage.")
//
// const date = new Date();
// const formattedDate = date.toISOString().replace(/:/g, '-').replace(/\.\d{3}/g, '').replace('T', '_').replace("Z", "");
@@ -165,7 +166,7 @@
$: if ($uiState.uiUnlocked && !hasShownUIHelpToast) {
hasShownUIHelpToast = true;
toast.push("Right-click to open context menu.")
notify("Right-click to open context menu.")
}
if (debugLayout) {

View File

@@ -28,6 +28,7 @@ import { ComfyBackendNode } from "$lib/nodes/ComfyBackendNode";
import { get } from "svelte/store";
import uiState from "$lib/stores/uiState";
import { promptToGraphVis, workflowToGraphVis } from "$lib/utils";
import notify from "$lib/notify";
export const COMFYBOX_SERIAL_VERSION = 1;
@@ -601,11 +602,7 @@ export default class ComfyApp {
} catch (error) {
// this.ui.dialog.show(error.response || error.toString());
const mes = error.response || error.toString()
toast.push(`Error queuing prompt:\n${mes}`, {
theme: {
'--toastBackground': 'var(--color-red-500)',
}
})
notify(`Error queuing prompt:\n${mes}`, null, "error")
console.error(promptToGraphVis(p))
console.error("Error queuing prompt", mes, num, p)
break;
@@ -643,7 +640,7 @@ export default class ComfyApp {
}
else {
console.error("No metadata found in image file.", pngInfo)
toast.push("No metadata found in image file.")
notify("No metadata found in image file.")
}
}
} else if (file.type === "application/json" || file.name.endsWith(".json")) {

View File

@@ -1,15 +1,7 @@
<script lang="ts">
import queueState from "$lib/stores/queueState";
import ProgressBar from "./ProgressBar.svelte";
function getNodeInfo(nodeId: number): string {
let app = (window as any).app;
if (!app)
return String(nodeId);
const title = app.lGraph.getNodeById(nodeId)?.title || String(nodeId);
return title + " (" + nodeId + ")"
}
import { getNodeInfo } from "$lib/utils"
const entries = [
{

View File

@@ -23,15 +23,17 @@
<style>
.progress {
width: 100%;
height: 100%;
text-align: center;
background-color: lightgrey;
padding: 3px;
padding: 0px;
position: relative;
}
.bar {
height: 100%;
background-color: #B3D8A9;
height: 20px;
}
.label {

View File

@@ -6,6 +6,7 @@ import { toast } from '@zerodevx/svelte-toast'
import type { GalleryOutput } from "./ComfyWidgetNodes";
import { get } from "svelte/store";
import queueState from "$lib/stores/queueState";
import notify from "$lib/notify";
export interface ComfyQueueEventsProperties extends Record<any, any> {
}
@@ -199,7 +200,7 @@ export class ComfyNotifyAction extends ComfyGraphNode {
override onAction(action: any, param: any) {
const message = this.getInputData(0);
if (message) {
toast.push(message);
notify(message);
}
};
}

View File

@@ -113,7 +113,7 @@ export class ComfyBackendNode extends ComfyGraphNode {
}
}
else {
console.error("[ComfyBackendNode] Missing input config in onConfigure()!", input, configs)
console.debug("[ComfyBackendNode] Missing input config in onConfigure()", input, configs)
input.config = {}
}
}

View File

@@ -158,7 +158,7 @@ export default class ComfyImageCacheNode extends ComfyGraphNode {
else {
this.properties.filenames[newIndex] = { filename: null, status: "uploading" }
this.onPropertyChanged("filenames", this.properties.filenames)
const url = "http://localhost:8188" // TODO make configurable
const url = `http://${location.hostname}:8188` // TODO make configurable
const params = new URLSearchParams(data)
const promise = fetch(url + "/view?" + params)

View File

@@ -516,11 +516,11 @@ export class ComfyGalleryNode extends ComfyWidgetNode<GradioFileData[]> {
private convertItems(output: GalleryOutput): GradioFileData[] {
return output.images.map(r => {
// TODO configure backend URL
const url = "http://localhost:8188/view?"
const url = `http://${location.hostname}:8188` // TODO make configurable
const params = new URLSearchParams(r)
return {
name: null,
data: url + params
data: url + "/view?" + params
}
});
}

37
src/lib/notify.ts Normal file
View File

@@ -0,0 +1,37 @@
import { toast } from "@zerodevx/svelte-toast";
import type { SvelteToastOptions } from "@zerodevx/svelte-toast/stores";
import { f7 } from "framework7-svelte"
let notification;
function notifyf7(text: string, title?: string) {
if (!notification) {
notification = f7.notification.create({
title: title,
titleRightText: 'now',
// subtitle: 'Notification with close on click',
text: text,
closeOnClick: true,
closeTimeout: 3000,
});
}
// Open it
notification.open();
}
function notifyToast(text: string, type?: string) {
const options: SvelteToastOptions = {}
if (type === "error") {
options.theme = {
'--toastBackground': 'var(--color-red-500)',
}
}
toast.push(text, options);
}
export default function notify(text: string, title?: string, type?: string) {
notifyf7(text, title);
notifyToast(text, title);
}

View File

@@ -99,3 +99,12 @@ export function promptToGraphVis(prompt: SerializedPrompt): string {
out += "}"
return out
}
export function getNodeInfo(nodeId: number): string {
let app = (window as any).app;
if (!app)
return String(nodeId);
const title = app.lGraph.getNodeById(nodeId)?.title || String(nodeId);
return title + " (" + nodeId + ")"
}

View File

@@ -11,6 +11,7 @@
let option: any
export let debug: boolean = false;
let input: HTMLInputElement | null = null
$: widget && setNodeValue(widget);
@@ -53,6 +54,11 @@
return links[0].data
}
function onSelect() {
if (input)
input.blur();
}
let lastPropsChanged: number = 0;
let werePropsChanged: boolean = false;
@@ -76,8 +82,10 @@
disabled={widget.attrs.disabled || node.properties.values.length === 0}
clearable={false}
showChevron={true}
inputAttributes={{ autocomplete: 'off' }}
bind:input
on:change
on:select
on:select={onSelect}
on:filter
on:blur
/>

View File

@@ -35,6 +35,7 @@
function onRelease(e: Event) {
if (nodeValue && option) {
$nodeValue = option
navigator.vibrate(100)
}
}

View File

@@ -1,38 +1,101 @@
<script lang="ts">
import ComfyApp, { type SerializedAppState } from "$lib/components/ComfyApp";
import notify from "$lib/notify";
import uiState from "$lib/stores/uiState";
import queueState from "$lib/stores/queueState";
import { getNodeInfo } from "$lib/utils"
import { Link, Toolbar } from "framework7-svelte"
import { f7 } from "framework7-svelte"
import ProgressBar from "$lib/components/ProgressBar.svelte";
export let subworkflowID: number = -1;
let app: ComfyApp = undefined;
let fileInput: HTMLInputElement = undefined;
$: if (!app)
app = $uiState.app
function queuePrompt() {
app.queuePrompt(0, 1);
showNotification();
notify("Prompt was queued", "Queued");
}
let notification;
const showNotification = () => {
if (!notification) {
notification = f7.notification.create({
title: 'Queued',
titleRightText: 'now',
// subtitle: 'Notification with close on click',
text: 'Prompt was queued',
closeOnClick: true,
closeTimeout: 3000,
});
function doLoad(): void {
if (!app?.lGraph || !fileInput)
return;
fileInput.click();
}
// Open it
notification.open();
function loadWorkflow(): void {
app.handleFile(fileInput.files[0]);
fileInput.files = null;
}
</script>
<div class="bottom">
{#if $queueState.runningNodeId || $queueState.progress}
<div class="node-name">
<span>Node: {getNodeInfo($queueState.runningNodeId)}</span>
</div>
<div class="progress-bar">
<ProgressBar value={$queueState.progress?.value} max={$queueState.progress?.max} />
</div>
{/if}
{#if typeof $queueState.queueRemaining === "number" && $queueState.queueRemaining > 0}
<div class="queue-remaining in-progress">
<div>
Queued prompts: {$queueState.queueRemaining}.
</div>
</div>
{/if}
</div>
<Toolbar bottom>
<Link on:click={queuePrompt}>Queue Prompt</Link>
<Link on:click={() => app.refreshComboInNodes()}>🔄</Link>
<Link on:click={doLoad}>Load</Link>
<input bind:this={fileInput} id="comfy-file-input" type="file" accept=".json" on:change={loadWorkflow} />
</Toolbar>
<style lang="scss">
#comfy-file-input {
display: none;
}
.bottom {
display: flex;
flex-direction: row;
position: absolute;
text-align: center;
width: 100%;
height: 2rem;
bottom: calc(var(--f7-toolbar-height) + var(--f7-safe-area-bottom));
z-index: var(--layer-top);
background-color: grey;
.node-name {
flex-grow: 1;
background-color: var(--color-red-300);
padding: 0.2em;
display: flex;
justify-content: center;
align-items: center;
}
.progress-bar {
flex-grow: 10;
background-color: var(--color-red-300);
display: flex;
justify-content: center;
align-items: center;
}
.queue-remaining {
flex-grow: 1;
padding: 0.2em;
&.in-progress {
background-color: var(--secondary-300);
}
}
}
</style>

View File

@@ -7,7 +7,7 @@
import uiState from "$lib/stores/uiState"
let app: ComfyApp | null = null;
let lCanvas: LGraphCanvas | null = null;
let lCanvas: ComfyGraphCanvas | null = null;
let canvasEl: HTMLCanvasElement | null = null;
$: if (!app)
@@ -21,13 +21,14 @@
lCanvas.draw(true, true);
}
$: if (app && canvasEl) {
$: if (app != null && canvasEl != null) {
if (!lCanvas) {
lCanvas = new ComfyGraphCanvas(app, canvasEl);
lCanvas.allow_interaction = false;
LiteGraph.dialog_close_on_mouse_leave = false;
LiteGraph.search_hide_on_mouse_leave = false;
LiteGraph.pointerevents_method = "pointer";
app.lGraph.eventBus.on("afterExecute", () => lCanvas.draw(true))
}
resizeCanvas();
}

View File

@@ -1,26 +1,22 @@
<script lang="ts">
import ComfyApp, { type SerializedAppState } from "$lib/components/ComfyApp";
import uiState from "$lib/stores/uiState";
import layoutState, { type IDragItem } from "$lib/stores/layoutState";
import queueState from "$lib/stores/queueState";
import { Page, Navbar, Link, BlockTitle, Block, List, ListItem, Toolbar } from "framework7-svelte"
import WidgetContainer from "$lib/components/WidgetContainer.svelte";
export let subworkflowID: number = -1;
let app: ComfyApp = undefined;
$: if (!app)
app = $uiState.app
</script>
<Page name="subworkflow">
<Navbar title="Workflow {subworkflowID}" backLink="Back" />
<div>Workflow!</div>
<WidgetContainer bind:dragItem={$layoutState.root} classes={["root-container", "mobile"]} />
</Page>
<style>
.is-executing {
border: 5px dashed var(--color-green-600) !important;
<style lang="scss">
// TODO generalize this to all properties!
:global(.root-container.mobile > .block > .v-pane) {
flex-direction: column !important;
}
</style>