Skip to content

Commit

Permalink
Adding keyboard setting with dbus
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/components/localization/InstallationLanguage.jsx

# Conflicts:
#	src/components/localization/InstallationLanguage.jsx
#	src/components/localization/InstallationLanguage.scss
  • Loading branch information
adamkankovsky committed Jan 14, 2025
1 parent 6b8450b commit 24e4350
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 18 deletions.
16 changes: 14 additions & 2 deletions src/actions/localization-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
getLanguageData,
getLanguages,
getLocaleData,
getLocaleKeyboardLayouts,
getLocales,
} from "../apis/localization.js";

Expand Down Expand Up @@ -51,11 +52,11 @@ export const getLanguageDataAction = ({ language }) => {
export const getLanguageAction = () => {
return async (dispatch) => {
const language = await getLanguage();

return dispatch({
dispatch({
payload: { language },
type: "GET_LANGUAGE"
});
return language;
};
};

Expand All @@ -69,3 +70,14 @@ export const getCommonLocalesAction = () => {
});
};
};

export const getKeyboardLayoutsAction = ({ language }) => {
return async (dispatch) => {
const keyboardLayouts = await getLocaleKeyboardLayouts(language);

dispatch({
payload: { keyboardLayouts },
type: "GET_KEYBOARD_LAYOUTS"
});
};
};
30 changes: 26 additions & 4 deletions src/apis/localization.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import cockpit from "cockpit";

import { getLanguageAction, getLanguagesAction } from "../actions/localization-actions.js";
import { getKeyboardLayoutsAction, getLanguageAction, getLanguagesAction } from "../actions/localization-actions.js";

import { debug } from "../helpers/log.js";
import { _callClient, _getProperty, _setProperty } from "./helpers.js";
Expand Down Expand Up @@ -62,18 +62,24 @@ export class LocalizationClient {
}

async initData () {
await this.dispatch(getLanguageAction());
const language = await this.dispatch(getLanguageAction());
await this.dispatch(getLanguagesAction());
if (language) {
await this.dispatch(getKeyboardLayoutsAction({ language }));
}
}

