Skip to content

Commit

Permalink
feat: Ton of layer operations.
Browse files Browse the repository at this point in the history
  • Loading branch information
petejohanson committed Jul 12, 2024
1 parent 67bc71a commit 28f2625
Show file tree
Hide file tree
Showing 5 changed files with 255 additions and 22 deletions.
14 changes: 7 additions & 7 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 package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"@heroicons/react": "^2.1.4",
"@tauri-apps/api": "^2.0.0-beta.13",
"@tauri-apps/plugin-cli": "^2.0.0-beta.5",
"@zmkfirmware/zmk-studio-ts-client": "^0.0.9",
"@zmkfirmware/zmk-studio-ts-client": "^0.0.11",
"emittery": "^1.0.3",
"immer": "^10.1.1",
"react": "^18.2.0",
Expand Down
184 changes: 180 additions & 4 deletions src/keyboard/Keyboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import {
PhysicalLayout,
Keymap,
SetLayerBindingResponse,
SetLayerPropsResponse,
BehaviorBinding,
Layer,
} from "@zmkfirmware/zmk-studio-ts-client/keymap";
import type { GetBehaviorDetailsResponse } from "@zmkfirmware/zmk-studio-ts-client/behaviors";

Expand Down Expand Up @@ -71,7 +73,7 @@ function useBehaviors(): BehaviorMap {
let behavior_details = await call_rpc(connection, details_req);
let dets: GetBehaviorDetailsResponse | undefined =
behavior_details?.behaviors?.getBehaviorDetails;
console.log("Details", dets);

if (dets) {
behavior_map[dets.id] = dets;
}
Expand Down Expand Up @@ -165,6 +167,7 @@ export default function Keyboard() {
(keymap) => keymap?.keymap?.getKeymap,
true
);

const [selectedLayerIndex, setSelectedLayerIndex] = useState<number>(0);
const [selectedKeyPosition, setSelectedKeyPosition] = useState<
number | undefined
Expand Down Expand Up @@ -214,7 +217,6 @@ export default function Keyboard() {

let doUpdateBinding = useCallback(
(binding: BehaviorBinding) => {
console.log("Updatet the binding");
if (!keymap || selectedKeyPosition === undefined) {
console.error(
"Can't update binding without a selected key position and loaded keymap"
Expand All @@ -235,7 +237,10 @@ export default function Keyboard() {
keymap: { setLayerBinding: { layerId, keyPosition, binding } },
});

if (resp.keymap?.setLayerBinding === SetLayerBindingResponse.SUCCESS) {
if (
resp.keymap?.setLayerBinding ===
SetLayerBindingResponse.SET_LAYER_BINDING_RESP_OK
) {
setKeymap(
produce((draft: any) => {
draft.layers[layer].bindings[keyPosition] = binding;
Expand All @@ -252,7 +257,8 @@ export default function Keyboard() {
},
});
if (
resp.keymap?.setLayerBinding === SetLayerBindingResponse.SUCCESS
resp.keymap?.setLayerBinding ===
SetLayerBindingResponse.SET_LAYER_BINDING_RESP_OK
) {
setKeymap(
produce((draft: any) => {
Expand Down Expand Up @@ -285,13 +291,15 @@ export default function Keyboard() {
let resp = await call_rpc(conn, {
keymap: { moveLayer: { startIndex, destIndex } },
});

if (resp.keymap?.moveLayer?.ok) {
setKeymap(resp.keymap?.moveLayer?.ok);
setSelectedLayerIndex(destIndex);
} else {
console.error("Error moving", resp);
}
};

undoRedo?.(async () => {
await doMove(start, end);
return () => doMove(end, start);
Expand All @@ -300,6 +308,169 @@ export default function Keyboard() {
[undoRedo]
);

const addLayer = useCallback(() => {
async function doAdd(): Promise<number> {
if (!conn || !keymap) {
throw new Error("Not connected");
}

const resp = await call_rpc(conn, { keymap: { addLayer: {} } });

if (resp.keymap?.addLayer?.ok) {
const newSelection = keymap.layers.length;
setKeymap(
produce((draft: any) => {
draft.layers.push(resp.keymap!.addLayer!.ok!.layer);
draft.availableLayers--;
})
);

setSelectedLayerIndex(newSelection);

return resp.keymap.addLayer.ok.index;
} else {
console.error("Add error", resp.keymap?.addLayer?.err);
throw new Error("Failed to add layer:" + resp.keymap?.addLayer?.err);
}
}

async function doRemove(layerIndex: number) {
if (!conn) {
throw new Error("Not connected");
}

const resp = await call_rpc(conn, {
keymap: { removeLayer: { layerIndex } },
});

console.log(resp);
if (resp.keymap?.removeLayer?.ok) {
setKeymap(
produce((draft: any) => {
draft.layers.splice(layerIndex, 1);
draft.availableLayers++;
})
);
} else {
console.error("Remove error", resp.keymap?.removeLayer?.err);
throw new Error(
"Failed to remove layer:" + resp.keymap?.removeLayer?.err
);
}
}

undoRedo?.(async () => {
let index = await doAdd();
return () => doRemove(index);
});
}, [conn, undoRedo, keymap]);

const removeLayer = useCallback(() => {
async function doRemove(layerIndex: number): Promise<void> {
if (!conn || !keymap) {
throw new Error("Not connected");
}

const resp = await call_rpc(conn, {
keymap: { removeLayer: { layerIndex } },
});

if (resp.keymap?.removeLayer?.ok) {
if (layerIndex == keymap.layers.length - 1) {
setSelectedLayerIndex(layerIndex - 1);
}
setKeymap(
produce((draft: any) => {
draft.layers.splice(layerIndex, 1);
draft.availableLayers++;
})
);
} else {
console.error("Remove error", resp.keymap?.removeLayer?.err);
throw new Error(
"Failed to remove layer:" + resp.keymap?.removeLayer?.err
);
}
}

async function doRestore(layerId: number, atIndex: number) {
if (!conn) {
throw new Error("Not connected");
}

const resp = await call_rpc(conn, {
keymap: { restoreLayer: { layerId, atIndex } },
});

console.log(resp);
if (resp.keymap?.restoreLayer?.ok) {
setKeymap(
produce((draft: any) => {
draft.layers.splice(atIndex, 0, resp!.keymap!.restoreLayer!.ok);
draft.availableLayers--;
})
);
setSelectedLayerIndex(atIndex);
} else {
console.error("Remove error", resp.keymap?.restoreLayer?.err);
throw new Error(
"Failed to restore layer:" + resp.keymap?.restoreLayer?.err
);
}
}

if (!keymap) {
throw new Error("No keymap loaded");
}

let index = selectedLayerIndex;
let layerId = keymap.layers[index].id;
undoRedo?.(async () => {
await doRemove(index);
return () => doRestore(layerId, index);
});
}, [conn, undoRedo, selectedLayerIndex]);

const changeLayerName = useCallback(
(id: number, oldName: string, newName: string) => {
async function changeName(layerId: number, name: string) {
if (!conn) {
throw new Error("Not connected");
}

const resp = await call_rpc(conn, {
keymap: { setLayerProps: { layerId, name } },
});

if (
resp.keymap?.setLayerProps ==
SetLayerPropsResponse.SET_LAYER_PROPS_RESP_OK
) {
setKeymap(
produce((draft: any) => {
const layer_index = draft.layers.findIndex(
(l: Layer) => l.id == layerId
);
draft.layers[layer_index].name = name;
})
);
} else {
throw new Error(
"Failed to change layer name:" + resp.keymap?.setLayerProps
);
}
}

undoRedo?.(async () => {
await changeName(id, newName);
return async () => {
await changeName(id, oldName);
};
});
},
[conn, undoRedo, keymap]
);

return (
<div className="p-2 h-full w-full grid grid-cols-[auto_1fr] grid-rows-[4fr_1fr]">
<div className="flex flex-col gap-2">
Expand All @@ -320,6 +491,11 @@ export default function Keyboard() {
selectedLayerIndex={selectedLayerIndex}
onLayerClicked={setSelectedLayerIndex}
onLayerMoved={moveLayer}
canAdd={(keymap.availableLayers || 0) > 0}
canRemove={(keymap.layers?.length || 0) > 1}
onAddClicked={addLayer}
onRemoveClicked={removeLayer}
onLayerNameChanged={changeLayerName}
/>
</div>
)}
Expand Down
10 changes: 5 additions & 5 deletions src/keyboard/LayerPicker.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,18 @@ type Story = StoryObj<typeof meta>;
export const Named: Story = {
args: {
layers: [
{ name: "Base" },
{ name: "Num" },
{ name: "Nav" },
{ name: "Symbol" },
{ id: 1, name: "Base" },
{ id: 2, name: "Num" },
{ id: 3, name: "Nav" },
{ id: 4, name: "Symbol" },
],
selectedLayerIndex: 2,
},
};

export const NoNames: Story = {
args: {
layers: [{}, {}, {}],
layers: [{ id: 1 }, { id: 2 }, { id: 3 }],
selectedLayerIndex: 0,
},
};
Loading

0 comments on commit 28f2625

Please sign in to comment.