diff --git a/package.json b/package.json index ec495f3c..7d240129 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "@tauri-apps/api": "^1.6.0", "@tauri-apps/cli": "^1.6.0", "@types/dom-view-transitions": "^1.0.6", + "@types/semver": "^7.7.0", "@types/w3c-web-serial": "^1.0.8", "@types/w3c-web-usb": "^1.0.10", "@types/wicg-file-system-access": "^2023.10.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3df1c60e..306557f5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -65,6 +65,9 @@ importers: '@types/dom-view-transitions': specifier: ^1.0.6 version: 1.0.6 + '@types/semver': + specifier: ^7.7.0 + version: 7.7.0 '@types/w3c-web-serial': specifier: ^1.0.8 version: 1.0.8 @@ -1488,6 +1491,9 @@ packages: '@types/retry@0.12.0': resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + '@types/semver@7.7.0': + resolution: {integrity: sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==} + '@types/sinonjs__fake-timers@8.1.1': resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==} @@ -5669,6 +5675,8 @@ snapshots: '@types/retry@0.12.0': {} + '@types/semver@7.7.0': {} + '@types/sinonjs__fake-timers@8.1.1': {} '@types/sizzle@2.3.8': {} diff --git a/src/i18n/de/index.ts b/src/i18n/de/index.ts index 2c9c515a..15fd1f17 100644 --- a/src/i18n/de/index.ts +++ b/src/i18n/de/index.ts @@ -21,7 +21,7 @@ const de = { AUTO_BACKUP: "Auto-backup", DISCLAIMER: "Das Backup in diesem Browser gespeichert und bleibt nur auf diesem Computer.", - DOWNLOAD: "Alles", + DOWNLOAD: "Komplettes Profil", RESTORE: "Wiederherstellen", }, modal: { diff --git a/src/i18n/en/index.ts b/src/i18n/en/index.ts index 83906923..1d23b879 100644 --- a/src/i18n/en/index.ts +++ b/src/i18n/en/index.ts @@ -17,7 +17,7 @@ const en = { AUTO_BACKUP: "Auto-backup", DISCLAIMER: "Whenever you connect this device to browser, a backup is made locally and kept only on your computer.", - DOWNLOAD: "Everything", + DOWNLOAD: "Full profile", RESTORE: "Restore", }, sync: { diff --git a/src/lib/backup/backup.ts b/src/lib/backup/backup.ts index 42687d2e..aaf6b65d 100644 --- a/src/lib/backup/backup.ts +++ b/src/lib/backup/backup.ts @@ -14,7 +14,7 @@ import { settings, } from "$lib/undo-redo.js"; import { get } from "svelte/store"; -import { serialPort } from "../serial/connection"; +import { activeProfile, serialPort } from "../serial/connection"; import { csvLayoutToJson, isCsvLayout } from "$lib/backup/compat/legacy-layout"; import { isCsvChords, csvChordsToJson } from "./compat/legacy-chords"; @@ -50,11 +50,9 @@ export function createLayoutBackup(): CharaLayoutFile { charaVersion: 1, type: "layout", device: get(serialPort)?.device, - layout: get(layout).map((it) => it.map((it) => it.action)) as [ - number[], - number[], - number[], - ], + layout: (get(layout)[get(activeProfile)]?.map((it) => + it.map((it) => it.action), + ) ?? []) as [number[], number[], number[]], }; } @@ -70,7 +68,7 @@ export function createSettingsBackup(): CharaSettingsFile { return { charaVersion: 1, type: "settings", - settings: get(settings).map((it) => it.value), + settings: get(settings)[get(activeProfile)]?.map((it) => it.value) ?? [], }; } @@ -97,9 +95,11 @@ export function restoreFromFile( const recent = file.history[0]; if (!recent) return; let backupDevice = recent[1].device; - if (backupDevice === "TWO") backupDevice = "ONE"; + if (backupDevice === "TWO" || backupDevice === "M4G") + backupDevice = "ONE"; let currentDevice = get(serialPort)?.device; - if (currentDevice === "TWO") currentDevice = "ONE"; + if (currentDevice === "TWO" || backupDevice === "M4G") + currentDevice = "ONE"; if (backupDevice !== currentDevice) { alert("Backup is incompatible with this device"); @@ -167,12 +167,13 @@ export function getChangesFromChordFile(file: CharaChordFile) { export function getChangesFromSettingsFile(file: CharaSettingsFile) { const changes: Change[] = []; for (const [id, value] of file.settings.entries()) { - const setting = get(settings)[id]; + const setting = get(settings)[get(activeProfile)]?.[id]; if (setting !== undefined && setting.value !== value) { changes.push({ type: ChangeType.Setting, id, setting: value, + profile: get(activeProfile), }); } } @@ -183,12 +184,13 @@ export function getChangesFromLayoutFile(file: CharaLayoutFile) { const changes: Change[] = []; for (const [layer, keys] of file.layout.entries()) { for (const [id, action] of keys.entries()) { - if (get(layout)[layer]?.[id]?.action !== action) { + if (get(layout)[get(activeProfile)]?.[layer]?.[id]?.action !== action) { changes.push({ type: ChangeType.Layout, layer, id, action, + profile: get(activeProfile), }); } } diff --git a/src/lib/components/layout/GenericLayout.svelte b/src/lib/components/layout/GenericLayout.svelte index f33a41d7..1d4b742e 100644 --- a/src/lib/components/layout/GenericLayout.svelte +++ b/src/lib/components/layout/GenericLayout.svelte @@ -8,17 +8,16 @@ import { dev } from "$app/environment"; import ActionSelector from "$lib/components/layout/ActionSelector.svelte"; import { get } from "svelte/store"; - import type { Writable } from "svelte/store"; import KeyboardKey from "$lib/components/layout/KeyboardKey.svelte"; import { getContext, mount, unmount } from "svelte"; import type { VisualLayoutConfig } from "./visual-layout.js"; import { changes, ChangeType, layout } from "$lib/undo-redo"; import { fly } from "svelte/transition"; import { expoOut } from "svelte/easing"; + import { activeLayer, activeProfile } from "$lib/serial/connection"; const { scale, margin, strokeWidth, fontSize, iconFontSize } = getContext("visual-layout-config"); - const activeLayer = getContext>("active-layer"); if (dev) { // you have absolutely no idea what a difference this makes for performance @@ -125,8 +124,10 @@ const keyInfo = layoutInfo.keys[index]; if (!keyInfo) return; const clickedGroup = groupParent.children.item(index) as SVGGElement; - const nextAction = get(layout)[get(activeLayer)]?.[keyInfo.id]; - const currentAction = get(deviceLayout)[get(activeLayer)]?.[keyInfo.id]; + const nextAction = + get(layout)[get(activeProfile)][get(activeLayer)]?.[keyInfo.id]; + const currentAction = + get(deviceLayout)[get(activeProfile)][get(activeLayer)]?.[keyInfo.id]; const component = mount(ActionSelector, { target: document.body, props: { diff --git a/src/lib/components/layout/KeyText.svelte b/src/lib/components/layout/KeyText.svelte index e489a7b2..02ca3059 100644 --- a/src/lib/components/layout/KeyText.svelte +++ b/src/lib/components/layout/KeyText.svelte @@ -1,5 +1,4 @@ {#each positions as position, layer} - {@const { action: actionId, isApplied } = $layout[layer]?.[key.id] ?? { + {@const { action: actionId, isApplied } = $layout[$activeProfile]?.[layer]?.[ + key.id + ] ?? { action: 0, isApplied: true, }} diff --git a/src/lib/components/layout/Layout.svelte b/src/lib/components/layout/Layout.svelte index dbe62742..5ca92f2c 100644 --- a/src/lib/components/layout/Layout.svelte +++ b/src/lib/components/layout/Layout.svelte @@ -2,21 +2,11 @@ import { deviceMeta, serialPort } from "$lib/serial/connection"; import { action } from "$lib/title"; import GenericLayout from "$lib/components/layout/GenericLayout.svelte"; - import { getContext } from "svelte"; - import type { Writable } from "svelte/store"; + import { activeProfile, activeLayer } from "$lib/serial/connection"; import type { VisualLayout } from "$lib/serialization/visual-layout"; import { fade, fly } from "svelte/transition"; import { restoreFromFile } from "$lib/backup/backup"; - let device = $derived($serialPort?.device); - const activeLayer = getContext>("active-layer"); - - const layers = [ - ["Numeric Layer", "123", 1], - ["Primary Layer", "abc", 0], - ["Function Layer", "function", 2], - ] as const; - const layouts = { ONE: () => import("$lib/assets/layouts/one.yml").then( @@ -46,19 +36,25 @@
- {#if device} - {#await layouts[device]() then visualLayout} + {#if $serialPort} + {#await layouts[$serialPort.device]() then visualLayout}
- {#each layers as [title, icon, value]} - - {/each} +
+ {#each Array.from({ length: $serialPort.layerCount }, (_, i) => i) as layer} + + {/each} +
{#if $deviceMeta?.factoryDefaults?.layout}
+
+ {#if $serialPort} + {#if $serialPort.profileCount > 1} + {#each Array.from({ length: $serialPort.profileCount }, (_, i) => i) as profile} + + {/each} + {/if} + {/if} +
+
{#if $canShare}