From a7d094bbcb176d96f8dbb24f529c26ba0f16cd08 Mon Sep 17 00:00:00 2001 From: Sakamoto Shiina <68018796+ShiinaSakamoto@users.noreply.github.com> Date: Thu, 12 Dec 2024 16:16:40 +0900 Subject: [PATCH] [Update] Main Page: Add UI, multi language. --- .../main_page/main_section/MainSection.jsx | 43 ++++++++++++-- .../language_selector/LanguageSelector.jsx | 23 +++----- .../LanguageSelectorTopBar.jsx | 1 + .../language_settings/LanguageSettings.jsx | 54 +++--------------- .../LanguageSettings.module.scss | 8 +++ .../AddRemoveTargetLanguageButtons.jsx | 34 +++++++++++ ...AddRemoveTargetLanguageButtons.module.scss | 32 +++++++++++ .../LanguageSelectorOpenButton.jsx | 57 ++++++++++++++++--- src-ui/assets/add.svg | 1 + src-ui/assets/remove.svg | 1 + src-ui/logics/main/useLanguageSettings.js | 33 +++++++++-- src-ui/store.js | 4 +- 12 files changed, 210 insertions(+), 81 deletions(-) create mode 100644 src-ui/app/main_page/sidebar_section/language_settings/add_remove_target_language_buttons/AddRemoveTargetLanguageButtons.jsx create mode 100644 src-ui/app/main_page/sidebar_section/language_settings/add_remove_target_language_buttons/AddRemoveTargetLanguageButtons.module.scss create mode 100644 src-ui/assets/add.svg create mode 100644 src-ui/assets/remove.svg diff --git a/src-ui/app/main_page/main_section/MainSection.jsx b/src-ui/app/main_page/main_section/MainSection.jsx index a61df63d..faf910bd 100644 --- a/src-ui/app/main_page/main_section/MainSection.jsx +++ b/src-ui/app/main_page/main_section/MainSection.jsx @@ -1,3 +1,4 @@ +import { useTranslation } from "react-i18next"; import styles from "./MainSection.module.scss"; import { TopBar } from "./top_bar/TopBar"; @@ -6,6 +7,7 @@ import { LanguageSelector } from "./language_selector/LanguageSelector"; import { useStore_IsOpenedLanguageSelector } from "@store"; import { useLanguageSettings } from "@logics_main"; +import { useEffect } from "react"; export const MainSection = () => { @@ -20,33 +22,62 @@ export const MainSection = () => { const HandleLanguageSelector = () => { + const { t } = useTranslation(); const { currentIsOpenedLanguageSelector, updateIsOpenedLanguageSelector } = useStore_IsOpenedLanguageSelector(); const { + currentSelectedPresetTabNumber, currentSelectedYourLanguages, setSelectedYourLanguages, currentSelectedTargetLanguages, setSelectedTargetLanguages, } = useLanguageSettings(); + useEffect(() => { + updateIsOpenedLanguageSelector({ + your_language: false, + target_language: false, + target_key: "1" + }); + + }, [currentSelectedPresetTabNumber.data, currentSelectedYourLanguages.data, currentSelectedTargetLanguages.data]); + + const getTitle = (target_selector_key) => { + if (target_selector_key === "your_language") return t("main_page.language_selector.title_your_language"); + if (target_selector_key === "target_language") { + if (currentSelectedTargetLanguages.data[currentSelectedPresetTabNumber.data]["2"].enable === false) return t("main_page.language_selector.title_target_language"); + return `${t("main_page.language_selector.title_target_language")} (${currentIsOpenedLanguageSelector.data.target_key})`; + } + }; + + + if (currentIsOpenedLanguageSelector.data.your_language === true) { const onclickFunction_YourLanguage = (payload) => { - updateIsOpenedLanguageSelector({ your_language: false, target_language: false }); - setSelectedYourLanguages(payload); + updateIsOpenedLanguageSelector({ your_language: false, target_language: false, target_key: currentIsOpenedLanguageSelector.data.target_key }); + setSelectedYourLanguages({ + ...payload, + target_key: currentIsOpenedLanguageSelector.data.target_key, + }); }; + const title = getTitle("your_language"); return ( ); } else if (currentIsOpenedLanguageSelector.data.target_language === true) { const onclickFunction_TargetLanguage = (payload) => { - updateIsOpenedLanguageSelector({ your_language: false, target_language: false }); - setSelectedTargetLanguages(payload); + updateIsOpenedLanguageSelector({ your_language: false, target_language: false, target_key: currentIsOpenedLanguageSelector.data.target_key }); + setSelectedTargetLanguages({ + ...payload, + target_key: currentIsOpenedLanguageSelector.data.target_key, + }); }; + const title = getTitle("target_language"); return ( ); diff --git a/src-ui/app/main_page/main_section/language_selector/LanguageSelector.jsx b/src-ui/app/main_page/main_section/language_selector/LanguageSelector.jsx index d94d10ec..8fce4e2d 100644 --- a/src-ui/app/main_page/main_section/language_selector/LanguageSelector.jsx +++ b/src-ui/app/main_page/main_section/language_selector/LanguageSelector.jsx @@ -4,17 +4,10 @@ import { useSelectableLanguageList } from "@logics_main"; import styles from "./LanguageSelector.module.scss"; import { LanguageSelectorTopBar } from "./language_selector_top_bar/LanguageSelectorTopBar"; -export const LanguageSelector = ({ id, onClickFunction }) => { +export const LanguageSelector = ({ title, onClickFunction }) => { const { t } = useTranslation(); const { currentSelectableLanguageList } = useSelectableLanguageList(); - const languageTitles = { - your_language: t("main_page.language_selector.title_your_language"), - target_language: t("main_page.language_selector.title_target_language") - }; - - const language_selector_title = languageTitles[id] || ""; - const groupLanguagesByFirstLetter = (languages) => { return languages.reduce((acc, { language, country }) => { const firstLetter = language[0].toUpperCase(); @@ -30,7 +23,7 @@ export const LanguageSelector = ({ id, onClickFunction }) => { return (
- +
{Object.entries(groupedLanguages).map(([letter, languages]) => ( @@ -46,25 +39,25 @@ const LanguageGroup = ({ onClickFunction, letter, languages }) => { return (

{letter}

- {languages.map((languageData, index) => ( - + {languages.map((language_data, index) => ( + ))}
); }; -const LanguageButton = ({ onClickFunction, languageData }) => { +const LanguageButton = ({ onClickFunction, language_data }) => { const adjustedOnClickFunction = () => { onClickFunction({ - language: languageData.language, - country: languageData.country + language: language_data.language, + country: language_data.country, }); }; return (
-

{languageData.language} ({languageData.country})

+

{language_data.language} ({language_data.country})

); }; \ No newline at end of file diff --git a/src-ui/app/main_page/main_section/language_selector/language_selector_top_bar/LanguageSelectorTopBar.jsx b/src-ui/app/main_page/main_section/language_selector/language_selector_top_bar/LanguageSelectorTopBar.jsx index 59cfc850..1ea1c832 100644 --- a/src-ui/app/main_page/main_section/language_selector/language_selector_top_bar/LanguageSelectorTopBar.jsx +++ b/src-ui/app/main_page/main_section/language_selector/language_selector_top_bar/LanguageSelectorTopBar.jsx @@ -9,6 +9,7 @@ export const LanguageSelectorTopBar = (props) => { updateIsOpenedLanguageSelector({ your_language: false, target_language: false, + target_key: "1" }); }; diff --git a/src-ui/app/main_page/sidebar_section/language_settings/LanguageSettings.jsx b/src-ui/app/main_page/sidebar_section/language_settings/LanguageSettings.jsx index a36ce73c..7d90bdf4 100644 --- a/src-ui/app/main_page/sidebar_section/language_settings/LanguageSettings.jsx +++ b/src-ui/app/main_page/sidebar_section/language_settings/LanguageSettings.jsx @@ -4,6 +4,7 @@ import { PresetTabSelector } from "./preset_tab_selector/PresetTabSelector"; import { LanguageSelectorOpenButton } from "./language_selector_open_button/LanguageSelectorOpenButton"; import { LanguageSwapButton } from "./language_swap_button/LanguageSwapButton"; import { TranslatorSelectorOpenButton } from "./translator_selector_open_button/TranslatorSelectorOpenButton"; +import { AddRemoveTargetLanguageButtons } from "./add_remove_target_language_buttons/AddRemoveTargetLanguageButtons"; import { useStore_IsOpenedTranslatorSelector } from "@store"; export const LanguageSettings = () => { @@ -22,69 +23,32 @@ export const LanguageSettings = () => { import MicSvg from "@images/mic.svg?react"; import HeadphonesSvg from "@images/headphones.svg?react"; -import { useStore_IsOpenedLanguageSelector } from "@store"; -import { - useMainFunction, - useLanguageSettings, -} from "@logics_main"; - -// 言語セレクターをトグルする処理を関数化 -const toggleSelector = (selector, currentStatus, updateSelector) => { - if (currentStatus) { - updateSelector({ your_language: false, target_language: false }); - } else { - updateSelector({ - your_language: selector === "your_language", - target_language: selector === "target_language", - }); - } -}; - -// 選択された言語データの取得を関数化 -const getSelectedLanguageData = (presetTabData, languageData) => { - return (presetTabData !== undefined && languageData !== undefined) - ? languageData[Number(presetTabData)] - : undefined; -}; +import { useMainFunction } from "@logics_main"; const PresetContainer = () => { const { t } = useTranslation(); - const { updateIsOpenedLanguageSelector, currentIsOpenedLanguageSelector } = useStore_IsOpenedLanguageSelector(); - const { currentTranscriptionSendStatus, currentTranscriptionReceiveStatus } = useMainFunction(); - const { - currentSelectedPresetTabNumber, - currentSelectedYourLanguages, - currentSelectedTargetLanguages, - } = useLanguageSettings(); - - const your_language_data = getSelectedLanguageData(currentSelectedPresetTabNumber.data, currentSelectedYourLanguages.data); - const target_language_data = getSelectedLanguageData(currentSelectedPresetTabNumber.data, currentSelectedTargetLanguages.data); - const yourLanguageSettings = { - title: t("main_page.your_language"), - is_opened: currentIsOpenedLanguageSelector.data.your_language, - onClickFunction: () => toggleSelector("your_language", currentIsOpenedLanguageSelector.data.your_language, updateIsOpenedLanguageSelector), TurnedOnSvgComponent: MicSvg, is_turned_on: currentTranscriptionSendStatus.data, - variable: your_language_data?.primary, }; const targetLanguageSettings = { - title: t("main_page.target_language"), - is_opened: currentIsOpenedLanguageSelector.data.target_language, - onClickFunction: () => toggleSelector("target_language", currentIsOpenedLanguageSelector.data.target_language, updateIsOpenedLanguageSelector), TurnedOnSvgComponent: HeadphonesSvg, is_turned_on: currentTranscriptionReceiveStatus.data, - variable: target_language_data?.primary, }; return (
- + - +
+ + + +
+
); diff --git a/src-ui/app/main_page/sidebar_section/language_settings/LanguageSettings.module.scss b/src-ui/app/main_page/sidebar_section/language_settings/LanguageSettings.module.scss index 1c2b3a0e..b6bd3eaa 100644 --- a/src-ui/app/main_page/sidebar_section/language_settings/LanguageSettings.module.scss +++ b/src-ui/app/main_page/sidebar_section/language_settings/LanguageSettings.module.scss @@ -18,4 +18,12 @@ display: flex; flex-direction: column; align-items: center; +} + +.target_language_containers { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + gap: 0.2rem; } \ No newline at end of file diff --git a/src-ui/app/main_page/sidebar_section/language_settings/add_remove_target_language_buttons/AddRemoveTargetLanguageButtons.jsx b/src-ui/app/main_page/sidebar_section/language_settings/add_remove_target_language_buttons/AddRemoveTargetLanguageButtons.jsx new file mode 100644 index 00000000..3e71373f --- /dev/null +++ b/src-ui/app/main_page/sidebar_section/language_settings/add_remove_target_language_buttons/AddRemoveTargetLanguageButtons.jsx @@ -0,0 +1,34 @@ +import clsx from "clsx"; +import styles from "./AddRemoveTargetLanguageButtons.module.scss"; +import RemoveSvg from "@images/remove.svg?react"; +import AddSvg from "@images/add.svg?react"; + +import { useLanguageSettings } from "@logics_main"; + +export const AddRemoveTargetLanguageButtons = () => { + const { + currentSelectedPresetTabNumber, + // currentSelectedYourLanguages, + currentSelectedTargetLanguages, + removeTargetLanguage, + addTargetLanguage, + } = useLanguageSettings(); + + const remove_button_class = clsx(styles.remove_target_language_button, { + [styles.is_disabled]: !currentSelectedTargetLanguages.data[currentSelectedPresetTabNumber.data]["2"].enable, + }); + const add_button_class = clsx(styles.add_target_language_button, { + [styles.is_disabled]: currentSelectedTargetLanguages.data[currentSelectedPresetTabNumber.data]["3"].enable, + }); + + return ( +
+
+ +
+
+ +
+
+ ); +}; \ No newline at end of file diff --git a/src-ui/app/main_page/sidebar_section/language_settings/add_remove_target_language_buttons/AddRemoveTargetLanguageButtons.module.scss b/src-ui/app/main_page/sidebar_section/language_settings/add_remove_target_language_buttons/AddRemoveTargetLanguageButtons.module.scss new file mode 100644 index 00000000..b6fe972c --- /dev/null +++ b/src-ui/app/main_page/sidebar_section/language_settings/add_remove_target_language_buttons/AddRemoveTargetLanguageButtons.module.scss @@ -0,0 +1,32 @@ +.add_remove_target_language_container { + width: 100%; + display: flex; + align-items: center; +} + +.add_target_language_button, .remove_target_language_button { + width: 100%; + display: flex; + justify-content: center; + align-items: center; + padding: 0.6rem 0; + cursor: pointer; + background-color: var(--dark_825_color); + &:hover { + background-color: var(--dark_875_color); + } + &:active { + background-color: var(--dark_900_color); + } + &.is_disabled { + pointer-events: none; + .remove_svg, .add_svg { + color: var(--dark_700_color); + } + } +} + +.remove_svg, .add_svg { + width: 0.8rem; + color: var(--dark_200_color); +} \ No newline at end of file diff --git a/src-ui/app/main_page/sidebar_section/language_settings/language_selector_open_button/LanguageSelectorOpenButton.jsx b/src-ui/app/main_page/sidebar_section/language_settings/language_selector_open_button/LanguageSelectorOpenButton.jsx index 4139c057..eacbf8f4 100644 --- a/src-ui/app/main_page/sidebar_section/language_settings/language_selector_open_button/LanguageSelectorOpenButton.jsx +++ b/src-ui/app/main_page/sidebar_section/language_settings/language_selector_open_button/LanguageSelectorOpenButton.jsx @@ -1,18 +1,61 @@ +import { useTranslation } from "react-i18next"; import clsx from "clsx"; import styles from "./LanguageSelectorOpenButton.module.scss"; import ArrowLeftSvg from "@images/arrow_left.svg?react"; +import { useStore_IsOpenedLanguageSelector } from "@store"; +import { + useLanguageSettings, +} from "@logics_main"; + +export const LanguageSelectorOpenButton = ({ TurnedOnSvgComponent, is_turned_on, selector_key, target_key }) => { + const { t } = useTranslation(); + const { updateIsOpenedLanguageSelector, currentIsOpenedLanguageSelector } = useStore_IsOpenedLanguageSelector(); + + const { + currentSelectedPresetTabNumber, + currentSelectedYourLanguages, + currentSelectedTargetLanguages, + } = useLanguageSettings(); + + const toggleSelector = () => { + if (currentIsOpenedLanguageSelector.data[selector_key] === true && currentIsOpenedLanguageSelector.data.target_key === target_key) { // Close Language Selector + updateIsOpenedLanguageSelector({ your_language: false, target_language: false, target_key: "1" }); + } else { // Open Language Selector + updateIsOpenedLanguageSelector({ + your_language: selector_key === "your_language", + target_language: selector_key === "target_language", + target_key: target_key, + }); + } + }; -export const LanguageSelectorOpenButton = ({ title, onClickFunction, is_opened, TurnedOnSvgComponent, is_turned_on, variable }) => { const arrow_class_names = clsx(styles.arrow_left_svg, { - [styles.reverse]: is_opened, + [styles.reverse]: (currentIsOpenedLanguageSelector.data[selector_key] === true && currentIsOpenedLanguageSelector.data.target_key === target_key), }); const category_class_names = clsx(styles.category_svg, { [styles.is_turned_on]: is_turned_on, }); - const languageText = variable?.language ?? "Loading..."; - const countryText = variable?.country ?? "Loading..."; + const getVariable = (target_selector_key) => { + if (target_selector_key === "your_language") return currentSelectedYourLanguages.data[currentSelectedPresetTabNumber.data]; + if (target_selector_key === "target_language") return currentSelectedTargetLanguages.data[currentSelectedPresetTabNumber.data]; + }; + + const getTitle = (target_selector_key) => { + if (target_selector_key === "your_language") return t("main_page.your_language"); + if (target_selector_key === "target_language") { + if (currentSelectedTargetLanguages.data[currentSelectedPresetTabNumber.data]["2"].enable === false) return t("main_page.target_language"); + return `${t("main_page.target_language")} ${target_key}`; + } + }; + + const title = getTitle(selector_key); + + if (getVariable(selector_key)[target_key].enable === false) return null; + + const language_text = getVariable(selector_key)[target_key].language ?? "Loading..."; + const country_text = getVariable(selector_key)[target_key].country ?? "Loading..."; return (
@@ -20,9 +63,9 @@ export const LanguageSelectorOpenButton = ({ title, onClickFunction, is_opened,

{title}

-
-

{languageText}

-

({countryText})

+
+

{language_text}

+

({country_text})

diff --git a/src-ui/assets/add.svg b/src-ui/assets/add.svg new file mode 100644 index 00000000..6bb80d3b --- /dev/null +++ b/src-ui/assets/add.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src-ui/assets/remove.svg b/src-ui/assets/remove.svg new file mode 100644 index 00000000..189ba7fe --- /dev/null +++ b/src-ui/assets/remove.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src-ui/logics/main/useLanguageSettings.js b/src-ui/logics/main/useLanguageSettings.js index 9a516a9c..163f9f37 100644 --- a/src-ui/logics/main/useLanguageSettings.js +++ b/src-ui/logics/main/useLanguageSettings.js @@ -61,10 +61,10 @@ export const useLanguageSettings = () => { const send_obj = { ...currentSelectedYourLanguages.data, [currentSelectedPresetTabNumber.data]: { - 1: { + 1: { // Fixed key 1. language: selected_language_data.language, country: selected_language_data.country, - enable: selected_language_data.enable, + enable: true, } } }; @@ -80,11 +80,29 @@ export const useLanguageSettings = () => { const setSelectedTargetLanguages = (selected_language_data) => { pendingSelectedTargetLanguages(); let send_obj = currentSelectedTargetLanguages.data; + send_obj[currentSelectedPresetTabNumber.data][selected_language_data.target_key].language = selected_language_data.language, + send_obj[currentSelectedPresetTabNumber.data][selected_language_data.target_key].country = selected_language_data.country, + asyncStdoutToPython("/set/data/selected_target_languages", send_obj); + }; - send_obj[currentSelectedPresetTabNumber.data][1].language = selected_language_data.language, - send_obj[currentSelectedPresetTabNumber.data][1].country = selected_language_data.country, - send_obj[currentSelectedPresetTabNumber.data][1].enable = selected_language_data.enable, - + const addTargetLanguage = () => { + pendingSelectedTargetLanguages(); + let send_obj = currentSelectedTargetLanguages.data; + let target_key = "2"; + if (send_obj[currentSelectedPresetTabNumber.data]["2"].enable === true) { + target_key = "3"; + } + send_obj[currentSelectedPresetTabNumber.data][target_key].enable = true, + asyncStdoutToPython("/set/data/selected_target_languages", send_obj); + }; + const removeTargetLanguage = () => { + pendingSelectedTargetLanguages(); + let send_obj = currentSelectedTargetLanguages.data; + let target_key = "3"; + if (send_obj[currentSelectedPresetTabNumber.data]["3"].enable === false) { + target_key = "2"; + } + send_obj[currentSelectedPresetTabNumber.data][target_key].enable = false, asyncStdoutToPython("/set/data/selected_target_languages", send_obj); }; @@ -134,6 +152,9 @@ export const useLanguageSettings = () => { updateSelectedTargetLanguages, setSelectedTargetLanguages, + addTargetLanguage, + removeTargetLanguage, + currentTranslationEngines, getTranslationEngines, updateTranslationEngines, diff --git a/src-ui/store.js b/src-ui/store.js index 878911cc..24c2824f 100644 --- a/src-ui/store.js +++ b/src-ui/store.js @@ -136,7 +136,7 @@ export const { atomInstance: Atom_IsAppliedInitMessageBoxHeight, useHook: useSto export const { atomInstance: Atom_SelectableLanguageList, useHook: useStore_SelectableLanguageList } = createAtomWithHook([], "SelectableLanguageList"); -export const { atomInstance: Atom_SelectedPresetTabNumber, useHook: useStore_SelectedPresetTabNumber } = createAtomWithHook("", "SelectedPresetTabNumber"); +export const { atomInstance: Atom_SelectedPresetTabNumber, useHook: useStore_SelectedPresetTabNumber } = createAtomWithHook("1", "SelectedPresetTabNumber"); export const { atomInstance: Atom_EnableMultiTranslation, useHook: useStore_EnableMultiTranslation } = createAtomWithHook(false, "EnableMultiTranslation"); export const { atomInstance: Atom_SelectedYourLanguages, useHook: useStore_SelectedYourLanguages } = createAtomWithHook({}, "SelectedYourLanguages"); export const { atomInstance: Atom_SelectedTargetLanguages, useHook: useStore_SelectedTargetLanguages } = createAtomWithHook({}, "SelectedTargetLanguages"); @@ -150,7 +150,7 @@ export const { atomInstance: Atom_SelectedTranslationEngines, useHook: useStore_ export const { atomInstance: Atom_IsMainPageCompactMode, useHook: useStore_IsMainPageCompactMode } = createAtomWithHook(false, "IsMainPageCompactMode"); export const { atomInstance: Atom_MessageInputBoxRatio, useHook: useStore_MessageInputBoxRatio } = createAtomWithHook(20, "MessageInputBoxRatio"); export const { atomInstance: Atom_IsOpenedLanguageSelector, useHook: useStore_IsOpenedLanguageSelector } = createAtomWithHook( - { your_language: false, target_language: false }, + { your_language: false, target_language: false, target_key: "1" }, "IsOpenedLanguageSelector" );