mirror of
https://github.com/mii443/vrclipboard-ime-gui.git
synced 2025-08-22 16:15:32 +00:00
update Terminal
This commit is contained in:
@ -31,6 +31,8 @@ pub struct Config {
|
|||||||
pub use_tsf_reconvert: bool,
|
pub use_tsf_reconvert: bool,
|
||||||
#[serde(default = "bool_true")]
|
#[serde(default = "bool_true")]
|
||||||
pub skip_on_out_of_vrc: bool,
|
pub skip_on_out_of_vrc: bool,
|
||||||
|
#[serde(default = "bool_false")]
|
||||||
|
pub tsf_announce: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
@ -44,6 +46,7 @@ impl Default for Config {
|
|||||||
skip_url: true,
|
skip_url: true,
|
||||||
use_tsf_reconvert: false,
|
use_tsf_reconvert: false,
|
||||||
skip_on_out_of_vrc: true,
|
skip_on_out_of_vrc: true,
|
||||||
|
tsf_announce: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ use clipboard::{ClipboardContext, ClipboardProvider};
|
|||||||
use clipboard_master::{CallbackResult, ClipboardHandler};
|
use clipboard_master::{CallbackResult, ClipboardHandler};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use rosc::{encoder, OscMessage, OscPacket, OscType};
|
use rosc::{encoder, OscMessage, OscPacket, OscType};
|
||||||
use tauri::{AppHandle, Emitter, Manager};
|
use tauri::{AppHandle, Emitter};
|
||||||
use tracing::{error, info, warn};
|
use tracing::{error, info, warn};
|
||||||
use windows::Win32::System::DataExchange::GetClipboardOwner;
|
use windows::Win32::System::DataExchange::GetClipboardOwner;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||||
//#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
|
|
||||||
mod com;
|
mod com;
|
||||||
mod config;
|
mod config;
|
||||||
@ -23,7 +23,6 @@ use com::Com;
|
|||||||
use config::Config;
|
use config::Config;
|
||||||
use handler::ConversionHandler;
|
use handler::ConversionHandler;
|
||||||
use tauri_emit_subscriber::TauriEmitSubscriber;
|
use tauri_emit_subscriber::TauriEmitSubscriber;
|
||||||
use tracing::{instrument::WithSubscriber, level_filters::LevelFilter, Level};
|
|
||||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
@ -58,8 +57,6 @@ fn save_settings(config: Config, state: State<AppState>) -> Result<(), String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("VRClipboard-IME Logs\nバグがあった場合はこのログを送ってください。");
|
|
||||||
|
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.plugin(tauri_plugin_shell::init())
|
.plugin(tauri_plugin_shell::init())
|
||||||
.plugin(tauri_plugin_updater::Builder::new().build())
|
.plugin(tauri_plugin_updater::Builder::new().build())
|
||||||
|
@ -4,7 +4,8 @@ import { listen } from "@tauri-apps/api/event";
|
|||||||
import "./App.css";
|
import "./App.css";
|
||||||
import TitleBar from "./TitleBar";
|
import TitleBar from "./TitleBar";
|
||||||
import SettingsComponent from "./SettingsComponent";
|
import SettingsComponent from "./SettingsComponent";
|
||||||
import { ThemeProvider, useTheme } from "./ThemeContext";
|
import { ThemeProvider } from "./ThemeContext";
|
||||||
|
import { LogProvider } from "./LogContext";
|
||||||
import TerminalComponent from "./TerminalComponent";
|
import TerminalComponent from "./TerminalComponent";
|
||||||
import AboutComponent from "./AboutComponent";
|
import AboutComponent from "./AboutComponent";
|
||||||
|
|
||||||
@ -15,7 +16,6 @@ interface Log {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const AppContent = () => {
|
const AppContent = () => {
|
||||||
const { theme } = useTheme();
|
|
||||||
const [logs, setLogs] = useState<Log[]>([]);
|
const [logs, setLogs] = useState<Log[]>([]);
|
||||||
const [activeMenuItem, setActiveMenuItem] = useState('home');
|
const [activeMenuItem, setActiveMenuItem] = useState('home');
|
||||||
|
|
||||||
@ -118,7 +118,9 @@ const AppContent = () => {
|
|||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<ThemeProvider>
|
<ThemeProvider>
|
||||||
<AppContent />
|
<LogProvider>
|
||||||
|
<AppContent />
|
||||||
|
</LogProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
69
src/LogContext.tsx
Normal file
69
src/LogContext.tsx
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import React, { createContext, useState, useContext, useEffect } from 'react';
|
||||||
|
import { listen } from '@tauri-apps/api/event';
|
||||||
|
|
||||||
|
export interface LogMessage {
|
||||||
|
level: 'info' | 'warn' | 'error' | 'debug' | 'trace';
|
||||||
|
message: string;
|
||||||
|
module_path: string;
|
||||||
|
timestamp: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LogContextType {
|
||||||
|
logs: LogMessage[];
|
||||||
|
clearLogs: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LogContext = createContext<LogContextType | undefined>(undefined);
|
||||||
|
|
||||||
|
export const LogProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||||
|
const [logs, setLogs] = useState<LogMessage[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// グローバルにログイベントを監視
|
||||||
|
const setupLogListener = async () => {
|
||||||
|
try {
|
||||||
|
// log-eventイベントのリスナーを設定
|
||||||
|
const unlisten = await listen<LogMessage>('log-event', (event) => {
|
||||||
|
setLogs(prev => [...prev, event.payload]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// クリーンアップ関数を返す
|
||||||
|
return () => {
|
||||||
|
unlisten();
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to set up log listener:', error);
|
||||||
|
return () => {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// リスナーをセットアップし、その結果をPromiseとして保持
|
||||||
|
const unlistenPromise = setupLogListener();
|
||||||
|
|
||||||
|
// コンポーネントのアンマウント時にリスナーを解除
|
||||||
|
return () => {
|
||||||
|
unlistenPromise.then(cleanupFn => cleanupFn()).catch(err => {
|
||||||
|
console.error('Error cleaning up event listener:', err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const clearLogs = () => {
|
||||||
|
setLogs([]);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LogContext.Provider value={{ logs, clearLogs }}>
|
||||||
|
{children}
|
||||||
|
</LogContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// カスタムフック
|
||||||
|
export const useLogs = (): LogContextType => {
|
||||||
|
const context = useContext(LogContext);
|
||||||
|
if (context === undefined) {
|
||||||
|
throw new Error('useLogs must be used within a LogProvider');
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
};
|
@ -1,51 +1,29 @@
|
|||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
import { listen } from '@tauri-apps/api/event';
|
|
||||||
import { Check, Copy, Trash, Download } from 'lucide-react';
|
import { Check, Copy, Trash, Download } from 'lucide-react';
|
||||||
|
import { useLogs } from './LogContext';
|
||||||
interface LogMessage {
|
|
||||||
level: 'info' | 'warn' | 'error' | 'debug' | 'trace';
|
|
||||||
message: string;
|
|
||||||
module_path: string;
|
|
||||||
timestamp: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const TerminalComponent: React.FC = () => {
|
const TerminalComponent: React.FC = () => {
|
||||||
const [logs, setLogs] = useState<LogMessage[]>([]);
|
const { logs, clearLogs } = useLogs();
|
||||||
const [filter, setFilter] = useState<string>('');
|
const [filter, setFilter] = useState<string>('');
|
||||||
const [autoScroll, setAutoScroll] = useState<boolean>(true);
|
const [autoScroll, setAutoScroll] = useState<boolean>(true);
|
||||||
const [copied, setCopied] = useState<boolean>(false);
|
const [copied, setCopied] = useState<boolean>(false);
|
||||||
const terminalRef = useRef<HTMLDivElement>(null);
|
const terminalRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
// 自動スクロール効果
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const setupLogListener = async () => {
|
// コンポーネントがマウントされたとき、または新しいログが追加されたときに自動スクロール
|
||||||
try {
|
|
||||||
const unlisten = await listen<LogMessage>('log-event', (event) => {
|
|
||||||
setLogs(prev => [...prev, event.payload]);
|
|
||||||
if (autoScroll && terminalRef.current) {
|
|
||||||
terminalRef.current.scrollTop = terminalRef.current.scrollHeight;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
unlisten();
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to set up log listener:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
setupLogListener();
|
|
||||||
|
|
||||||
if (terminalRef.current) {
|
|
||||||
terminalRef.current.scrollTop = terminalRef.current.scrollHeight;
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (autoScroll && terminalRef.current) {
|
if (autoScroll && terminalRef.current) {
|
||||||
terminalRef.current.scrollTop = terminalRef.current.scrollHeight;
|
terminalRef.current.scrollTop = terminalRef.current.scrollHeight;
|
||||||
}
|
}
|
||||||
}, [logs, filter, autoScroll]);
|
}, [logs, filter, autoScroll]);
|
||||||
|
|
||||||
|
// コンポーネントがマウントされた時に一度だけ実行
|
||||||
|
useEffect(() => {
|
||||||
|
// 初期スクロール位置を設定
|
||||||
|
if (terminalRef.current) {
|
||||||
|
terminalRef.current.scrollTop = terminalRef.current.scrollHeight;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
const getLogColor = (level: string): string => {
|
const getLogColor = (level: string): string => {
|
||||||
switch (level) {
|
switch (level) {
|
||||||
@ -59,8 +37,7 @@ const TerminalComponent: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleCopyLogs = async () => {
|
const handleCopyLogs = async () => {
|
||||||
const logText = logs
|
const logText = filteredLogs
|
||||||
.filter(log => filter === '' || log.message.toLowerCase().includes(filter.toLowerCase()) || log.level.includes(filter.toLowerCase()))
|
|
||||||
.map(log => `[${log.timestamp} ${log.module_path}] [${log.level.toUpperCase()}] ${log.message}`)
|
.map(log => `[${log.timestamp} ${log.module_path}] [${log.level.toUpperCase()}] ${log.message}`)
|
||||||
.join('\n');
|
.join('\n');
|
||||||
|
|
||||||
@ -73,13 +50,8 @@ const TerminalComponent: React.FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClearLogs = () => {
|
|
||||||
setLogs([]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSaveLogs = () => {
|
const handleSaveLogs = () => {
|
||||||
const logText = logs
|
const logText = filteredLogs
|
||||||
.filter(log => filter === '' || log.message.toLowerCase().includes(filter.toLowerCase()) || log.level.includes(filter.toLowerCase()))
|
|
||||||
.map(log => `[${log.timestamp} ${log.module_path}] [${log.level.toUpperCase()}] ${log.message}`)
|
.map(log => `[${log.timestamp} ${log.module_path}] [${log.level.toUpperCase()}] ${log.message}`)
|
||||||
.join('\n');
|
.join('\n');
|
||||||
|
|
||||||
@ -97,7 +69,7 @@ const TerminalComponent: React.FC = () => {
|
|||||||
const filteredLogs = logs.filter(
|
const filteredLogs = logs.filter(
|
||||||
log => filter === '' ||
|
log => filter === '' ||
|
||||||
log.message.toLowerCase().includes(filter.toLowerCase()) ||
|
log.message.toLowerCase().includes(filter.toLowerCase()) ||
|
||||||
log.level.includes(filter.toLowerCase())
|
log.level.toLowerCase().includes(filter.toLowerCase())
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -114,7 +86,7 @@ const TerminalComponent: React.FC = () => {
|
|||||||
{copied ? 'コピー完了' : 'コピー'}
|
{copied ? 'コピー完了' : 'コピー'}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={handleClearLogs}
|
onClick={clearLogs}
|
||||||
className="flex items-center text-xs text-gray-600 dark:text-gray-400 hover:text-red-600 dark:hover:text-red-400 bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded"
|
className="flex items-center text-xs text-gray-600 dark:text-gray-400 hover:text-red-600 dark:hover:text-red-400 bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded"
|
||||||
title="ログをクリア"
|
title="ログをクリア"
|
||||||
>
|
>
|
||||||
|
Reference in New Issue
Block a user