feat: combine save/apply

resolves #45
This commit is contained in:
2023-11-29 01:06:24 +01:00
parent 018c7a5eac
commit 3a6483aa61
7 changed files with 97 additions and 134 deletions

View File

@@ -1,4 +1,4 @@
import type {Translation} from "../i18n-types"
import type { Translation } from "../i18n-types"
const de = {
TITLE: "CharaChorder Gerätemanager",
@@ -11,9 +11,7 @@ const de = {
},
sync: {
TITLE_READ: "Neueste Änderungen werden abgerufen",
TITLE_WRITE: "Änderungen werden gebrannt",
DISCLAIMER_WRITE:
"Das Brennen von Änderungen ist nur für Layouts und Einstellungen erforderlich wenn diese Neustarts überdauern sollen. Bei Akkorden passiert das brennen automatisch beim anwenden.",
TITLE_WRITE: "Änderungen werden gespeichert",
},
backup: {
TITLE: "Sicherungskopie",

View File

@@ -1,4 +1,4 @@
import type {BaseTranslation} from "../i18n-types"
import type { BaseTranslation } from "../i18n-types"
const en = {
TITLE: "CharaChorder Device Manager",
@@ -18,9 +18,7 @@ const en = {
},
sync: {
TITLE_READ: "Reading latest changes",
TITLE_WRITE: "Burning changes to device",
DISCLAIMER_WRITE:
"Burning is only necessary if you want your layout or settings to persist across reboots. Chords always persist automatically on apply.",
TITLE_WRITE: "Saving changes to device",
},
modal: {
CLOSE: "Close",

View File

@@ -0,0 +1,26 @@
e + b + a,babe
e + c + b,because
f + e + c + a,face
h + e + c + a,each
i + d + ',I'd
i + g + b,big
i + g + e,give
k + b + a,back
k + e + a,take
l + e + a,late
l + e + d + a,lead
l + f + e,feel
l + g + e + a,large
l + h + e,help
l + i + a,Lia
l + i + f,fill
l + i + f + e,life
l + i + g + b + a,gitlab
l + k + i + e,like
m + e + a,make
m + i + ',I'm
n + c + a,can
n + d + a,and
n + e + b,been
n + e + b + a,enable
n + e + d,end
1 e + b + a babe
2 e + c + b because
3 f + e + c + a face
4 h + e + c + a each
5 i + d + ' I'd
6 i + g + b big
7 i + g + e give
8 k + b + a back
9 k + e + a take
10 l + e + a late
11 l + e + d + a lead
12 l + f + e feel
13 l + g + e + a large
14 l + h + e help
15 l + i + a Lia
16 l + i + f fill
17 l + i + f + e life
18 l + i + g + b + a gitlab
19 l + k + i + e like
20 m + e + a make
21 m + i + ' I'm
22 n + c + a can
23 n + d + a and
24 n + e + b been
25 n + e + b + a enable
26 n + e + d end

View File

@@ -0,0 +1,26 @@
e + b + a,babe
e + c + b,because
f + e + c + a,face
h + e + c + a,each
i + d + ',I'd
i + g + b,big
i + g + e,give
k + b + a,back
k + e + a,take
l + e + a,late
l + e + d + a,lead
l + f + e,feel
l + g + e + a,large
l + h + e,help
l + i + a,Lia
l + i + f,fill
l + i + f + e,life
l + i + g + b + a,gitlab
l + k + i + e,like
m + e + a,make
m + i + ',I'm
n + c + a,can
n + d + a,and
n + e + b,been
n + e + b + a,enable
n + e + d,end

View File

@@ -0,0 +1,21 @@
import { KEYMAP_IDS } from "$lib/serial/keymap-codes"
import type { CharaChordFile } from "$lib/share/chara-file"
export function csvChordsToJson(csv: string): CharaChordFile {
return {
charaVersion: 1,
type: 'chords',
chords: csv.split('\n').map(line => {
const [input, output] = line.split(',', 2)
return [
input.split('+').map(it => KEYMAP_IDS.get(it.trim())?.code ?? 0),
output.split('').map(it => KEYMAP_IDS.get(it.trim())?.code ?? 0),
]
})
}
}
export function isCsvLayout(csv: string): boolean {
return /^((\s*\w+\s*+?),\s*\w+\n?)+$/.test(csv)
}

View File

@@ -2,7 +2,7 @@
import LL from "../i18n/i18n-svelte"
import {changes, ChangeType, chords, layout, overlay, settings} from "$lib/undo-redo"
import type {Change} from "$lib/undo-redo"
import {fly} from "svelte/transition"
import {fly, slide} from "svelte/transition"
import {action} from "$lib/title"
import {
deviceChords,
@@ -34,10 +34,9 @@
}
let redoQueue: Change[] = []
async function apply() {
async function save() {
const port = $serialPort
if (!port) return
$syncStatus = "uploading"
for (const [id, {actions, phrase}] of $overlay.chords) {
@@ -79,21 +78,7 @@
await port.setSetting(id, setting)
}
$deviceLayout = $layout.map(layer => layer.map<number>(({action}) => action)) as [
number[],
number[],
number[],
]
$deviceChords = $chords
.map(({actions, phrase}) => ({actions, phrase}))
.filter(({phrase}) => phrase.length > 1)
$deviceSettings = $settings.map(({value}) => value)
$changes = []
$syncStatus = "done"
}
async function flashChanges() {
$syncStatus = "uploading"
// Yes, this is a completely arbitrary and unnecessary delay.
// The only purpose of it is to create a sense of weight,
// aka make it more "energy intensive" to click.
@@ -101,7 +86,7 @@
// would be if they click it every time they change a setting.
// Because of that, we don't need to show a fearmongering message such as
// "Your device will break after you click this 10,000 times!"
const virtualWriteTime = 6000
const virtualWriteTime = 1000
const startStamp = performance.now()
await new Promise<void>(resolve => {
function animate() {
@@ -118,83 +103,22 @@
}
requestAnimationFrame(animate)
})
if ($serialPort) {
await $serialPort.commit()
$changes = []
}
await port.commit()
$deviceLayout = $layout.map(layer => layer.map<number>(({action}) => action)) as [
number[],
number[],
number[],
]
$deviceChords = $chords
.map(({actions, phrase}) => ({actions, phrase}))
.filter(({phrase}) => phrase.length > 1)
$deviceSettings = $settings.map(({value}) => value)
$changes = []
$syncStatus = "done"
}
</script>
<!-- <svg viewBox="0 0 36 36" style="width: 48px">
<defs>
<rect
id="mouth"
x="13"
y="13"
width="512"
height="10"
rx="5"
style="transform-origin: center; animation-direction: alternate-reverse"
>
<animateTransform
attributeName="transform"
attributeType="XML"
type="scale"
values="1; 0.25; 1"
keyTimes="0; 0.33; 1"
dur="0.4"
repeatCount="indefinite"
/>
</rect>
<mask id="inner-mask">
<rect x="0" y="0" width="36" height="36" />
<use fill="white" href="#mouth" />
</mask>
<mask id="clip">
<rect x="0" y="0" width="36" height="36" fill="white" />
<use fill="black" href="#mouth" />
</mask>
</defs>
<g mask="url(#clip)" style="transform-origin: center">
<animateTransform
attributeName="transform"
attributeType="XML"
type="scale"
values="1 1;0.9 0.8; 1 1"
keyTimes="0; 0.33; 1"
dur="0.4"
repeatCount="indefinite"
/>
<circle cx="18" cy="18" r="14" stroke="currentcolor" fill="none" stroke-width="5" />
<circle cx="18" cy="18" r="10" fill="currentcolor" stroke-width="6" />
</g>
<g mask="url(#inner-mask)">
<text
mask="url(#inner-mask)"
x="18"
y="17.2"
fill="currentcolor"
text-anchor="start"
dominant-baseline="central"
font-size="8"
font-weight="bold"
>
<animateTransform
attributeName="transform"
attributeType="XML"
type="translate"
from="0"
to="-76.8"
dur="1.6"
repeatCount="indefinite"
/>
c&nbsp;&nbsp;&nbsp;c&nbsp;&nbsp;&nbsp;o&nbsp;&nbsp;&nbsp;s&nbsp;&nbsp;&nbsp;c&nbsp;&nbsp;&nbsp;c&nbsp;&nbsp;&nbsp;o&nbsp;&nbsp;&nbsp;s
</text>
</g>
</svg> -->
<button
use:action={{title: $LL.saveActions.UNDO(), shortcut: "ctrl+z"}}
class="icon"
@@ -207,46 +131,17 @@
disabled={redoQueue.length === 0}
on:click={redo}>redo</button
>
<div class="separator" />
<button
use:action={{title: $LL.saveActions.SAVE(), shortcut: "ctrl+shift+s"}}
on:click={flashChanges}
class="icon">save</button
>
{#if $changes.length !== 0}
<div transition:slide class="separator" />
<button
class="click-me"
transition:fly={{x: 8}}
on:click={apply}
use:action={{
title: $LL.changes.TITLE(),
shortcut: "ctrl+s",
}}><span class="icon">bolt</span>{$LL.saveActions.APPLY()}</button
transition:fly={{x: 10}}
use:action={{title: $LL.saveActions.SAVE(), shortcut: "ctrl+shift+s"}}
on:click={save}
class="icon">save</button
>
{/if}
<style lang="scss">
.click-me {
display: flex;
align-items: center;
justify-content: center;
height: fit-content;
margin-inline: 8px;
padding-block: 2px;
padding-inline-start: 4px;
padding-inline-end: 8px;
font-family: inherit;
font-weight: bold;
color: var(--md-sys-color-primary);
border: 2px solid var(--md-sys-color-primary);
border-radius: 18px;
outline: 2px dashed var(--md-sys-color-primary);
outline-offset: 2px;
}
.separator {
width: 1px;
height: 24px;

View File

@@ -30,7 +30,6 @@
<h2>{$LL.sync.TITLE_READ()}</h2>
{:else}
<h2>{$LL.sync.TITLE_WRITE()}</h2>
<p>{$LL.sync.DISCLAIMER_WRITE()}</p>
{/if}
<progress max={$syncProgress?.max ?? 1} value={$syncProgress?.current ?? 1}></progress>
</dialog>