Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert vuex/keycodes store to pinia #1370

Merged
merged 10 commits into from
Nov 7, 2024
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
Loading