Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 33 additions & 25 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
import MainPage from "$/components/MainPage.svelte";
</script>

<MainPage />
<MainPage />
66 changes: 65 additions & 1 deletion src/components/LabelDesigner.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<script lang="ts">
import { get } from "svelte/store";
import { registerPlugin, Capacitor } from "@capacitor/core";
const PdfIntent = registerPlugin('PdfIntent');
import Dropdown from "bootstrap/js/dist/dropdown";
import * as fabric from "fabric";
import { onDestroy, onMount, tick } from "svelte";
Expand Down Expand Up @@ -349,6 +352,67 @@

window.addEventListener("hashchange", loadLabelFromUrl);

// --- PDF INTENT LOGIC START ---

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you extract this to function?

if (Capacitor.getPlatform() === 'android') {
const processPdfImage = async (base64Image: string) => {
try {
// 1. Clear the canvas
fabricCanvas!.clear();

// 2. Load the base64 string directly into a Fabric Image object
const img = await fabric.FabricImage.fromURL(base64Image);

const qt = get(appConfig).pdfQuickTransform;
if (qt) {
// Apply your saved Quick Transform!
img.set({
originX: qt.originX as fabric.TOriginX,
originY: qt.originY as fabric.TOriginY,
left: qt.left,
top: qt.top,
scaleX: qt.scaleX,
scaleY: qt.scaleY,
angle: qt.angle,
snapAngle: OBJECT_DEFAULTS.snapAngle
});
} else {
// Default: If nothing is saved, fit it neatly into the canvas
img.set({ ...OBJECT_DEFAULTS });
CanvasUtils.fitObjectIntoCanvas(
fabricCanvas!,
img,
OBJECT_DEFAULTS.left as number,
OBJECT_DEFAULTS.top as number
);
}

// 4. Add to canvas and update history
fabricCanvas!.add(img);
fabricCanvas!.setActiveObject(img);
undo.push(fabricCanvas!, labelProps);

// 5. Automatically open the Print Dialog
openPreviewAndPrint();
} catch (e) {
Toasts.error("Failed to load PDF to canvas: " + e);
}
};

// Listen for PDFs sent while app is already open in background
PdfIntent.addListener('onPdfReceived', (info: any) => {
if (info && info.image) processPdfImage(info.image);
});

// Check for PDFs sent when the app was completely closed (Cold Boot)
try {
const result = await PdfIntent.checkIntent();
if (result && result.image) processPdfImage(result.image);
} catch (e: any) {
Toasts.error("PDF Intent Error: " + (e.message || String(e)));
}
}
// --- PDF INTENT LOGIC END ---

undo.push(fabricCanvas, labelProps);

// force close dropdowns on touch devices
Expand Down Expand Up @@ -616,4 +680,4 @@
.canvas-wrapper canvas {
image-rendering: pixelated;
}
</style>
</style>
49 changes: 44 additions & 5 deletions src/components/PrinterConnector.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,43 @@
let connectionType = $state<ConnectionType>("bluetooth");
let featureSupport = $state<AvailableTransports>({ webBluetooth: false, webSerial: false, capacitorBle: false });

