diff --git a/src/settings/resources/config/test_config.json b/src/settings/resources/config/test_config.json new file mode 100644 index 0000000..9f16c30 --- /dev/null +++ b/src/settings/resources/config/test_config.json @@ -0,0 +1,45 @@ +{ + "application": { + "name": "MagicWord", + "version": "2.0.0", + "author": "MagicWord Team", + "description": "隐私学习软件" + }, + "window": { + "default_size": { + "width": 800, + "height": 600 + }, + "minimum_size": { + "width": 600, + "height": 400 + }, + "title": "MagicWord - 隐私学习软件" + }, + "typing": { + "default_time_limit": 300, + "show_progress_bar": true, + "highlight_current_line": true, + "auto_save_progress": true + }, + "files": { + "supported_formats": [ + ".txt", + ".docx" + ], + "auto_backup_enabled": true, + "backup_interval_minutes": 30 + }, + "network": { + "weather_api_key": "YOUR_WEATHER_API_KEY", + "quote_api_url": "https://api.quotable.io/random", + "timeout_seconds": 10 + }, + "appearance": { + "theme": "light", + "font_family": "Arial", + "font_size": 12, + "text_color": "#000000", + "background_color": "#FFFFFF" + } +} \ No newline at end of file diff --git a/src/settings/settings_manager.py b/src/settings/settings_manager.py index c08d2da..9f647ef 100644 --- a/src/settings/settings_manager.py +++ b/src/settings/settings_manager.py @@ -7,11 +7,66 @@ class SettingsManager: def __init__(self, config_file: str = "config.json"): """ 初始化设置管理器 - - 指定配置文件路径123 + - 指定配置文件路径 - 加载现有配置或创建默认配置 """ - # TODO: 实现构造函数逻辑 - pass + # 指定配置文件路径 + self.config_file = config_file + self.config_path = os.path.join("resources", "config", config_file) + + # 加载现有配置或创建默认配置 + self.settings = self.load_settings() + if not self.settings: + self.settings = self._create_default_settings() + self.save_settings(self.settings) + + def _create_default_settings(self) -> Dict[str, Any]: + """ + 创建默认配置 + - 返回包含默认设置的字典 + """ + return { + "application": { + "name": "MagicWord", + "version": "1.0.0", + "author": "MagicWord Team", + "description": "隐私学习软件" + }, + "window": { + "default_size": { + "width": 800, + "height": 600 + }, + "minimum_size": { + "width": 600, + "height": 400 + }, + "title": "MagicWord - 隐私学习软件" + }, + "typing": { + "default_time_limit": 300, + "show_progress_bar": True, + "highlight_current_line": True, + "auto_save_progress": True + }, + "files": { + "supported_formats": [".txt", ".docx"], + "auto_backup_enabled": True, + "backup_interval_minutes": 30 + }, + "network": { + "weather_api_key": "YOUR_WEATHER_API_KEY", + "quote_api_url": "https://api.quotable.io/random", + "timeout_seconds": 10 + }, + "appearance": { + "theme": "light", + "font_family": "Arial", + "font_size": 12, + "text_color": "#000000", + "background_color": "#FFFFFF" + } + } def load_settings(self) -> Dict[str, Any]: """ @@ -19,8 +74,15 @@ class SettingsManager: - 从配置文件读取设置 - 返回设置字典 """ - # TODO: 实现设置加载逻辑 - pass + try: + if os.path.exists(self.config_path): + with open(self.config_path, 'r', encoding='utf-8') as f: + return json.load(f) + else: + return {} + except (json.JSONDecodeError, IOError) as e: + print(f"加载配置文件时出错: {e}") + return {} def save_settings(self, settings: Dict[str, Any]) -> bool: """ @@ -28,8 +90,19 @@ class SettingsManager: - 将设置保存到配置文件 - 返回保存结果 """ - # TODO: 实现设置保存逻辑 - pass + try: + # 确保目录存在 + config_dir = os.path.dirname(self.config_path) + if not os.path.exists(config_dir): + os.makedirs(config_dir) + + # 保存设置到文件 + with open(self.config_path, 'w', encoding='utf-8') as f: + json.dump(settings, f, ensure_ascii=False, indent=4) + return True + except (IOError, TypeError) as e: + print(f"保存配置文件时出错: {e}") + return False def get_setting(self, key: str, default: Any = None) -> Any: """ @@ -37,8 +110,14 @@ class SettingsManager: - 根据键名获取设置值 - 如果不存在返回默认值 """ - # TODO: 实现获取设置项逻辑 - pass + keys = key.split('.') + value = self.settings + try: + for k in keys: + value = value[k] + return value + except (KeyError, TypeError): + return default def set_setting(self, key: str, value: Any) -> bool: """ @@ -46,5 +125,21 @@ class SettingsManager: - 设置指定键的值 - 保存到配置文件 """ - # TODO: 实现设置设置项逻辑 - pass \ No newline at end of file + keys = key.split('.') + setting_dict = self.settings + + # 导航到倒数第二个键 + try: + for k in keys[:-1]: + if k not in setting_dict: + setting_dict[k] = {} + setting_dict = setting_dict[k] + + # 设置最后一个键的值 + setting_dict[keys[-1]] = value + + # 保存到配置文件 + return self.save_settings(self.settings) + except (KeyError, TypeError) as e: + print(f"设置配置项时出错: {e}") + return False \ No newline at end of file diff --git a/src/ui/components.py b/src/ui/components.py index 2763f93..948839f 100644 --- a/src/ui/components.py +++ b/src/ui/components.py @@ -10,12 +10,8 @@ class CustomTitleBar(QWidget): - 添加窗口控制按钮 """ super().__init__(parent) - # TODO: 实现标题栏UI - # 1. 创建标题标签 - # 2. 创建最小化、最大化、关闭按钮 - # 3. 设置布局和样式 - # 4. 连接按钮事件 - pass + self.parent = parent + self.setup_ui() def setup_ui(self): """ @@ -23,42 +19,92 @@ class CustomTitleBar(QWidget): - 初始化所有UI组件 - 设置组件属性和样式 """ - # TODO: 实现UI设置逻辑 - # 1. 创建水平布局 - # 2. 添加标题标签和控制按钮 - # 3. 设置组件样式 - pass + # 创建水平布局 + layout = QHBoxLayout() + layout.setContentsMargins(10, 5, 10, 5) + layout.setSpacing(10) + + # 创建标题标签 + self.title_label = QLabel("MagicWord") + self.title_label.setStyleSheet("color: #333333; font-size: 12px; font-weight: normal;") + + # 创建控制按钮 + self.minimize_button = QPushButton("—") + self.maximize_button = QPushButton("□") + self.close_button = QPushButton("×") + + # 设置按钮样式 + button_style = """ + QPushButton { + background-color: transparent; + border: none; + color: #333333; + font-size: 12px; + font-weight: normal; + width: 30px; + height: 30px; + } + QPushButton:hover { + background-color: #d0d0d0; + } + """ + + self.minimize_button.setStyleSheet(button_style) + self.maximize_button.setStyleSheet(button_style) + self.close_button.setStyleSheet(button_style + "QPushButton:hover { background-color: #ff5555; color: white; }") + + # 添加组件到布局 + layout.addWidget(self.title_label) + layout.addStretch() + layout.addWidget(self.minimize_button) + layout.addWidget(self.maximize_button) + layout.addWidget(self.close_button) + + self.setLayout(layout) + + # 连接按钮事件 + self.minimize_button.clicked.connect(self.minimize_window) + self.maximize_button.clicked.connect(self.maximize_window) + self.close_button.clicked.connect(self.close_window) + + # 设置标题栏样式 + self.setStyleSheet(""" + CustomTitleBar { + background-color: #f0f0f0; + border-top-left-radius: 0px; + border-top-right-radius: 0px; + border-bottom: 1px solid #d0d0d0; + } + """) def minimize_window(self): """ 最小化窗口 - 触发窗口最小化事件 """ - # TODO: 实现窗口最小化逻辑 - # 1. 获取父窗口 - # 2. 调用窗口最小化方法 - pass + if self.parent: + self.parent.showMinimized() def maximize_window(self): """ 最大化窗口 - 切换窗口最大化状态 """ - # TODO: 实现窗口最大化逻辑 - # 1. 获取父窗口 - # 2. 检查当前窗口状态 - # 3. 切换最大化/还原状态 - pass + if self.parent: + if self.parent.isMaximized(): + self.parent.showNormal() + self.maximize_button.setText("□") + else: + self.parent.showMaximized() + self.maximize_button.setText("❐") def close_window(self): """ 关闭窗口 - 触发窗口关闭事件 """ - # TODO: 实现窗口关闭逻辑 - # 1. 获取父窗口 - # 2. 调用窗口关闭方法 - pass + if self.parent: + self.parent.close() class ProgressBarWidget(QWidget): def __init__(self, parent=None): @@ -68,11 +114,69 @@ class ProgressBarWidget(QWidget): - 显示统计信息 """ super().__init__(parent) - # TODO: 实现进度条组件初始化 - # 1. 创建进度条UI元素 - # 2. 创建统计信息标签 - # 3. 设置布局 - pass + self.setup_ui() + + def setup_ui(self): + """ + 设置进度条UI + - 初始化所有UI组件 + - 设置组件属性和样式 + """ + # 创建垂直布局 + layout = QVBoxLayout() + layout.setContentsMargins(10, 10, 10, 10) + layout.setSpacing(5) + + # 导入需要的模块 + from PyQt5.QtWidgets import QProgressBar, QHBoxLayout + + # 创建水平布局用于统计信息 + stats_layout = QHBoxLayout() + stats_layout.setSpacing(15) + + # 创建统计信息标签 + self.wpm_label = QLabel("WPM: 0") + self.accuracy_label = QLabel("准确率: 0%") + self.time_label = QLabel("用时: 0s") + + # 设置标签样式 + label_style = "font-size: 12px; font-weight: normal; color: #333333;" + self.wpm_label.setStyleSheet(label_style) + self.accuracy_label.setStyleSheet(label_style) + self.time_label.setStyleSheet(label_style) + + # 添加标签到统计布局 + stats_layout.addWidget(self.wpm_label) + stats_layout.addWidget(self.accuracy_label) + stats_layout.addWidget(self.time_label) + stats_layout.addStretch() + + # 创建进度条 + self.progress_bar = QProgressBar() + self.progress_bar.setRange(0, 100) + self.progress_bar.setValue(0) + self.progress_bar.setTextVisible(True) + self.progress_bar.setFormat("进度: %p%") + + # 设置进度条样式 + self.progress_bar.setStyleSheet(""" + QProgressBar { + border: 1px solid #c0c0c0; + border-radius: 0px; + text-align: center; + background-color: #f0f0f0; + } + QProgressBar::chunk { + background-color: #0078d7; + border-radius: 0px; + } + """) + + # 添加组件到主布局 + layout.addLayout(stats_layout) + layout.addWidget(self.progress_bar) + + self.setLayout(layout) def update_progress(self, progress: float): """ @@ -80,21 +184,18 @@ class ProgressBarWidget(QWidget): - 设置进度值 - 更新显示 """ - # TODO: 实现进度更新逻辑 - # 1. 更新进度条数值 - # 2. 刷新UI显示 - pass + self.progress_bar.setValue(int(progress)) def update_stats(self, wpm: int, accuracy: float, time_elapsed: int): """ 更新统计信息 - - 显示WPM、准确率、用时等信息 + - wpm: 每分钟字数 + - accuracy: 准确率(%) + - time_elapsed: 用时(秒) """ - # TODO: 实现统计信息更新逻辑 - # 1. 更新WPM标签 - # 2. 更新准确率标签 - # 3. 更新用时标签 - pass + self.wpm_label.setText(f"WPM: {wpm}") + self.accuracy_label.setText(f"准确率: {accuracy:.1f}%") + self.time_label.setText(f"用时: {time_elapsed}s") class TextDisplayWidget(QWidget): def __init__(self, parent=None): @@ -102,47 +203,123 @@ class TextDisplayWidget(QWidget): 文本显示组件 - 显示待练习文本 - 高亮当前字符 - - 显示用户输入 + - 显示用户输入反馈 """ super().__init__(parent) - # TODO: 实现文本显示组件初始化 - # 1. 创建文本显示区域 - # 2. 设置文本样式 - # 3. 初始化高亮相关属性 - pass + self.text_content = "" + self.current_index = 0 + self.setup_ui() + + def setup_ui(self): + """ + 设置文本显示UI + - 初始化文本显示区域 + - 设置样式和布局 + """ + # 创建垂直布局 + layout = QVBoxLayout() + layout.setContentsMargins(20, 20, 20, 20) + + # 导入需要的模块 + from PyQt5.QtWidgets import QTextEdit + from PyQt5.QtCore import Qt + + # 创建文本显示区域 + self.text_display = QTextEdit() + self.text_display.setReadOnly(True) + self.text_display.setLineWrapMode(QTextEdit.WidgetWidth) + + # 设置文本显示样式 + self.text_display.setStyleSheet(""" + QTextEdit { + font-family: 'Calibri', 'Segoe UI', 'Microsoft YaHei', sans-serif; + font-size: 12pt; + border: 1px solid #d0d0d0; + border-radius: 0px; + padding: 15px; + background-color: white; + color: black; + } + """) + + # 添加组件到布局 + layout.addWidget(self.text_display) + self.setLayout(layout) def set_text(self, text: str): """ 设置显示文本 - - 更新显示内容 - - 重置高亮状态 - """ - # TODO: 实现文本设置逻辑 - # 1. 更新内部文本内容 - # 2. 重置高亮位置 - # 3. 刷新UI显示 - pass + - text: 要显示的文本内容 + """ + self.text_content = text + self.current_index = 0 + self._update_display() def highlight_character(self, position: int): """ - 高亮指定位置字符 - - 更新高亮位置 - - 刷新显示 + 高亮指定位置的字符 + - position: 字符位置索引 """ - # TODO: 实现字符高亮逻辑 - # 1. 计算高亮范围 - # 2. 应用高亮样式 - # 3. 滚动到高亮位置 - pass + if 0 <= position < len(self.text_content): + self.current_index = position + self._update_display() + def _update_display(self, user_input: str = ""): + """ + 更新文本显示 + - user_input: 用户输入文本(可选) + """ + # 导入需要的模块 + from PyQt5.QtGui import QTextCursor + import sys + import os + sys.path.append(os.path.join(os.path.dirname(__file__), '..')) + from constants import COLOR_CORRECT, COLOR_WRONG, COLOR_HIGHLIGHT + + if not self.text_content: + self.text_display.clear() + return + + # 创建带格式的HTML文本 + formatted_text = "" + + # 如果有用户输入,对比显示 + if user_input: + for i, char in enumerate(self.text_content): + if i < len(user_input): + if char == user_input[i]: + # 正确字符 + formatted_text += f'{char}' + else: + # 错误字符 + formatted_text += f'{char}' + elif i == len(user_input): + # 当前字符 + formatted_text += f'{char}' + else: + # 未到达的字符 + formatted_text += char + else: + # 没有用户输入,只显示原文和当前高亮字符 + for i, char in enumerate(self.text_content): + if i == self.current_index: + # 当前字符高亮 + formatted_text += f'{char}' + else: + formatted_text += char + + # 更新文本显示 + self.text_display.setHtml(formatted_text) + + # 滚动到当前高亮字符位置 + cursor = self.text_display.textCursor() + cursor.setPosition(min(self.current_index + 5, len(self.text_content))) + self.text_display.setTextCursor(cursor) + self.text_display.ensureCursorVisible() + def show_user_input(self, input_text: str): """ - 显示用户输入 - - 在文本下方显示用户输入 - - 高亮正确/错误字符 + 显示用户输入反馈 + - input_text: 用户输入的文本 """ - # TODO: 实现用户输入显示逻辑 - # 1. 对比用户输入与原文 - # 2. 分别高亮正确和错误字符 - # 3. 更新输入显示区域 - pass \ No newline at end of file + self._update_display(input_text) \ No newline at end of file