Skip to content

Commit

Permalink
Convert vuex/keycodes store to pinia (#1370)
Browse files Browse the repository at this point in the history
* chore: add some error handling to path

* chore: remove some lodash

 - partial
 - values
 - no need to spread default exports

* chore: remove more uses of lodash

* chore: wip - keycode store to pinia

* chore: remove more vuex keycodes store and replace

* chore: replace uses of vuex keycodes store

 - replace all uses of vuex keycodes store with pinia
 - fix ergo keyboard menu

* chore: simplify conditionals

* chore: simplify conditional using ?

* chore: add jsdoc and types

* chore: mark which properties are optional

Some properties for typedefs are actually optional.
Use the correct jsdoc syntax.
  • Loading branch information
yanfali authored Nov 7, 2024
1 parent 6c25d2b commit 76009c0
Show file tree
Hide file tree
Showing 13 changed files with 373 additions and 299 deletions.
15 changes: 11 additions & 4 deletions src/components/Keycodes.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,16 @@
</div>
</template>
<script>
import { mapState, mapGetters, mapMutations } from 'vuex';
import { mapState, mapMutations } from 'vuex';
import * as pinia from 'pinia';
import isUndefined from 'lodash/isUndefined';
import debounce from 'lodash/debounce';
import Keycode from '@/components/Keycode.vue';
import Space from '@/components/Space.vue';
import store from '@/store';

import { useKeycodesStore } from '../store/keycodes.js';

export default {
name: 'keycodes-component',
components: { Keycode, Space },
Expand All @@ -78,9 +81,13 @@ export default {
this.debouncedSetSearchFilter = debounce(this.setSearchFilter, 500);
},
computed: {
...mapGetters('keycodes', ['keycodes']),
...pinia.mapState(useKeycodesStore, [
'keycodes',
'searchFilter',
'searchCounters',
'active'
]),
...mapState('app', ['configuratorSettings']),
...mapState('keycodes', ['searchFilter', 'searchCounters', 'active']),
activeTab() {
return this.keycodesByGroup[this.active];
},
Expand Down Expand Up @@ -108,7 +115,7 @@ export default {
},
methods: {
...mapMutations('app', ['setMessage', 'stopListening', 'startListening']),
...mapMutations('keycodes', ['setSearchFilter', 'changeActive']),
...pinia.mapActions(useKeycodesStore, ['setSearchFilter', 'changeActive']),
getComponent(code) {
return isUndefined(code) ? Space : Keycode;
},
Expand Down
4 changes: 3 additions & 1 deletion src/components/VisualTesterKeymap.vue
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ import { mapState, mapGetters, mapMutations, mapActions } from 'vuex';
import BaseKeymap from '@/components/BaseKeymap.vue';
import TesterKey from '@/components/TesterKey.vue';
import { Howl } from 'howler';
import { useKeycodesStore } from '../store/keycodes';
export default {
name: 'VisualTesterKeymap',
Expand Down Expand Up @@ -185,7 +186,8 @@ export default {
},
async mounted() {
this.createKeyListeners();
this.$store.commit('keycodes/updateKeycodeNames');
const keycodesStore = useKeycodesStore();
keycodesStore.updateKeycodeNames();
await this.init();
this.setSize(this.calculateMax(this.layout));
},
Expand Down
2 changes: 0 additions & 2 deletions src/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import Vuex from 'vuex';
import { createPinia, PiniaVuePlugin } from 'pinia';
import app from './modules/app';
import keymap from './modules/keymap';
import keycodes from './modules/keycodes';
import tester from './modules/tester';

Vue.use(Vuex);
Expand All @@ -15,7 +14,6 @@ export default new Vuex.Store({
modules: {
app,
keymap,
keycodes,
tester
},
state: {},
Expand Down
218 changes: 218 additions & 0 deletions src/store/keycodes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
import { defineStore } from 'pinia';
import isUndefined from 'lodash/isUndefined';
import store from '@/store';
import keymapExtras from '@/i18n/keymap_extras';

import ansi from './modules/keycodes/ansi';
import iso_jis from './modules/keycodes/iso-jis';
import quantum from './modules/keycodes/quantum';
import settings from './modules/keycodes/kb-settings';
import media from './modules/keycodes/app-media-mouse';
import steno from './modules/keycodes/steno';

const keycodePickerTabLayout = {
ANSI_ISO: [...ansi, ...iso_jis],
ISO_ANSI: [...iso_jis, ...ansi],
special: [...quantum, ...settings, ...media]
};

/**
* Validates the os keyboard layout and if not valid returns a default of 'keymap_us'.
* @returns {string}
*/
function getOSKeyboardLayout() {
let osKeyboardLayout = store.getters['app/osKeyboardLayout'];
if (isUndefined(osKeyboardLayout) || !keymapExtras[osKeyboardLayout]) {
const fallbackOSKeyboardLayout = 'keymap_us';
console.log(
`The stored OS keyboard layout value (${osKeyboardLayout}) is not a valid value! Falling back to '${fallbackOSKeyboardLayout}'.`
);
store.commit('app/setOSKeyboardLayout', fallbackOSKeyboardLayout);
osKeyboardLayout = fallbackOSKeyboardLayout;
}
return osKeyboardLayout;
}

function isANSI() {
return keymapExtras[getOSKeyboardLayout()].isANSI;
}

/**
* Remap keycodes to their Locale equivalent for the OS layout.
* @param {Object} keycodeLUT
* @param {KeycodeDefinition|KeycodeLabel|WidthPlaceholder} keycodeObject
* @returns {KeycodeDefinition|WidthPlaceholder|KeycodeLabel}
*/
function toLocaleKeycode(keycodeLUT, keycodeObject) {
console.assert(!isUndefined(keycodeLUT));
if (!keycodeObject.name || !keycodeObject.code) {
// Not a KeycodeDefinition; return as is
return keycodeObject;
}
if (keycodeLUT[keycodeObject.code]) {
// Clone in a shallow manner the original keycodeObject object and
// override the name, title, and possibly other fields
return { ...keycodeObject, ...keycodeLUT[keycodeObject.code] };
} else {
return keycodeObject;
}
}

/**
* Used to dynamically generate the tab data for they keycode
* display. This UI is customized based on the OS keyboard layout
* selected.
*
* @param {string} osKeyboardLayout
* @param {boolean} isSteno
* @returns {Array.<KeycodeDefinition|KeycodeLabel|WidthPlaceholder}
*/
function generateKeycodes(osKeyboardLayout, isSteno = false) {
store.commit('app/setIso', !isANSI());
const keycodes = [
...(isANSI()
? keycodePickerTabLayout.ANSI_ISO
: keycodePickerTabLayout.ISO_ANSI),
...keycodePickerTabLayout.special,
...(isSteno ? steno : [])
];
const { keycodeLUT } = keymapExtras[getOSKeyboardLayout()];
return keycodes.map((keycodeObject) =>
toLocaleKeycode(keycodeLUT, keycodeObject)
);
}

/**
* Counts the number of potential matches in each keycode array.
* The keycode arrays represent the source data used to render the keycodes
* display. This count is used to give hints of matches per tab in the UI.
*
* @param {string} filter
* @param {Array.<KeycodeDefinition|KeycodeLabel|WidthPlaceholder>} collection of keycode objects
* @returns
*/
function countMatches(filter, collection) {
filter = filter.toUpperCase();
return collection.reduce((matchCount, { code, name, title }) => {
if (!isUndefined(code)) {
if (
code.includes(filter) ||
name?.toUpperCase().includes(filter) ||
title?.toUpperCase().includes(filter)
) {
matchCount += 1;
}
}
return matchCount;
}, 0);
}

/**
* Use Options style for now.
*/
export const useKeycodesStore = defineStore('keycodes', {
/**
*
* @returns {KeycodeStoreState}
*/
state: () => ({
keycodes: [
...keycodePickerTabLayout.ANSI_ISO,
...keycodePickerTabLayout.special
],
searchFilter: '',
searchCounters: {
ANSI: 0,
'ISO/JIS': 0,
Quantum: 0,
KeyboardSettings: 0,
AppMediaMouse: 0
},
steno: false,
active: 'ANSI'
}),
getters: {
lookupKeyPressCode: () => (searchTerm) =>
this.lookupKeycode(searchTerm, true),
lookupKeycode:
(state) =>
(searchTerm, isKeys = false) =>
state.keycodes.find(
({ code, keys }) =>
code === searchTerm || (isKeys && keys && keys === searchTerm)
)
},
actions: {
changeActive(newActive) {
this.active = newActive;
},
enableSteno() {
this.steno = true;
this.keycodes = generateKeycodes(getOSKeyboardLayout(), this.steno);
},
disableSteno() {
this.steno = false;
this.keycodes = generateKeycodes(getOSKeyboardLayout(), this.steno);
},
updateKeycodeNames() {
this.keycodes = generateKeycodes(getOSKeyboardLayout(), this.steno);
},
setSearchFilter(newVal) {
this.searchFilter = newVal;
if (this.searchFilter !== '') {
this.searchCounters = {
ANSI: countMatches(this.searchFilter, ansi),
'ISO/JIS': countMatches(this.searchFilter, iso_jis),
Quantum: countMatches(this.searchFilter, quantum),
KeyboardSettings: countMatches(this.searchFilter, settings),
AppMediaMouse: countMatches(this.searchFilter, media)
};
}
}
}
});

/**
* @typedef {Object} KeycodeLabel - used to label groups of keycodes
* @property {string} label - Label name
* @property {'label'} width - always the special indicator 'label'
* @property {boolean} [group] - group following keycodes under this
* @property {string} [icon] - font-awesome icon to display
* @property {string} [iconClass] - css class to apply
*/

/**
* @typedef {Object} WidthPlaceholder - used for spacing
* @property {number} width - width in Key Units * 1000. e.g. 1U = 1000, 2U = 2000.
*/

/**
* @typedef {Object} KeycodeDefinition - metadata about a keycode
* @property {string} name - UI display label for the keycode
* @property {string} code - QMK keycode defintion
* @property {string} [keys] - javascript keypress id. Used by keyboard handler
* @property {number} [width] - width in Key Units * 1000. e.g. 1U = 1000, 2U = 2000.
* @property {'text'|'layer'|'container'|'layer-container'} [type]
* @property {number} [layer]
* @property {string} [title] - help text for hover
*/

/**
* @typedef {{}
* & Record<'ISO/JIS', number>
* & Record<'ANSI', number>
* & Record<'Quantum', number>
* & Record<'KeyboardSettings', number>
* & Record<'AppMediaMouse', number>
* } SearchCounters
*
*/

/**
* @typedef {Object} KeycodeStoreState
* @property {Array.<KeycodeDefinition|KeycodeLabel|WidthPlaceholder>} keycodes - active keycodes
* @property {string} searchFilter - currently search filter
* @property {SearchCounters} searchCounters - count of matching keycodes per tab
* @property {boolean} steno - is steno tab active
* @property {'ANSI'|'ISO/JIS'|'AppMediaMouse'|'Quantum'|'Steno'|'KeyboardSettings'} active - active tab
*/
43 changes: 24 additions & 19 deletions src/store/modules/app/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,15 @@ import {
} from '@/store/modules/constants';
import { getPreferredLayout, getExclusionList } from '@/util';
import { localStorageSet, CONSTS } from '@/store/localStorage';
import { useKeycodesStore } from '../../keycodes.js';

const steno_keyboards = ['gergo', 'georgi'];
const steno_keyboards = new Set([
'gboards/gergo',
'gboards/georgi',
'stenokeyboards/the_uni/pro_micro',
'stenokeyboards/the_uni/rp_2040',
'stenokeyboards/the_uni/usb_c'
]);

const actions = {
/**
Expand Down Expand Up @@ -55,7 +62,10 @@ const actions = {
*/
async loadKeymapFromUrl(_, url) {
return fetch(url).then(async (r) => {
return await r.json();
if (r.ok) {
return await r.json();
}
console.error('Error fetching keymap from URL', r.statusText);
});
},
/**
Expand Down Expand Up @@ -86,13 +96,11 @@ const actions = {
commit('setLayout', nextLayout);

// enable and disable steno in keycode UI
const stenoCheck = steno_keyboards.reduce((_, keeb) => {
return { [keeb]: true };
}, {});
if (stenoCheck[keyboard]) {
this.commit('keycodes/enableSteno');
const keycodesStore = useKeycodesStore();
if (steno_keyboards.has(keyboard)) {
keycodesStore.enableSteno();
} else {
this.commit('keycodes/disableSteno');
keycodesStore.disableSteno();
}

if (clearKeymap) {
Expand Down Expand Up @@ -147,11 +155,12 @@ const actions = {
},
async changeOSKeyboardLayout({ dispatch, state, commit }, osLayout) {
commit('setOSKeyboardLayout', osLayout);
// Important to call keycodes/updateKeycodeNames *before* keymap/updateKeycodeNames.
this.commit('keycodes/updateKeycodeNames');
const keycodesStore = useKeycodesStore();

// Important to call keycodes/updatekeycodeNames *before* keymap/updateKeycodeNames.
keycodesStore.updateKeycodeNames();
this.commit('keymap/updateKeycodeNames');
this.commit(
'keycodes/changeActive',
keycodesStore.changeActive(
state.configuratorSettings.iso ? 'ISO/JIS' : 'ANSI'
);
this.commit(
Expand Down Expand Up @@ -230,10 +239,8 @@ const actions = {
async initKeypressListener({ commit }) {
const store = this;
const keypressListener = new keypress.Listener();
const conf = generateKeypressCombos(
store,
store.getters['keycodes/keycodes']
);
const keycodesStore = useKeycodesStore();
const conf = generateKeypressCombos(store, keycodesStore.keycodes);
keypressListener.register_many(conf);
keypressListener.simple_combo('ctrl shift i', () => {
if (!store.state.app.isPreview) {
Expand Down Expand Up @@ -269,6 +276,4 @@ const actions = {
}
};

export default {
...actions
};
export default actions;
4 changes: 1 addition & 3 deletions src/store/modules/app/getters.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,4 @@ const getters = {
}
};

export default {
...getters
};
export default getters;
Loading

0 comments on commit 76009c0

Please sign in to comment.