const onConnectClicked = async () => {
const toggleAutoConnect = (e: Event & { currentTarget: HTMLInputElement }) => {
const checked = e.currentTarget.checked;

automation.update(prev => {
const newState = { ...(prev || {}), autoConnect: checked };
if (checked) {
// Grab the reliable internal device ID from the connected client
const client = $printerClient as any;
const deviceId = client?.device?.deviceId || client?.deviceId || $printerInfo?.mac;
newState.autoConnectDeviceId = deviceId;
} else {
newState.autoConnectDeviceId = undefined;
}
return newState;
});
};

const onConnectClicked = async (isAutoConnect: boolean = false) => {
initClient(connectionType);
connectionState.set("connecting");

try {
if ($printerClient instanceof NiimbotCapacitorBleClient && $automation?.autoConnectDeviceId !== undefined) {
if (isAutoConnect && $printerClient instanceof NiimbotCapacitorBleClient && $automation?.autoConnectDeviceId !== undefined) {
// Background auto-connection on app startup
await $printerClient.connect({ deviceId: $automation.autoConnectDeviceId });
} else {
// Manual connection: ALWAYS open the scanner to prevent getting locked out
await $printerClient.connect();

// If auto-connect is enabled, refresh the saved ID with the one we just successfully scanned
if ($automation?.autoConnect && $printerClient instanceof NiimbotCapacitorBleClient) {
const client = $printerClient as any;
const deviceId = client?.device?.deviceId || client?.deviceId || $printerInfo?.mac;
if (deviceId) {
automation.update(prev => ({ ...prev, autoConnectDeviceId: deviceId }));
}
}
}
} catch (e) {
connectionState.set("disconnected");
Expand Down Expand Up @@ -110,7 +138,7 @@
}

if ($automation !== undefined && $automation.autoConnect && connectionType === "capacitor-ble") {
onConnectClicked();
onConnectClicked(true);
}
});
</script>
Expand All @@ -130,6 +158,17 @@
{/each}
</ul>
</div>

<!-- Toggle is now always visible -->
<div class="form-check form-switch mt-2 mb-2 px-3 border-bottom pb-2">
<input
class="form-check-input"
type="checkbox"
id="autoConnectSwitch"
checked={$automation?.autoConnect}
onchange={toggleAutoConnect} />
<label class="form-check-label" for="autoConnectSwitch">Auto-connect on launch</label>
</div>
{/if}

{#if $printerMeta}
Expand Down Expand Up @@ -279,7 +318,7 @@
class="btn btn-primary"
disabled={$connectionState === "connecting" ||
(!featureSupport.capacitorBle && !featureSupport.webBluetooth && !featureSupport.webSerial)}
onclick={onConnectClicked}>
onclick={() => onConnectClicked(false)}>
<MdIcon icon="power" />
</button>
{/if}
Expand All @@ -296,4 +335,4 @@
width: 100vw;
max-width: 300px;
}
</style>
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { appConfig } from "$/stores";
import MdIcon from "$/components/basic/MdIcon.svelte";
import ObjectPositionControls from "$/components/designer-controls/ObjectPositionControls.svelte";

import { Toasts } from "$/utils/toasts";

interface Props {
selectedObject: fabric.FabricObject;
Expand All @@ -14,6 +14,22 @@

let { selectedObject, editRevision, valueUpdated }: Props = $props();

const saveQuickTransform = () => {
appConfig.update((cfg) => ({
...cfg,
pdfQuickTransform: {
scaleX: selectedObject.scaleX ?? 1,
scaleY: selectedObject.scaleY ?? 1,
left: selectedObject.left ?? 0,
top: selectedObject.top ?? 0,
angle: selectedObject.angle ?? 0,
originX: selectedObject.originX,
originY: selectedObject.originY,
}
}));
Toasts.message("Saved as Quick Transform for incoming PDFs");
};

const putToCenterV = () => {
selectedObject.canvas!.centerObjectV(selectedObject);
valueUpdated();
Expand Down Expand Up @@ -114,10 +130,14 @@
</select>
</div>
</div>

<button class="btn btn-sm btn-outline-warning ms-1" onclick={saveQuickTransform} title="Save as PDF Quick Transform">
<MdIcon icon="save" /> Quick Transform
</button>
{/if}

<style>
.dropdown-menu.arrangement {
text-align: center;
}
</style>
</style>
10 changes: 9 additions & 1 deletion src/stores.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ export const csvData = writablePersisted<CsvParams>("csv_params", CsvParamsSchem

userFonts.subscribe(FileUtils.loadFonts);

export const automation = readable<AutomationProps | undefined>(
// src/stores.ts

// 1. Change `readable` to `writable`
export const automation = writable<AutomationProps | undefined>(
(() => {
try {
return LocalStoragePersistence.loadAutomation() ?? undefined;
Expand All @@ -63,6 +66,11 @@ export const automation = readable<AutomationProps | undefined>(
})(),
);

// 2. Automatically save to local storage whenever it changes
automation.subscribe((value) => {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is writablePersisted for this

LocalStoragePersistence.saveAutomation(value);
});

export const refreshRfidInfo = () => {
const client = get(printerClient);

Expand Down
Loading