[mobile] Show graph
This commit is contained in:
@@ -1,14 +1,28 @@
|
||||
<script lang="ts">
|
||||
import { App, View, Page, Navbar, Toolbar, Link } from 'framework7-svelte';
|
||||
import "framework7/css/bundle"
|
||||
import { onMount } from "svelte";
|
||||
import { get } from "svelte/store";
|
||||
import { Button } from "@gradio/button";
|
||||
import ComfyApp, { type SerializedAppState } from "$lib/components/ComfyApp";
|
||||
import { Checkbox } from "@gradio/form"
|
||||
import widgetState from "$lib/stores/widgetState";
|
||||
import nodeState from "$lib/stores/nodeState";
|
||||
import uiState from "$lib/stores/uiState";
|
||||
import { ImageViewer } from "$lib/ImageViewer";
|
||||
import { download } from "$lib/utils"
|
||||
|
||||
import { onMount } from 'svelte';
|
||||
import { f7, f7ready } from 'framework7-svelte';
|
||||
import { LGraph, LGraphNode } from "@litegraph-ts/core";
|
||||
import type { ComfyAPIStatus } from "$lib/api";
|
||||
import queueState from "$lib/stores/queueState";
|
||||
import { App, View, Toolbar, Page, Navbar, Link, BlockTitle, Block, List, ListItem } from "framework7-svelte"
|
||||
|
||||
// Import pages components
|
||||
import HomePage from './home.svelte';
|
||||
import AboutPage from './about.svelte';
|
||||
import LoginPage from './login.svelte';
|
||||
import { f7, f7ready } from 'framework7-svelte';
|
||||
|
||||
import "framework7/css/bundle"
|
||||
|
||||
import HomePage from './mobile/routes/home.svelte';
|
||||
import AboutPage from './mobile/routes/about.svelte';
|
||||
import LoginPage from './mobile/routes/login.svelte';
|
||||
import GraphPage from './mobile/routes/graph.svelte';
|
||||
|
||||
function onBackKeyDown(e) {
|
||||
if(f7.view.current.router.currentRoute.path == '/'){
|
||||
@@ -21,56 +35,61 @@
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
onMount(async () => {
|
||||
window.addEventListener("backbutton", onBackKeyDown, false);
|
||||
window.addEventListener("popstate", onBackKeyDown, false);
|
||||
})
|
||||
});
|
||||
|
||||
/*
|
||||
/*
|
||||
Now we need to map components to routes.
|
||||
We need to pass them along with the F7 app parameters to <App> component
|
||||
*/
|
||||
|
||||
const f7params = {
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
component: HomePage,
|
||||
},
|
||||
{
|
||||
path: '/about/',
|
||||
component: AboutPage,
|
||||
},
|
||||
{
|
||||
path: '/login/',
|
||||
component: LoginPage,
|
||||
},
|
||||
],
|
||||
popup: {
|
||||
closeOnEscape: true,
|
||||
},
|
||||
sheet: {
|
||||
closeOnEscape: true,
|
||||
},
|
||||
popover: {
|
||||
closeOnEscape: true,
|
||||
},
|
||||
actions: {
|
||||
closeOnEscape: true,
|
||||
},
|
||||
}
|
||||
let f7params = {
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
component: HomePage,
|
||||
},
|
||||
{
|
||||
path: '/about/',
|
||||
component: AboutPage,
|
||||
},
|
||||
{
|
||||
path: '/login/',
|
||||
component: LoginPage,
|
||||
},
|
||||
{
|
||||
path: '/graph/',
|
||||
component: GraphPage,
|
||||
},
|
||||
],
|
||||
popup: {
|
||||
closeOnEscape: true,
|
||||
},
|
||||
sheet: {
|
||||
closeOnEscape: true,
|
||||
},
|
||||
popover: {
|
||||
closeOnEscape: true,
|
||||
},
|
||||
actions: {
|
||||
closeOnEscape: true,
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Main Framework7 App component where we pass Framework7 params -->
|
||||
<App theme="ios" name="ComfyBox" {...f7params}>
|
||||
<App theme="auto" name="ComfyBox" {...f7params}>
|
||||
<View
|
||||
url="/"
|
||||
main={true}
|
||||
class="safe-areas"
|
||||
masterDetailBreakpoint={768},
|
||||
browserHistory=true,
|
||||
browserHistoryRoot="/mobile/"
|
||||
/>
|
||||
|
||||
<!-- Your main view, should have "main" prop -->
|
||||
<View
|
||||
url="/"
|
||||
main={true}
|
||||
class="safe-areas"
|
||||
masterDetailBreakpoint={768},
|
||||
browserHistory=true,
|
||||
browserHistoryRoot="/mobile/"
|
||||
/>
|
||||
<div class="canvas-wrapper pane-wrapper" style="display: none">
|
||||
<canvas id="graph-canvas" />
|
||||
</div>
|
||||
</App>
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
<!-- home.svelte -->
|
||||
<Page name="home">
|
||||
<Navbar title="Home Page" />
|
||||
...
|
||||
<Link href="/about/">About Page</Link>
|
||||
<Link href="/login/">Login Page</Link>
|
||||
</Page>
|
||||
<script>
|
||||
import { Page, Navbar, Link } from 'framework7-svelte';
|
||||
</script>
|
||||
@@ -9,7 +9,6 @@ export default class ComfyGraphCanvas extends LGraphCanvas {
|
||||
constructor(
|
||||
app: ComfyApp,
|
||||
canvas: HTMLCanvasElement | string,
|
||||
graph?: LGraph,
|
||||
options: {
|
||||
skip_render?: boolean;
|
||||
skip_events?: boolean;
|
||||
@@ -17,7 +16,7 @@ export default class ComfyGraphCanvas extends LGraphCanvas {
|
||||
viewport?: Vector4;
|
||||
} = {}
|
||||
) {
|
||||
super(canvas, graph, options);
|
||||
super(canvas, app.lGraph, options);
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,11 +88,11 @@ export default class GraphSync {
|
||||
this.stores[nodeId].push({ store: wuis.value, unsubscribe: unsub });
|
||||
}
|
||||
|
||||
console.log("NEWSTORES", this.stores[nodeId])
|
||||
console.debug("NEWSTORES", this.stores[nodeId])
|
||||
}
|
||||
|
||||
private removeStores(nodeId: string) {
|
||||
console.log("DELSTORES", this.stores[nodeId])
|
||||
console.debug("DELSTORES", this.stores[nodeId])
|
||||
for (const ss of this.stores[nodeId]) {
|
||||
ss.unsubscribe();
|
||||
}
|
||||
|
||||
@@ -49,8 +49,6 @@ export default class ComfyAPI extends EventTarget {
|
||||
private getBackendUrl(): string {
|
||||
const hostname = this.hostname || location.hostname;
|
||||
const port = this.port || location.port;
|
||||
console.log(hostname)
|
||||
console.log(port)
|
||||
return `${window.location.protocol}//${hostname}:${port}`
|
||||
}
|
||||
|
||||
|
||||
@@ -120,11 +120,11 @@
|
||||
});
|
||||
|
||||
await app.setup();
|
||||
refreshView();
|
||||
|
||||
(window as any).app = app;
|
||||
(window as any).appPane = uiPane;
|
||||
|
||||
refreshView();
|
||||
|
||||
imageViewer = new ImageViewer(app.rootEl);
|
||||
|
||||
let wrappers = containerElem.querySelectorAll<HTMLDivElement>(".pane-wrapper")
|
||||
|
||||
@@ -88,7 +88,7 @@ export default class ComfyApp {
|
||||
this.rootEl = document.getElementById("main") as HTMLDivElement;
|
||||
this.canvasEl = document.getElementById("graph-canvas") as HTMLCanvasElement;
|
||||
this.lGraph = new LGraph();
|
||||
this.lCanvas = new ComfyGraphCanvas(this, this.canvasEl, this.lGraph);
|
||||
this.lCanvas = new ComfyGraphCanvas(this, this.canvasEl);
|
||||
this.canvasCtx = this.canvasEl.getContext("2d");
|
||||
this.graphSync = new GraphSync(this);
|
||||
|
||||
@@ -151,37 +151,37 @@ export default class ComfyApp {
|
||||
}
|
||||
|
||||
private graphOnConfigure() {
|
||||
console.log("Configured");
|
||||
console.debug("Configured");
|
||||
this.eventBus.emit("configured", this.lGraph);
|
||||
}
|
||||
|
||||
private graphOnBeforeChange(graph: LGraph, info: any) {
|
||||
console.log("BeforeChange", info);
|
||||
console.debug("BeforeChange", info);
|
||||
this.eventBus.emit("beforeChange", graph, info);
|
||||
}
|
||||
|
||||
private graphOnAfterChange(graph: LGraph, info: any) {
|
||||
console.log("AfterChange", info);
|
||||
console.debug("AfterChange", info);
|
||||
this.eventBus.emit("afterChange", graph, info);
|
||||
}
|
||||
|
||||
private graphOnNodeAdded(node: LGraphNode) {
|
||||
console.log("Added", node);
|
||||
console.debug("Added", node);
|
||||
this.eventBus.emit("nodeAdded", node);
|
||||
}
|
||||
|
||||
private graphOnNodeRemoved(node: LGraphNode) {
|
||||
console.log("Removed", node);
|
||||
console.debug("Removed", node);
|
||||
this.eventBus.emit("nodeRemoved", node);
|
||||
}
|
||||
|
||||
private graphOnNodeConnectionChange(kind: LConnectionKind, node: LGraphNode, slot: INodeSlot, targetNode: LGraphNode, targetSlot: INodeSlot) {
|
||||
console.log("ConnectionChange", node);
|
||||
console.debug("ConnectionChange", node);
|
||||
this.eventBus.emit("nodeConnectionChanged", kind, node, slot, targetNode, targetSlot);
|
||||
}
|
||||
|
||||
private canvasOnClear() {
|
||||
console.log("CanvasClear");
|
||||
console.debug("CanvasClear");
|
||||
this.eventBus.emit("cleared");
|
||||
}
|
||||
|
||||
@@ -306,11 +306,13 @@ export default class ComfyApp {
|
||||
}
|
||||
|
||||
private showDropZone() {
|
||||
this.dropZone.style.display = "block";
|
||||
if (this.dropZone)
|
||||
this.dropZone.style.display = "block";
|
||||
}
|
||||
|
||||
private hideDropZone() {
|
||||
this.dropZone.style.display = "none";
|
||||
if (this.dropZone)
|
||||
this.dropZone.style.display = "none";
|
||||
}
|
||||
|
||||
private allowDrag(event: DragEvent) {
|
||||
@@ -334,10 +336,15 @@ export default class ComfyApp {
|
||||
private addDropHandler() {
|
||||
this.dropZone = document.getElementById("dropzone");
|
||||
|
||||
window.addEventListener('dragenter', this.allowDrag.bind(this));
|
||||
this.dropZone.addEventListener('dragover', this.allowDrag.bind(this));
|
||||
this.dropZone.addEventListener('dragleave', this.hideDropZone.bind(this));
|
||||
this.dropZone.addEventListener('drop', this.handleDrop.bind(this));
|
||||
if (this.dropZone) {
|
||||
window.addEventListener('dragenter', this.allowDrag.bind(this));
|
||||
this.dropZone.addEventListener('dragover', this.allowDrag.bind(this));
|
||||
this.dropZone.addEventListener('dragleave', this.hideDropZone.bind(this));
|
||||
this.dropZone.addEventListener('drop', this.handleDrop.bind(this));
|
||||
}
|
||||
else {
|
||||
console.warn("No dropzone detected (probably on mobile).")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,7 @@ export type QueueItem = {
|
||||
}
|
||||
|
||||
type QueueStateOps = {
|
||||
statusUpdated: (status: ComfyAPIQueueStatus) => void,
|
||||
statusUpdated: (status: ComfyAPIQueueStatus | null) => void,
|
||||
executingUpdated: (runningNodeId: string | null) => void,
|
||||
progressUpdated: (progress: Progress | null) => void
|
||||
}
|
||||
@@ -21,9 +21,10 @@ type WritableQueueStateStore = Writable<QueueState> & QueueStateOps;
|
||||
|
||||
const store: Writable<QueueState> = writable({ queueRemaining: null, runningNodeId: null, progress: null })
|
||||
|
||||
function statusUpdated(status: ComfyAPIQueueStatus) {
|
||||
function statusUpdated(status: ComfyAPIQueueStatus | null) {
|
||||
store.update((s) => {
|
||||
s.queueRemaining = status.exec_info.queue_remaining;
|
||||
if (status !== null)
|
||||
s.queueRemaining = status.exec_info.queue_remaining;
|
||||
return s
|
||||
})
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ function nodeAdded(node: LGraphNode) {
|
||||
}
|
||||
}
|
||||
|
||||
console.log("NODEADDED", state)
|
||||
console.debug("NODEADDED", state)
|
||||
|
||||
store.set(state);
|
||||
}
|
||||
|
||||
43
src/mobile/routes/graph.svelte
Normal file
43
src/mobile/routes/graph.svelte
Normal file
@@ -0,0 +1,43 @@
|
||||
<script lang="ts">
|
||||
import { Page, Navbar, Block, Tab, BlockHeader, Segmented, Button, Icon } from 'framework7-svelte';
|
||||
import { LGraphCanvas } from "@litegraph-ts/core";
|
||||
import ComfyApp, { type SerializedAppState } from "$lib/components/ComfyApp";
|
||||
import ComfyGraphCanvas from "$lib/ComfyGraphCanvas";
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
export let app: ComfyApp = undefined;
|
||||
let lCanvas: LGraphCanvas | null = null;
|
||||
let canvasEl: HTMLCanvasElement | null = null;
|
||||
|
||||
function resizeCanvas() {
|
||||
canvasEl.width = canvasEl.parentElement.offsetWidth;
|
||||
canvasEl.height = canvasEl.parentElement.offsetHeight;
|
||||
canvasEl.style.width = ""
|
||||
canvasEl.style.height = ""
|
||||
lCanvas.draw(true, true);
|
||||
}
|
||||
|
||||
$: if (app && canvasEl) {
|
||||
if (!lCanvas) {
|
||||
lCanvas = new ComfyGraphCanvas(app, canvasEl);
|
||||
lCanvas.allow_interaction = false;
|
||||
}
|
||||
resizeCanvas();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<Page>
|
||||
<Navbar title="Node Graph" backLink="Back" />
|
||||
<div class="canvas-wrapper pane-wrapper">
|
||||
<canvas bind:this={canvasEl} id="extra-canvas" />
|
||||
</div>
|
||||
</Page>
|
||||
|
||||
<style lang="scss">
|
||||
.canvas-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #333;
|
||||
}
|
||||
</style>
|
||||
90
src/mobile/routes/home.svelte
Normal file
90
src/mobile/routes/home.svelte
Normal file
@@ -0,0 +1,90 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { get } from "svelte/store";
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes';
|
||||
import { Button } from "@gradio/button";
|
||||
import ComfyApp, { type SerializedAppState } from "$lib/components/ComfyApp";
|
||||
import { Checkbox } from "@gradio/form"
|
||||
import widgetState from "$lib/stores/widgetState";
|
||||
import nodeState from "$lib/stores/nodeState";
|
||||
import uiState from "$lib/stores/uiState";
|
||||
import { ImageViewer } from "$lib/ImageViewer";
|
||||
import { download } from "$lib/utils"
|
||||
|
||||
import { LGraph, LGraphNode } from "@litegraph-ts/core";
|
||||
import type { ComfyAPIStatus } from "$lib/api";
|
||||
import queueState from "$lib/stores/queueState";
|
||||
import { Page, Navbar, Link, BlockTitle, Block, List, ListItem } from "framework7-svelte"
|
||||
|
||||
let app: ComfyApp = undefined;
|
||||
|
||||
let serializedPaneOrder = {};
|
||||
|
||||
function serializeAppState(): SerializedAppState {
|
||||
const graph = app.lGraph;
|
||||
|
||||
const serializedGraph = graph.serialize()
|
||||
|
||||
return {
|
||||
createdBy: "ComfyBox",
|
||||
version: 1,
|
||||
workflow: serializedGraph,
|
||||
panes: serializedPaneOrder
|
||||
}
|
||||
}
|
||||
|
||||
function doAutosave(graph: LGraph): void {
|
||||
const savedWorkflow = serializeAppState();
|
||||
localStorage.setItem("workflow", JSON.stringify(savedWorkflow))
|
||||
}
|
||||
|
||||
function doRestore(workflow: SerializedAppState) {
|
||||
serializedPaneOrder = workflow.panes;
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
app = new ComfyApp();
|
||||
|
||||
// TODO dedup
|
||||
app.eventBus.on("nodeAdded", nodeState.nodeAdded);
|
||||
app.eventBus.on("nodeRemoved", nodeState.nodeRemoved);
|
||||
app.eventBus.on("configured", nodeState.configureFinished);
|
||||
app.eventBus.on("cleared", nodeState.clear);
|
||||
|
||||
app.eventBus.on("nodeAdded", widgetState.nodeAdded);
|
||||
app.eventBus.on("nodeRemoved", widgetState.nodeRemoved);
|
||||
app.eventBus.on("configured", widgetState.configureFinished);
|
||||
app.eventBus.on("cleared", widgetState.clear);
|
||||
app.eventBus.on("autosave", doAutosave);
|
||||
app.eventBus.on("restored", doRestore);
|
||||
|
||||
app.api.addEventListener("status", (ev: CustomEvent) => {
|
||||
queueState.statusUpdated(ev.detail as ComfyAPIStatus);
|
||||
});
|
||||
|
||||
await app.setup();
|
||||
(window as any).app = app;
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<Page name="home">
|
||||
<Navbar title="Home Page" />
|
||||
|
||||
<BlockTitle>Yo</BlockTitle>
|
||||
<Block>
|
||||
<div>{app} Nodes</div>
|
||||
</Block>
|
||||
|
||||
<List strong inset dividersIos class="components-list searchbar-found">
|
||||
<ListItem link="/accordion/" title="Accordion">
|
||||
<i class="icon icon-f7" slot="media" />
|
||||
</ListItem>
|
||||
<ListItem link="/action-sheet/" title="Action Sheet">
|
||||
<i class="icon icon-f7" slot="media" />
|
||||
</ListItem>
|
||||
<ListItem link="/graph/" title="Show Node Graph" routeProps={{ app: app }}>
|
||||
<i class="icon icon-f7" slot="media" />
|
||||
</ListItem>
|
||||
</List>
|
||||
</Page>
|
||||
Reference in New Issue
Block a user