feat(ui): Cài đặt ▸ Giới thiệu, gỡ dòng ghi công khỏi thanh trạng thái

Dòng "Made by QuanDH14" là widget thường trực ở góc dưới phải: chiếm một góc
màn hình trên MỌI màn, suốt cả phiên, cho một thông tin chỉ cần đọc một lần.
Chuyển vào Cài đặt ▸ Giới thiệu — vẫn tra được, không còn đứng thường trực.

Mục Giới thiệu đứng CUỐI danh sách: nó không có thiết lập nào để đổi, nên đặt
trước các mục thao tác được sẽ đẩy chúng xuống mà không được gì.

Đặc tả SettingsDialog đổi từ 5 lên 6 mục — thay đổi CÓ CHỦ Ý, không phải tách nhầm.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-10 01:34:36 +09:00
committed by thanhnv
co-authored by Claude Opus 5
parent 19f3ccc7be
commit d4da30f9a6
4 changed files with 163 additions and 17 deletions
+60
View File
@@ -0,0 +1,60 @@
"""Mục "Giới thiệu" trong Cài đặt.
Dòng ghi công tác giả trước đây nằm cố định ở góc dưới phải cửa sổ, dưới dạng
widget thường trực của thanh trạng thái. Chỗ đó chiếm một góc màn hình trên MỌI
màn hình, suốt cả phiên làm việc, cho một thông tin người dùng chỉ cần đọc một
lần. Chuyển vào Cài đặt: vẫn tra được bất cứ lúc nào, nhưng không còn đứng
thường trực trong tầm mắt.
Cùng nhóm widget với bốn mục kia của Cài đặt (``general``/``provider``/
``parameter``/``routing``) nên nó tự là một trang, không cần lắp ráp riêng.
"""
from __future__ import annotations
from PySide6.QtCore import Qt
from PySide6.QtWidgets import QLabel, QVBoxLayout, QWidget
from ... import DISPLAY_NAME, __version__
from ...i18n import tr
class AboutSettingsWidget(QWidget):
"""Nhóm "Giới thiệu": tên ứng dụng và dòng ghi công tác giả."""
def __init__(self, ctx=None, parent: QWidget | None = None) -> None:
"""Trang Giới thiệu. ``ctx`` không dùng tới, giữ cho khớp chữ ký của
bốn widget Cài đặt còn lại."""
super().__init__(parent)
self.ctx = ctx
layout = QVBoxLayout(self)
layout.setContentsMargins(4, 4, 4, 4)
layout.setSpacing(8)
# Tên sản phẩm là danh từ riêng, không dịch — lấy thẳng từ gốc gói,
# cùng nguồn với tiêu đề cửa sổ (main_window.py:90) nên hai chỗ không lệch.
self.app_label = QLabel(f"{DISPLAY_NAME} v{__version__}")
# Không đặt màu ở đây: cỡ chữ là khác biệt duy nhất cần thiết, còn màu
# do theme quyết định (xem theme/__init__.py — ngoài theme/ không file
# nào được đặt tên một màu).
font = self.app_label.font()
font.setPointSize(font.pointSize() + 4)
font.setBold(True)
self.app_label.setFont(font)
layout.addWidget(self.app_label)
self.credit_label = QLabel(tr("app.credit"))
self.credit_label.setObjectName("faint")
self.credit_label.setTextInteractionFlags(Qt.TextSelectableByMouse)
layout.addWidget(self.credit_label)
layout.addStretch(1)
def apply_to(self, data: dict) -> None:
"""Không có thiết lập nào để ghi — mục này chỉ hiển thị.
Vẫn khai để khớp giao diện chung của các trang Cài đặt: ``_save`` gọi
``apply_to`` trên từng trang, nên một trang thiếu hàm này sẽ là
``AttributeError`` ngay lần đầu ai đó thêm nó vào vòng lặp.
"""
return
+16 -11
View File
@@ -163,9 +163,10 @@ class MainWindow(NavRailMixin, RailProjectMixin, TopBarMixin,
self._built.append(widget is not None)
self._build_nav_rail(right, rlay)
# Landing stays Workspace ▸ Project, exactly as before. Go through _goto
# so the page is actually shown — selecting the row alone only moves the
# highlight (its signals are blocked to avoid rebuild loops).
# Land on the Workspace screen. Go through _goto so the page is actually
# shown — selecting the row alone only moves the highlight (its signals
# are blocked to avoid rebuild loops). Which Workspace sub-view the user
# ends up looking at is settled after _restore_sessions(), below.
self._goto(self._ROW_WORKSPACE, self.workspace.current_subtab())
self.toast = Toast(self) # top-left "task done" popup
# Floating in-app Help assistant — a robot icon pinned bottom-right on
@@ -176,14 +177,19 @@ class MainWindow(NavRailMixin, RailProjectMixin, TopBarMixin,
self.help_agent.status_message.connect(self.statusBar().showMessage)
self.statusBar().showMessage(tr("app.status.ready"))
# Author credit, pinned to the bottom-right corner. A permanent status-bar
# widget sits at the right end and is never cleared by showMessage (which
# writes on the left).
self._credit = QLabel(tr("app.credit"))
self._credit.setObjectName("faint")
self._credit.setStyleSheet("padding: 0 10px;")
self.statusBar().addPermanentWidget(self._credit)
# Dòng ghi công tác giả đã chuyển vào Cài đặt ▸ Giới thiệu
# (presentation/settings/about_widget.py). Nó từng là widget thường trực
# ở góc dưới phải: chiếm một góc màn hình trên MỌI màn hình, suốt cả
# phiên, cho một thông tin chỉ cần đọc một lần.
self._restore_sessions()
# Open on "All projects…" — literally the same call the nav rail's link
# of that name makes, so the rail highlight and the content can never
# disagree. This runs AFTER the restore on purpose: _restore_sessions
# still reloads the last thread, because recovering it after a crash is
# the whole point of it, but the user should first see the list of
# everything rather than whichever conversation happened to be open when
# the app was last closed.
self.goto_all_projects()
self._tray.setup()
# Start the task scheduler last, once the whole window exists — it
# catches up any overdue tasks right away (first tick runs inline).
@@ -252,7 +258,6 @@ class MainWindow(NavRailMixin, RailProjectMixin, TopBarMixin,
self._nav_toggle_btn.setText("" if self._nav_collapsed else tr("app.nav.menu_label"))
self._nav_toggle_btn.setToolTip(
tr("app.nav.expand_tooltip") if self._nav_collapsed else tr("app.nav.collapse_tooltip"))
self._credit.setText(tr("app.credit"))
if hasattr(self, "provider_lbl"):
self.provider_lbl.setText(tr("app.provider"))
if hasattr(self, "settings_btn"):