Merge branch 'ui' into for_webui

This commit is contained in:
Sakamoto Shiina
2024-09-26 00:31:54 +09:00
8 changed files with 145 additions and 24 deletions

View File

@@ -34,6 +34,7 @@ import { useUiLanguage } from "@logics_configs/useUiLanguage";
import { useIsMainPageCompactMode } from "@logics_main/useIsMainPageCompactMode";
import { useLanguageSettings } from "@logics_main/useLanguageSettings";
import { useSelectableLanguageList } from "@logics_main/useSelectableLanguageList";
import { useMessageInputBoxRatio } from "@logics_main/useMessageInputBoxRatio";
const StartPythonFacadeComponent = () => {
const { asyncStartPython } = useStartPython();
@@ -62,6 +63,7 @@ const StartPythonFacadeComponent = () => {
getSelectedTranslationEngines,
} = useLanguageSettings();
const { getSelectableLanguageList } = useSelectableLanguageList();
const { getMessageInputBoxRatio } = useMessageInputBoxRatio();
useEffect(() => {
@@ -70,6 +72,7 @@ const StartPythonFacadeComponent = () => {
asyncStartPython().then((result) => {
getUiLanguage();
getIsMainPageCompactMode();
getMessageInputBoxRatio();
getSoftwareVersion();

View File

@@ -1,34 +1,97 @@
import { useResizable } from "react-resizable-layout";
import { useRef, useEffect, useState } from "react";
import styles from "./MessageContainer.module.scss";
import { appWindow } from "@tauri-apps/api/window"; // Tauriのwindow APIをインポート
import { LogBox } from "./log_box/LogBox";
import { MessageInputBox } from "./message_input_box/MessageInputBox";
import { useMessageInputBoxRatio } from "@logics_main/useMessageInputBoxRatio";
export const MessageContainer = () => {
const { currentMessageInputBoxRatio, setMessageInputBoxRatio } = useMessageInputBoxRatio();
const [message_box_height_in_rem, setMessageBoxHeightInRem] = useState(10);
const container_ref = useRef(null);
const log_box_ref = useRef(null);
const message_box_wrapper_ref = useRef(null);
const calculateMessageBoxRatioAndHeight = () => {
if (log_box_ref.current && message_box_wrapper_ref.current) {
const container_height = container_ref.current.offsetHeight;
const container_padding_bottom = parseFloat(window.getComputedStyle(container_ref.current).paddingBottom);
const total_height = container_height - container_padding_bottom;
const message_box_height = message_box_wrapper_ref.current.offsetHeight;
const message_box_ratio = (message_box_height / total_height) * 100;
setMessageInputBoxRatio(message_box_ratio);
const height_in_rem = convertRatioToRem(message_box_ratio);
setMessageBoxHeightInRem(height_in_rem);
}
};
const { position, separatorProps } = useResizable({
axis: "y",
reverse: true
reverse: true,
onResizeEnd: calculateMessageBoxRatioAndHeight,
});
useEffect(() => {
setMessageBoxHeightInRem((position / 10) - 1.5);
}, [position]);
useEffect(() => {
setMessageBoxHeightInRem(convertRatioToRem(currentMessageInputBoxRatio.data));
}, [currentMessageInputBoxRatio.data]);
const convertRatioToRem = (ratio) => {
const container_height = container_ref.current.offsetHeight;
const container_padding_bottom = parseFloat(window.getComputedStyle(container_ref.current).paddingBottom);
const total_height = container_height - container_padding_bottom;
return ((ratio / 100) * total_height / 10) | 0; // 10px = 1rem
};
// Tauriのwindow resizeイベントをリッスン
useEffect(() => {
let resizeTimeout;
// イベントのリスナーを設定
const unlisten = appWindow.onResized(() => {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(() => {
calculateMessageBoxRatioAndHeight(); // リサイズが終了した後に実行
}, 200); // ドラッグが終了したと見なすまでの遅延200ms程度
});
return () => {
unlisten.then((dispose) => dispose()); // イベントリスナーを解除
};
}, []);
return (
<div className={styles.container}>
<LogBox />
<Separator
dir={"horizontal"}
{...separatorProps}
/>
<div className={styles.message_box_resize_wrapper} style={ { height: `${(position / 10) - 1.5 }rem` } }>
<div className={styles.container} ref={container_ref}>
<div ref={log_box_ref} className={styles.log_box_resize_wrapper}>
<LogBox />
</div>
<Separator {...separatorProps} onDragStart={calculateMessageBoxRatioAndHeight} />
<div
className={styles.message_box_resize_wrapper}
ref={message_box_wrapper_ref}
style={{ height: `${message_box_height_in_rem}rem` }}
>
<MessageInputBox />
</div>
</div>
);
};
const Separator = ({ ...props }) => {
const Separator = ({ onDragStart, ...props }) => {
return (
<div tabIndex={0} className={styles.separator} {...props}>
<div tabIndex={0} className={styles.separator} {...props} onDragStart={onDragStart}>
<span className={styles.separator_line}></span>
</div>
);
};
};

View File

@@ -6,6 +6,11 @@
padding: 0 1.6rem 1rem 1.6rem;
}
.log_box_resize_wrapper {
flex: 1;
overflow: auto;
}
.separator {
position: relative;
width: 100%;
@@ -32,5 +37,5 @@
.message_box_resize_wrapper {
height: 10rem;
min-height: 3.8rem;
max-height: 80%;
max-height: 90%;
}

View File

@@ -0,0 +1,24 @@
import { useStore_MessageInputBoxRatio } from "@store";
import { useStdoutToPython } from "@logics/useStdoutToPython";
import { clampMinMax } from "@utils/clampMinMax";
export const useMessageInputBoxRatio = () => {
const { asyncStdoutToPython } = useStdoutToPython();
const { currentMessageInputBoxRatio, updateMessageInputBoxRatio } = useStore_MessageInputBoxRatio();
const getMessageInputBoxRatio = () => {
asyncStdoutToPython("/get/data/message_box_ratio");
};
const setMessageInputBoxRatio = (ratio) => {
const parsed = parseFloat(ratio.toFixed(2));
const valid_ratio = clampMinMax(parsed, 1, 99);
asyncStdoutToPython("/set/data/message_box_ratio", valid_ratio);
};
return {
currentMessageInputBoxRatio,
getMessageInputBoxRatio,
updateMessageInputBoxRatio,
setMessageInputBoxRatio,
};
};

View File

@@ -1,12 +1,15 @@
import { translator_status } from "@data";
import { arrayToObject } from "@utils/arrayToObject";
import { useMainFunction } from "@logics_main/useMainFunction";
import { useMessage } from "@logics_common/useMessage";
import { useVolume } from "@logics_common/useVolume";
import { useMainFunction } from "@logics_main/useMainFunction";
import { useSelectableLanguageList } from "@logics_main/useSelectableLanguageList";
import { useLanguageSettings } from "@logics_main/useLanguageSettings";
import { useIsMainPageCompactMode } from "@logics_main/useIsMainPageCompactMode";
import { useVolume } from "@logics_common/useVolume";
import { useMessageInputBoxRatio } from "@logics_main/useMessageInputBoxRatio";
import { useSoftwareVersion } from "@logics_configs/useSoftwareVersion";
@@ -67,6 +70,9 @@ export const useReceiveRoutes = () => {
updateSpeakerThresholdCheckStatus,
} = useVolume();
const { updateMessageInputBoxRatio } = useMessageInputBoxRatio();
const routes = {
// Main Page
// Page Controls
@@ -118,6 +124,10 @@ export const useReceiveRoutes = () => {
"/run/transcription_send_mic_message": addSentMessageLog,
"/run/transcription_receive_speaker_message": addReceivedMessageLog,
// Message Box
"/get/data/message_box_ratio": updateMessageInputBoxRatio,
"/set/data/message_box_ratio": updateMessageInputBoxRatio,
// Config Page
// Common

View File

@@ -2,9 +2,9 @@ import { store } from "@store";
import { encode } from "js-base64";
export const useStdoutToPython = () => {
const asyncStdoutToPython = async (path, value) => {
const asyncStdoutToPython = async (path, value = undefined) => {
let send_object = { endpoint: path };
if (value) send_object.data = encode(JSON.stringify(value));
if (value !== undefined) send_object.data = encode(JSON.stringify(value));
// send to python
const backend_subprocess = store.backend_subprocess;

View File

@@ -101,18 +101,15 @@ const createAtomWithHook = (initialValue, base_name, options) => {
export const { atomInstance: Atom_SoftwareVersion, useHook: useStore_SoftwareVersion } = createAtomWithHook("-", "SoftwareVersion");
// Main Page
// Functions
export const { atomInstance: Atom_TranslationStatus, useHook: useStore_TranslationStatus } = createAtomWithHook(false, "TranslationStatus", {is_state_ok: true});
export const { atomInstance: Atom_TranscriptionSendStatus, useHook: useStore_TranscriptionSendStatus } = createAtomWithHook(false, "TranscriptionSendStatus", {is_state_ok: true});
export const { atomInstance: Atom_TranscriptionReceiveStatus, useHook: useStore_TranscriptionReceiveStatus } = createAtomWithHook(false, "TranscriptionReceiveStatus", {is_state_ok: true});
export const { atomInstance: Atom_ForegroundStatus, useHook: useStore_ForegroundStatus } = createAtomWithHook(false, "ForegroundStatus", {is_state_ok: true});
export const { atomInstance: Atom_MessageLogs, useHook: useStore_MessageLogs } = createAtomWithHook(generateTestData(20), "MessageLogs");
export const { atomInstance: Atom_IsMainPageCompactMode, useHook: useStore_IsMainPageCompactMode } = createAtomWithHook(false, "IsMainPageCompactMode");
export const { atomInstance: Atom_IsOpenedLanguageSelector, useHook: useStore_IsOpenedLanguageSelector } = createAtomWithHook(
{ your_language: false, target_language: false },
"IsOpenedLanguageSelector"
);
export const { atomInstance: Atom_SelectableLanguageList, useHook: useStore_SelectableLanguageList } = createAtomWithHook([], "SelectableLanguageList");
export const { atomInstance: Atom_SelectedPresetTabNumber, useHook: useStore_SelectedPresetTabNumber } = createAtomWithHook("", "SelectedPresetTabNumber");
@@ -127,10 +124,21 @@ export const { atomInstance: Atom_SelectedTranslationEngines, useHook: useStore_
export const { atomInstance: Atom_IsOpenedConfigPage, useHook: useStore_IsOpenedConfigPage } = createAtomWithHook(false, "IsOpenedConfigPage");
export const { atomInstance: Atom_SelectedConfigTabId, useHook: useStore_SelectedConfigTabId } = createAtomWithHook("device", "SelectedConfigTabId");
export const { atomInstance: Atom_IsOpenedDropdownMenu, useHook: useStore_IsOpenedDropdownMenu } = createAtomWithHook("", "IsOpenedDropdownMenu");
// Designs
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 },
"IsOpenedLanguageSelector"
);
// Config Page
// Designs
export const { atomInstance: Atom_IsOpenedDropdownMenu, useHook: useStore_IsOpenedDropdownMenu } = createAtomWithHook("", "IsOpenedDropdownMenu");
// Device
export const { atomInstance: Atom_EnableAutoMicSelect, useHook: useStore_EnableAutoMicSelect } = createAtomWithHook(true, "EnableAutoMicSelect");
export const { atomInstance: Atom_EnableAutoSpeakerSelect, useHook: useStore_EnableAutoSpeakerSelect } = createAtomWithHook(true, "EnableAutoSpeakerSelect");

View File

@@ -0,0 +1,8 @@
export const clampMinMax = (value, min, max) => {
return Math.min(Math.max(value, min), max);
};
// console.log(clamp(5, 1, 10)); // 5 (範囲内)
// console.log(clamp(-3, 0, 10)); // 0 (minより小さい)
// console.log(clamp(15, 1, 10)); // 10 (maxより大きい)
// console.log(clamp(7.5, 1, 10)); // 7.5 (範囲内、少数)