startEventMonitor () {
this.client.subscribe(
{ },
(path, iface, signal, args) => {
async (path, iface, signal, args) => {
switch (signal) {
case "PropertiesChanged":
if (args[0] === INTERFACE_NAME && Object.hasOwn(args[1], "Language")) {
this.dispatch(getLanguageAction());
const language = await this.dispatch(getLanguageAction());
if (language) {
await this.dispatch(getKeyboardLayoutsAction({ language }));
}
} else {
debug(`Unhandled signal on ${path}: ${iface}.${signal}`, JSON.stringify(args));
}
Expand Down Expand Up @@ -139,3 +145,19 @@ export const getLocaleData = ({ locale }) => {
export const setLanguage = ({ lang }) => {
return setProperty("Language", cockpit.variant("s", lang));
};

/**
* @param {string} layout Keyboard layout id
*/
export const setKeyboardLayout = ({ layout }) => {
return setProperty("SetCompositorSelectedLayout", cockpit.variant("s", layout));
};

/**
* @param {string} lang Locale id
*
* @returns {Promise} Resolves a list of locale keyboards
*/
export const getLocaleKeyboardLayouts = ({ locale }) => {
return callClient("GetLocaleKeyboardLayouts", [locale]);
};
33 changes: 24 additions & 9 deletions src/components/localization/InstallationLanguage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import cockpit from "cockpit";

import React, { useContext, useEffect } from "react";
import React, { useContext, useEffect, useState } from "react";
import {
Button,
Form,
Expand All @@ -36,6 +36,7 @@ import { SearchIcon, TimesIcon } from "@patternfly/react-icons";

import { setLocale } from "../../apis/boss.js";
import {
setKeyboardLayout,
setLanguage,
} from "../../apis/localization.js";

Expand All @@ -47,6 +48,8 @@ import {

import { LanguageContext } from "../../contexts/Common.jsx";

import { KeyboardSelector } from "./Keyboard.jsx";

import "./InstallationLanguage.scss";

const _ = cockpit.gettext;
Expand Down Expand Up @@ -295,21 +298,23 @@ class LanguageSelector extends React.Component {
}

const InstallationLanguage = ({ setIsFormValid, setStepNotification }) => {
const { commonLocales, language, languages } = useContext(LanguageContext);
const { commonLocales, keyboardLayouts, language, languages } = useContext(LanguageContext);
const [keyboard, setKeyboard] = useState("");

const handleSetKeyboard = (value) => {
setKeyboard(value);
setKeyboardLayout(value);
};

useEffect(() => {
setIsFormValid(language !== "");
}, [language, setIsFormValid]);

return (
<>
<Title
headingLevel="h3"
>
{_("Choose a language")}
</Title>
<Form>
<FormGroup>
<Title headingLevel="h3">{_("Choose Language and Keyboard")}</Title>
<Form className="anaconda-screen-selectors-container">
<FormGroup label={_("Language")}>
<LanguageSelector
id="language-selector"
languages={languages}
Expand All @@ -320,6 +325,16 @@ const InstallationLanguage = ({ setIsFormValid, setStepNotification }) => {
reRenderApp={setLanguage}
/>
</FormGroup>

<FormGroup label={_("Keyboard")} fieldId={`${SCREEN_ID}-keyboard-layouts`}>
<KeyboardSelector
id="keyboard-selector"
idPrefix={SCREEN_ID}
keyboards={keyboardLayouts}
selectedKeyboard={keyboard}
setKeyboard={handleSetKeyboard}
/>
</FormGroup>
</Form>
</>
);
Expand Down
27 changes: 24 additions & 3 deletions src/components/localization/InstallationLanguage.scss
Original file line number Diff line number Diff line change
@@ -1,13 +1,34 @@
.anaconda-screen-language-menu.pf-v5-c-menu.pf-m-scrollable {
.anaconda-screen-selectors-container {
display: grid;
grid-template-columns: 150px 1fr;
row-gap: var(--pf-v5-global--spacer--lg);
column-gap: var(--pf-v5-global--spacer--md);
}

.anaconda-screen-selectors-container .pf-v5-c-form__group {
display: contents;
}

.anaconda-screen-selectors-container label {
grid-column: 1;
font-weight: 600;
text-align: left;
}

.anaconda-screen-selectors-container .pf-v5-c-form__group-control {
grid-column: 2;
max-width: 400px;
}

.anaconda-screen-language-menu.pf-v5-c-menu.pf-m-scrollable {
// heading: 84, footer: 44, content (about from header): 158, necessary padding underneath: 8px,
// keyboardSelector: 60
// 50px magic number
--pf-v5-c-menu__content--MaxHeight: calc(100vh - 84px - 44px - 158px - 8px - 50px);
--pf-v5-c-menu__content--MaxHeight: calc(100vh - 84px - 44px - 158px - 8px - 60px - 50px);
}

.anaconda-screen-language-search {
margin-bottom: var(--pf-v5-global--spacer--sm);
max-width: 400px;
}

.anaconda-screen-language-menu {
Expand Down
69 changes: 69 additions & 0 deletions src/components/localization/Keyboard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright (C) 2024 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with This program; If not, see <http://www.gnu.org/licenses/>.
*/

import cockpit from "cockpit";

import React, { useEffect } from "react";
import { FormSelect, FormSelectOption } from "@patternfly/react-core";

const _ = cockpit.gettext;

export const KeyboardSelector = ({ idPrefix, keyboards, selectedKeyboard, setKeyboard }) => {
useEffect(() => {
// Ensure the selected keyboard is valid or reset to the default layout
if (keyboards.length > 0) {
const selectedLayoutId = selectedKeyboard?.split(":")[0];
const isKeyboardValid = keyboards.some(
({ layoutId }) => layoutId === selectedLayoutId
);

// Reset to default if current selection is invalid
if (!isKeyboardValid) {
setKeyboard(keyboards[0].layoutId); // Default layout without variant
}
}
}, [keyboards, selectedKeyboard, setKeyboard]);

const handleChange = (event) => {
const { value } = event.target;
setKeyboard(value);
};

const selectedValue =
selectedKeyboard || (keyboards.length > 0 ? keyboards[0].layoutId : "");

return (
<FormSelect
id={`${idPrefix}-keyboard-layouts`}
onChange={handleChange}
value={selectedValue}
>
<FormSelectOption
key={keyboards[0]?.layoutId}
label={_("Default layout")}
value={keyboards[0]?.layoutId}
/>
{keyboards.map(({ description, layoutId, variantId }) => (
<FormSelectOption
key={`${layoutId}:${variantId || ""}`}
label={description}
value={`${layoutId}:${variantId || ""}`}
/>
))}
</FormSelect>
);
};
3 changes: 3 additions & 0 deletions src/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export const storageInitialState = {
/* Initial state for the localization store substate */
export const localizationInitialState = {
commonLocales: [],
keyboardLayouts: [],
language: "",
languages: {}
};
Expand Down Expand Up @@ -173,6 +174,8 @@ export const localizationReducer = (state = localizationInitialState, action) =>
return { ...state, commonLocales: action.payload.commonLocales };
} else if (action.type === "GET_LANGUAGE") {
return { ...state, language: action.payload.language };
} else if (action.type === "GET_KEYBOARD_LAYOUTS") {
return { ...state, keyboardLayouts: action.payload.keyboardLayouts };
} else {
return state;
}
Expand Down

0 comments on commit 24e4350

Please sign in to comment.