From 3fe38feb0b64844fb6ab32419176728c7c5e135a Mon Sep 17 00:00:00 2001 From: hongwei Date: Thu, 26 Mar 2026 16:57:09 +0800 Subject: [PATCH 1/9] =?UTF-8?q?[202=5F112]=E5=A2=9E=E5=8A=A0=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E6=9B=B4=E6=96=B0=E7=9A=84=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TeXmacs/misc/themes/liii-night.css | 62 +++++++ TeXmacs/misc/themes/liii.css | 62 +++++++ TeXmacs/plugins/lang/dic/en_US/zh_CN.scm | 7 +- TeXmacs/progs/utils/misc/version-update.scm | 90 ++++++++++ devel/202_112.md | 157 ++++++++++++++++++ .../QWindowKit/updatenotificationbar.cpp | 92 ++++++++++ .../QWindowKit/updatenotificationbar.hpp | 41 +++++ src/Plugins/QWindowKit/windowbar.hpp | 6 + src/Plugins/QWindowKit/windowbar_p.hpp | 9 + src/Plugins/Qt/qt_tm_widget.cpp | 128 +++++++++++++- src/Plugins/Qt/qt_tm_widget.hpp | 12 +- 11 files changed, 661 insertions(+), 5 deletions(-) create mode 100644 TeXmacs/progs/utils/misc/version-update.scm create mode 100644 devel/202_112.md create mode 100644 src/Plugins/QWindowKit/updatenotificationbar.cpp create mode 100644 src/Plugins/QWindowKit/updatenotificationbar.hpp diff --git a/TeXmacs/misc/themes/liii-night.css b/TeXmacs/misc/themes/liii-night.css index 9cb40e0a33..50f444c38a 100644 --- a/TeXmacs/misc/themes/liii-night.css +++ b/TeXmacs/misc/themes/liii-night.css @@ -925,6 +925,68 @@ QWidget#auxiliary_container { background-color: rgba(255, 255, 255, 0.2); } +/**************************************************************************** +* 版本更新提示条样式 +****************************************************************************/ +#updateNotificationBar { + background-color: #0d2b4a; + border: 1px solid #1a4a7a; + border-left: none; + border-right: none; + border-top: none; +} + +#updateNotificationMessage { + color: #64b5f6; + font-size: 13px; + font-weight: 500; +} + +#updateNotificationUpdateButton { + background-color: #1976d2; + color: white; + border: none; + border-radius: 4px; + padding: 4px 12px; + font-size: 12px; + font-weight: 500; +} + +#updateNotificationUpdateButton:hover { + background-color: #1565c0; +} + +#updateNotificationSnoozeButton { + background-color: transparent; + border: 1px solid #4a7a9a; + color: #64b5f6; + padding: 4px 12px; + border-radius: 4px; + font-size: 12px; + font-weight: 500; +} + +#updateNotificationSnoozeButton:hover { + background-color: #1a3a5a; +} + +#updateNotificationCloseButton { + background-color: transparent; + color: #64b5f6; + border: none; + font-size: 16px; + font-weight: bold; + border-radius: 4px; + padding: 0; + margin: 0; + min-width: 24px; + min-height: 24px; +} + +#updateNotificationCloseButton:hover { + background-color: rgba(100, 181, 246, 0.1); +} + /**************************************************************************** * 文档编辑区域样式 ****************************************************************************/ diff --git a/TeXmacs/misc/themes/liii.css b/TeXmacs/misc/themes/liii.css index 608d206c23..ef02a1cecc 100644 --- a/TeXmacs/misc/themes/liii.css +++ b/TeXmacs/misc/themes/liii.css @@ -893,6 +893,68 @@ QWidget#auxiliary_container { background-color: rgba(0, 0, 0, 0.2); } +/**************************************************************************** +* 版本更新提示条样式 +****************************************************************************/ +#updateNotificationBar { + background-color: #e3f2fd; + border: 1px solid #bbdefb; + border-left: none; + border-right: none; + border-top: none; +} + +#updateNotificationMessage { + color: #1565c0; + font-size: 13px; + font-weight: 500; +} + +#updateNotificationUpdateButton { + background-color: #1976d2; + color: white; + border: none; + border-radius: 4px; + padding: 4px 12px; + font-size: 12px; + font-weight: 500; +} + +#updateNotificationUpdateButton:hover { + background-color: #1565c0; +} + +#updateNotificationSnoozeButton { + background-color: transparent; + border: 1px solid #90caf9; + color: #1976d2; + padding: 4px 12px; + border-radius: 4px; + font-size: 12px; + font-weight: 500; +} + +#updateNotificationSnoozeButton:hover { + background-color: #e3f2fd; +} + +#updateNotificationCloseButton { + background-color: transparent; + color: #1565c0; + border: none; + font-size: 16px; + font-weight: bold; + border-radius: 4px; + padding: 0; + margin: 0; + min-width: 24px; + min-height: 24px; +} + +#updateNotificationCloseButton:hover { + background-color: rgba(21, 101, 192, 0.1); +} + /*文本工具栏窗口样式*/ QWidget#text_toolbar { background: #ffffff; diff --git a/TeXmacs/plugins/lang/dic/en_US/zh_CN.scm b/TeXmacs/plugins/lang/dic/en_US/zh_CN.scm index 04d1ad03f2..b95c27a9a1 100644 --- a/TeXmacs/plugins/lang/dic/en_US/zh_CN.scm +++ b/TeXmacs/plugins/lang/dic/en_US/zh_CN.scm @@ -2559,4 +2559,9 @@ ("zoom/unzoom" "放大/缩小") ("You are currently in guest mode, login to enable AI, MathOCR,and other features" "您当前处于访客状态,登录激活AI和公式识别等功能") ("Login Now" "立即登录") -("Use extensible brackets" "使用可伸缩括号") \ No newline at end of file +("Use extensible brackets" "使用可伸缩括号") +;; 版本更新提示 +("New version available" "发现新版本") +("current" "当前") +("Update now" "立即更新") +("Remind later" "稍后提醒") diff --git a/TeXmacs/progs/utils/misc/version-update.scm b/TeXmacs/progs/utils/misc/version-update.scm new file mode 100644 index 0000000000..e3329025cf --- /dev/null +++ b/TeXmacs/progs/utils/misc/version-update.scm @@ -0,0 +1,90 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; MODULE : version-update.scm +;; DESCRIPTION : 版本更新检查(开发者配置) +;; COPYRIGHT : (C) 2026 Mogan STEM authors +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(texmacs-module (utils misc version-update)) + +;; ============================================ +;; 开发者配置区(修改此处调整行为) +;; ============================================ +(define SNOOZE-DAYS 3) ; 稍后提醒间隔,单位:天 + +;; Mock 远程版本号(用于测试,设为 #f 则使用真实网络请求) +;; 示例:(define MOCK-REMOTE-VERSION "2026.3.0") +(define MOCK-REMOTE-VERSION "2026.3.0") + +;; 社区版是否显示版本更新提示(用于测试) +(define VERSION-UPDATE-FOR-COMMUNITY #f) + +(tm-define (version-update-for-community?) + (:secure #t) + VERSION-UPDATE-FOR-COMMUNITY) + +(tm-define (set-version-update-for-community! enabled) + (:secure #t) + (set! VERSION-UPDATE-FOR-COMMUNITY enabled)) + +;; ============================================ +;; 内部实现 +;; ============================================ + +;; 获取/设置 Mock 远程版本号(用于测试) +(tm-define (get-mock-remote-version) + (:secure #t) + MOCK-REMOTE-VERSION) + +(tm-define (set-mock-remote-version! version) + (:secure #t) + (set! MOCK-REMOTE-VERSION version)) + +(define LAST-CHECK-KEY "version_last_check") +(define IGNORED-VERSION-KEY "version_ignored") +(define SNOOZE-UNTIL-KEY "version_snooze_until") + +(define (current-timestamp) + (current-time)) + +;; 检查是否应该检查更新(考虑稍后提醒时间) +(tm-define (should-check-version-update?) + (:secure #t) + (let* ((now (current-timestamp)) + (snooze-until (or (persistent-get (get-texmacs-home-path) SNOOZE-UNTIL-KEY) "0")) + (snooze-time (if (== snooze-until "") 0 (string->number snooze-until)))) + (>= now snooze-time))) + +;; 强制清除所有记录(用于测试) +(tm-define (clear-version-update-history) + (:secure #t) + (persistent-remove (get-texmacs-home-path) SNOOZE-UNTIL-KEY) + (persistent-remove (get-texmacs-home-path) IGNORED-VERSION-KEY) + (display "Version update history cleared\n")) + +;; 稍后提醒(使用默认间隔) +(tm-define (snooze-version-update) + (:secure #t) + (let* ((now (current-timestamp)) + (future (+ now (* SNOOZE-DAYS 24 3600)))) + (persistent-set (get-texmacs-home-path) SNOOZE-UNTIL-KEY + (number->string future)))) + +;; 跳过此版本 +(tm-define (ignore-version version) + (:secure #t) + (persistent-set (get-texmacs-home-path) IGNORED-VERSION-KEY version) + (persistent-remove (get-texmacs-home-path) SNOOZE-UNTIL-KEY)) + +;; 检查版本是否被忽略 +(tm-define (is-version-ignored? version) + (:secure #t) + (== (persistent-get (get-texmacs-home-path) IGNORED-VERSION-KEY) version)) + +;; 获取下载页URL +(tm-define (get-update-download-url) + (:secure #t) + (if (== (get-output-language) "chinese") + "https://liiistem.cn/install.html" + "https://liiistem.com/install.html")) diff --git a/devel/202_112.md b/devel/202_112.md new file mode 100644 index 0000000000..0e0b1dc5d3 --- /dev/null +++ b/devel/202_112.md @@ -0,0 +1,157 @@ +# 202_112 版本更新提示功能 + +## 2026年3月26日 + +### 如何测试 + +**步骤1:清除历史记录(如需重置)** +在 Scheme 会话中执行: +```scheme +(clear-version-update-history) +``` + +**步骤2:在 Scheme 会话中配置测试参数** +;; 如果是社区版,先开启版本更新提示,默认设置 Mock 远程版本("2026.3.0" 比当前版本高) +(set-version-update-for-community! #t) + +**步骤3:重启应用**,等待10秒后查看提示条是否显示 + +#### 3. 测试要点 +- 新版本可用时正确显示提示条 +- 点击"立即更新"打开浏览器,提示条不消失 +- 点击"稍后提醒"3天后再次提示 +- 版本号比较正确(如 2026.10.0 > 2026.2.0) +- 社区版通过 Scheme 指令可开启测试 + +--- + +### What +实现版本更新提示功能,当有新版本可用时,在窗口顶部显示提示条,引导用户更新到最新版本。 + +### 功能特性 +1. **自动检查版本** - 启动后延迟10秒自动检查远程版本 +2. **语义化版本比较** - 正确比较版本号(如 2026.10.0 > 2026.2.0) +3. **多语言支持** - 根据语言环境显示不同官网链接 +4. **社区版测试支持** - 通过 Scheme 指令可在社区版开启测试 + +### 用户操作按钮 +- **立即更新** - 打开浏览器跳转到官网下载页,提示条保持显示 +- **稍后提醒** - 3天后(开发者可配置)再次提示 +- **关闭** - 仅隐藏当前会话 + +### 新增文件 +``` +src/Plugins/QWindowKit/updatenotificationbar.hpp +src/Plugins/QWindowKit/updatenotificationbar.cpp +TeXmacs/progs/utils/misc/version-update.scm +``` + +### 修改文件 +``` +src/Plugins/Qt/qt_tm_widget.hpp +src/Plugins/Qt/qt_tm_widget.cpp +TeXmacs/misc/themes/liii.css +TeXmacs/misc/themes/liii-night.css +TeXmacs/plugins/lang/dic/en_US/zh_CN.scm +``` + +### 开发者配置 +在 `TeXmacs/progs/utils/misc/version-update.scm` 中: + +```scheme +;; 配置稍后提醒间隔(单位:天) +(define SNOOZE-DAYS 3) + +;; Mock 远程版本用于测试 +(define MOCK-REMOTE-VERSION "2026.3.0") + +;; 社区版开启版本更新提示(用于测试) +(set-version-update-for-community! #t) +``` + +### Scheme 控制接口 +```scheme +(use-modules (utils misc version-update)) + +;; 检查是否应该检查更新 +(should-check-version-update?) + +;; Mock 版本控制(用于测试) +(get-mock-remote-version) +(set-mock-remote-version! "2026.3.0") + +;; 稍后提醒 +(snooze-version-update) + +;; 清除所有记录 +(clear-version-update-history) + +;; 社区版控制 +(version-update-for-community?) +(set-version-update-for-community! #t) +``` + +### UI 布局 +版本更新提示条和登录提示条垂直堆叠显示: +``` +┌─────────────────────────────────────────┐ +│ 🎉 发现新版本 v2026.3.0(当前 v2026.2.1)│ +│ [立即更新] [稍后提醒] [×] │ +├─────────────────────────────────────────┤ +│ 访客登录提示条(如有) │ +│ [立即登录] [×] │ +└─────────────────────────────────────────┘ +``` + +### 官网链接 +- 中文:`https://liiistem.cn/install.html` +- 英文:`https://liiistem.com/install.html` + +### 记录存储位置 +| 平台 | 路径 | +|------|------| +| macOS | `~/Library/Application Support/moganlab/system/_/` | +| Linux | `~/.local/share/moganlab/system/_/` | +| Windows | `%APPDATA%/moganlab/system/_/` | + +### 提示显示判定逻辑 + +版本更新提示条的显示需要满足以下条件(按顺序检查): + +``` +应用启动 + ↓ +延迟10秒 + ↓ +检查商业版/社区版开关 ──否──→ 结束(不显示) + ↓ 是(商业版 或 社区版已开启测试) +检查稍后提醒时间 ──否──→ 结束(不显示) + ↓ 是(当前时间 > 设置的稍后提醒时间) +获取远程版本号(Mock优先) + ↓ +语义化版本比较(只比较前三位数字) + ↓ +远程版本 > 本地版本 ──否──→ 结束(不显示) + ↓ 是 +显示提示条 +``` + +**关键判定条件:** + +| 检查项 | 说明 | Scheme变量/函数 | +|--------|------|-----------------| +| 社区版开关 | 社区版默认关闭,需手动开启 | `VERSION-UPDATE-FOR-COMMUNITY` | +| 稍后提醒时间 | 用户点击"稍后提醒"后记录的时间戳 | `version_snooze_until` | +| 版本号比较 | 取前三位数字比较,如 `2026.10.0` vs `2026.2.1` | `isVersionNewer()` | + +**注意:** 目前没有"跳过此版本"功能,用户只能选择"稍后提醒"或保持提示条显示。 + +### Why +帮助用户及时获取最新版本,提升用户体验和软件安全性。 + +### How +1. 启动后延迟10秒检查版本 +2. Mock 版本优先于网络请求(用于测试) +3. 语义化版本号比较(取前三位数字) +4. 商业版默认开启,社区版可通过 Scheme 指令测试 +5. 用户操作后记录状态到本地持久化存储 diff --git a/src/Plugins/QWindowKit/updatenotificationbar.cpp b/src/Plugins/QWindowKit/updatenotificationbar.cpp new file mode 100644 index 0000000000..df6314f9ea --- /dev/null +++ b/src/Plugins/QWindowKit/updatenotificationbar.cpp @@ -0,0 +1,92 @@ +/*****************************************************************************/ +/* MODULE : updatenotificationbar.cpp */ +/* DESCRIPTION : Version update notification bar (horizontal layout) */ +/* COPYRIGHT : (C) 2026 Mogan STEM authors */ +/*****************************************************************************/ + +#include "updatenotificationbar.hpp" +#include "qt_utilities.hpp" + +#include + +UpdateNotificationBar::UpdateNotificationBar (QWidget* parent) + : QFrame (parent) { + setupUI (); +} + +UpdateNotificationBar::~UpdateNotificationBar ()= default; + +void +UpdateNotificationBar::setupUI () { + // 主布局(横条) + m_layout= new QHBoxLayout (this); + m_layout->setContentsMargins (12, 8, 12, 8); + m_layout->setSpacing (0); + + // 左侧 stretch(将内容推向中间) + m_layout->addStretch (1); + + // 图标 🎉 + m_iconLabel= new QLabel (this); + m_iconLabel->setText ("🎉"); + m_iconLabel->setStyleSheet ("font-size: 16px; margin-right: 8px;"); + m_layout->addWidget (m_iconLabel); + + // 提示文字(居中对齐) + m_messageLabel= new QLabel (this); + m_messageLabel->setObjectName ("updateNotificationMessage"); + m_messageLabel->setAlignment (Qt::AlignCenter | Qt::AlignVCenter); + m_messageLabel->setWordWrap (false); + m_layout->addWidget (m_messageLabel); + + // 按钮容器 + QWidget* btnWidget= new QWidget (this); + QHBoxLayout* btnLayout= new QHBoxLayout (btnWidget); + btnLayout->setContentsMargins (0, 0, 0, 0); + btnLayout->setSpacing (8); + + // 立即更新按钮 + m_updateNowBtn= new QPushButton (qt_translate ("Update now"), btnWidget); + m_updateNowBtn->setObjectName ("updateNotificationUpdateButton"); + m_updateNowBtn->setCursor (Qt::PointingHandCursor); + connect (m_updateNowBtn, &QPushButton::clicked, this, + &UpdateNotificationBar::updateNowRequested); + btnLayout->addWidget (m_updateNowBtn); + + // 稍后提醒按钮 + m_snoozeBtn= new QPushButton (qt_translate ("Remind later"), btnWidget); + m_snoozeBtn->setObjectName ("updateNotificationSnoozeButton"); + m_snoozeBtn->setCursor (Qt::PointingHandCursor); + connect (m_snoozeBtn, &QPushButton::clicked, this, + &UpdateNotificationBar::snoozeRequested); + btnLayout->addWidget (m_snoozeBtn); + + m_layout->addWidget (btnWidget); + + // 右侧 stretch(与左侧对称,将内容推向中间) + m_layout->addStretch (1); + + // 关闭按钮 + m_closeBtn= new QPushButton ("×", this); + m_closeBtn->setObjectName ("updateNotificationCloseButton"); + m_closeBtn->setCursor (Qt::PointingHandCursor); + m_closeBtn->setFixedSize (24, 24); + m_closeBtn->setStyleSheet ("text-align: center; font-size: 18px;"); + connect (m_closeBtn, &QPushButton::clicked, this, + &UpdateNotificationBar::closeRequested); + m_layout->addWidget (m_closeBtn); + + // 对象名(用于样式表) + setObjectName ("updateNotificationBar"); +} + +void +UpdateNotificationBar::setVersionInfo (const QString& currentVersion, + const QString& remoteVersion) { + QString msg= QString ("%1 v%2 (%3: v%4)") + .arg (qt_translate ("New version available")) + .arg (remoteVersion) + .arg (qt_translate ("current")) + .arg (currentVersion); + m_messageLabel->setText (msg); +} diff --git a/src/Plugins/QWindowKit/updatenotificationbar.hpp b/src/Plugins/QWindowKit/updatenotificationbar.hpp new file mode 100644 index 0000000000..8ea43d2db2 --- /dev/null +++ b/src/Plugins/QWindowKit/updatenotificationbar.hpp @@ -0,0 +1,41 @@ +/*****************************************************************************/ +/* MODULE : updatenotificationbar.hpp */ +/* DESCRIPTION : Version update notification bar (horizontal layout) */ +/* COPYRIGHT : (C) 2026 Mogan STEM authors */ +/*****************************************************************************/ + +#ifndef UPDATENOTIFICATIONBAR_H +#define UPDATENOTIFICATIONBAR_H + +#include +#include +#include +#include + +class UpdateNotificationBar : public QFrame { + Q_OBJECT + +public: + explicit UpdateNotificationBar (QWidget* parent= nullptr); + ~UpdateNotificationBar (); + + void setVersionInfo (const QString& currentVersion, + const QString& remoteVersion); + +signals: + void updateNowRequested (); + void snoozeRequested (); + void closeRequested (); + +private: + void setupUI (); + + QHBoxLayout* m_layout; + QLabel* m_iconLabel; + QLabel* m_messageLabel; + QPushButton* m_updateNowBtn; + QPushButton* m_snoozeBtn; + QPushButton* m_closeBtn; +}; + +#endif // UPDATENOTIFICATIONBAR_H diff --git a/src/Plugins/QWindowKit/windowbar.hpp b/src/Plugins/QWindowKit/windowbar.hpp index 5d993b6369..e8f8e7c9e8 100644 --- a/src/Plugins/QWindowKit/windowbar.hpp +++ b/src/Plugins/QWindowKit/windowbar.hpp @@ -13,6 +13,8 @@ namespace QWK { class WindowBarPrivate; +class GuestNotificationBar; +class UpdateNotificationBar; class WindowBar : public QFrame { Q_OBJECT @@ -32,6 +34,10 @@ class WindowBar : public QFrame { QAbstractButton* maxButton () const; QAbstractButton* closeButton () const; + // Notification bars + GuestNotificationBar* guestNotificationBar () const; + UpdateNotificationBar* updateNotificationBar () const; + void setMenuBar (QMenuBar* menuBar); void setTitleLabel (QLabel* label); void setTitleWidget (QWidget* widget); // 新接口:支持任意QWidget diff --git a/src/Plugins/QWindowKit/windowbar_p.hpp b/src/Plugins/QWindowKit/windowbar_p.hpp index 90ebefea37..7b49325499 100644 --- a/src/Plugins/QWindowKit/windowbar_p.hpp +++ b/src/Plugins/QWindowKit/windowbar_p.hpp @@ -11,6 +11,9 @@ namespace QWK { +class GuestNotificationBar; +class UpdateNotificationBar; + class WindowBarPrivate { Q_DECLARE_PUBLIC (WindowBar) public: @@ -38,6 +41,12 @@ class WindowBarPrivate { QHBoxLayout* layout; + // Notification bars container (vertical layout) + QWidget* notificationContainer; + QVBoxLayout* notificationLayout; + GuestNotificationBar* guestNotificationBar; + UpdateNotificationBar* updateNotificationBar; + inline QWidget* widgetAt (int index) const { return layout->itemAt (index)->widget (); } diff --git a/src/Plugins/Qt/qt_tm_widget.cpp b/src/Plugins/Qt/qt_tm_widget.cpp index 1c16cf6c35..8ce707d2ad 100644 --- a/src/Plugins/Qt/qt_tm_widget.cpp +++ b/src/Plugins/Qt/qt_tm_widget.cpp @@ -335,8 +335,20 @@ qt_tm_widget_rep::qt_tm_widget_rep (int mask, command _quit) QObject::connect (loginButton, &QWK::LoginButton::clicked, [this] () { checkLocalTokenAndLogin (); }); - // 初始化访客提示条 - guestNotificationBar= new QWK::GuestNotificationBar (mw); + // 创建通知条容器(垂直布局,放在标题栏下方) + QWidget* notificationContainer= new QWidget (mw); + QVBoxLayout* notificationLayout = new QVBoxLayout (notificationContainer); + notificationLayout->setContentsMargins (0, 0, 0, 0); + notificationLayout->setSpacing (0); + + // 初始化版本更新提示条(在上) + updateNotificationBar= new UpdateNotificationBar (); + notificationLayout->addWidget (updateNotificationBar); + updateNotificationBar->hide (); + + // 初始化访客提示条(在下) + guestNotificationBar= new QWK::GuestNotificationBar (); + notificationLayout->addWidget (guestNotificationBar); // 连接提示条信号 QObject::connect (guestNotificationBar, @@ -362,6 +374,27 @@ qt_tm_widget_rep::qt_tm_widget_rep (int mask, command _quit) checkNetworkAvailable (); } + // 连接版本更新提示条信号 + QObject::connect (updateNotificationBar, + &UpdateNotificationBar::updateNowRequested, [this] () { + eval ("(use-modules (utils misc version-update))"); + string url= as_string (call ("get-update-download-url")); + open_url (url); + // 不隐藏提示条,保持显示直到用户实际更新版本 + }); + QObject::connect (updateNotificationBar, + &UpdateNotificationBar::snoozeRequested, [this] () { + eval ("(use-modules (utils misc version-update))"); + call ("snooze-version-update"); + updateNotificationBar->hide (); + }); + QObject::connect (updateNotificationBar, + &UpdateNotificationBar::closeRequested, + [this] () { updateNotificationBar->hide (); }); + + // 延迟检查版本更新(启动后10秒) + QTimer::singleShot (10000, [this] () { checkVersionUpdate (); }); + // there is a bug in the early implementation of toolbars in Qt 4.6 // which has been fixed in 4.6.2 (at least) // this is why we change dimension of icons @@ -519,7 +552,8 @@ qt_tm_widget_rep::qt_tm_widget_rep (int mask, command _quit) QWidget* q= main_widget->as_qwidget (); // force creation of QWidget q->setParent ( qwid); // q->layout()->removeWidget(q) will reset the parent to this - bl->addWidget (guestNotificationBar); // 添加访客提示条 + bl->addWidget ( + notificationContainer); // 添加通知容器(包含版本更新和访客提示条) bl->addWidget (q); mw->setCentralWidget (cw); @@ -2236,3 +2270,91 @@ qt_tm_widget_rep::checkNetworkAvailable () { } }); } + +// 检查版本更新,根据条件显示提示条 +// 流程:1.检查商业版/社区版开关 -> 2.检查稍后提醒时间 -> 3.获取远程版本 +// -> 4.比较并显示 +void +qt_tm_widget_rep::checkVersionUpdate () { + eval ("(use-modules (utils misc version-update))"); + + // 非商业版且未开启社区版测试开关时不检查 + bool forCommunity= as_bool (call ("version-update-for-community?")); + if (is_community_stem () && !forCommunity) return; + + // 检查是否处于稍后提醒期间 + bool shouldCheck= as_bool (call ("should-check-version-update?")); + if (!shouldCheck) return; + + // 检查是否有 mock 版本(用于测试) + object mockVersion= call ("get-mock-remote-version"); + bool hasMock = !is_bool (mockVersion) || as_bool (mockVersion); + + if (hasMock) { + // 使用 mock 版本进行测试 + QString remoteVersion= to_qstring (as_string (mockVersion)); + QString localVersion = XMACS_VERSION; + + if (isVersionNewer (remoteVersion, localVersion)) { + m_remoteVersion= remoteVersion; + updateNotificationBar->setVersionInfo (localVersion, remoteVersion); + updateNotificationBar->show (); + } + return; + } + + // 发送HTTP请求获取远程版本 + QNetworkAccessManager* manager= new QNetworkAccessManager (mainwindow ()); + QNetworkRequest request ( + QUrl ("https://liiistem.cn/mogan_latest_version.tm")); + request.setRawHeader ("User-Agent", + to_qstring (stem_user_agent ()).toUtf8 ()); + + QNetworkReply* reply= manager->get (request); + QObject::connect (reply, &QNetworkReply::finished, [this, reply, manager] () { + if (reply->error () == QNetworkReply::NoError) { + QByteArray data = reply->readAll (); + QString remoteVersion= parseVersionFromTM (data); + QString localVersion = XMACS_VERSION; + + if (isVersionNewer (remoteVersion, localVersion)) { + m_remoteVersion= remoteVersion; + updateNotificationBar->setVersionInfo (localVersion, remoteVersion); + updateNotificationBar->show (); + } + } + reply->deleteLater (); + manager->deleteLater (); + }); +} + +QString +qt_tm_widget_rep::parseVersionFromTM (const QByteArray& data) { + QString content= QString::fromUtf8 (data); + // 简单解析 标签内容 + QRegularExpression re ("\\s*([\\d\\.\\-rc]+)"); + QRegularExpressionMatch match= re.match (content); + return match.captured (1).trimmed (); +} + +bool +qt_tm_widget_rep::isVersionNewer (const QString& remote, const QString& local) { + // 提取纯数字版本号(去掉 -rcX 后缀) + QString remoteClean= remote.split ("-")[0]; + QString localClean = local.split ("-")[0]; + + // 语义化版本号比较(只比较前三位) + QStringList remoteParts= remoteClean.split ("."); + QStringList localParts = localClean.split ("."); + + // 只比较前三位版本号 + for (int i= 0; i < 3; i++) { + int remoteNum= (i < remoteParts.size ()) ? remoteParts[i].toInt () : 0; + int localNum = (i < localParts.size ()) ? localParts[i].toInt () : 0; + + if (remoteNum != localNum) { + return remoteNum > localNum; + } + } + return false; // 版本相同 +} diff --git a/src/Plugins/Qt/qt_tm_widget.hpp b/src/Plugins/Qt/qt_tm_widget.hpp index 7a489ce41a..c4850eea50 100644 --- a/src/Plugins/Qt/qt_tm_widget.hpp +++ b/src/Plugins/Qt/qt_tm_widget.hpp @@ -33,6 +33,7 @@ #include "../QWindowKit/guestnotificationbar.hpp" #include "../QWindowKit/loginbutton.hpp" #include "../QWindowKit/logindialog.hpp" +#include "../QWindowKit/updatenotificationbar.hpp" #include "../QWindowKit/windowbar.hpp" #include "../QWindowKit/windowbutton.hpp" #include @@ -80,7 +81,8 @@ class qt_tm_widget_rep : public qt_window_widget_rep { QTMTabPageContainer* tabPageContainer; QTMAuxiliaryWidget* auxiliaryWidget; QWK::WidgetWindowAgent* windowAgent; - QWK::GuestNotificationBar* guestNotificationBar; // 新增:访客提示条 + QWK::GuestNotificationBar* guestNotificationBar; // 访客提示条 + UpdateNotificationBar* updateNotificationBar; // 版本更新提示条 QWK::LoginButton* loginButton; QWK::LoginDialog* m_loginDialog; QLabel* avatarLabel; @@ -90,6 +92,7 @@ class qt_tm_widget_rep : public qt_window_widget_rep { QLabel* membershipTitleLabel; QPushButton* loginActionButton; QPushButton* logoutButton; + QString m_remoteVersion; // 远程版本号 #ifdef Q_OS_MAC QToolBar* dumbToolBar; @@ -124,6 +127,13 @@ class qt_tm_widget_rep : public qt_window_widget_rep { void showNotLoggedInDialog (const QString& errorMessage); void logout (); + // Version update notification + void setupUpdateNotificationBar (); + void checkVersionUpdate (); + QString parseVersionFromTM (const QByteArray& data); + void showUpdateNotification (const QString& version); + bool isVersionNewer (const QString& remote, const QString& local); + qt_widget main_widget; qt_widget main_menu_widget; qt_widget waiting_main_menu_widget; From 098a5fded405ba444befa77aaf49179d92d2abb6 Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 1 Apr 2026 10:51:39 +0800 Subject: [PATCH 2/9] =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=A4=BE=E5=8C=BA?= =?UTF-8?q?=E7=89=88=E7=9A=84=E6=9B=B4=E6=96=B0=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TeXmacs/progs/utils/misc/version-update.scm | 24 +++++++--------- devel/202_112.md | 32 ++++++++------------- src/Plugins/Qt/qt_tm_widget.cpp | 8 ++---- 3 files changed, 24 insertions(+), 40 deletions(-) diff --git a/TeXmacs/progs/utils/misc/version-update.scm b/TeXmacs/progs/utils/misc/version-update.scm index e3329025cf..75e35c4b63 100644 --- a/TeXmacs/progs/utils/misc/version-update.scm +++ b/TeXmacs/progs/utils/misc/version-update.scm @@ -17,17 +17,6 @@ ;; 示例:(define MOCK-REMOTE-VERSION "2026.3.0") (define MOCK-REMOTE-VERSION "2026.3.0") -;; 社区版是否显示版本更新提示(用于测试) -(define VERSION-UPDATE-FOR-COMMUNITY #f) - -(tm-define (version-update-for-community?) - (:secure #t) - VERSION-UPDATE-FOR-COMMUNITY) - -(tm-define (set-version-update-for-community! enabled) - (:secure #t) - (set! VERSION-UPDATE-FOR-COMMUNITY enabled)) - ;; ============================================ ;; 内部实现 ;; ============================================ @@ -83,8 +72,15 @@ (== (persistent-get (get-texmacs-home-path) IGNORED-VERSION-KEY) version)) ;; 获取下载页URL +;; 社区版跳转到 mogan.app,商业版跳转到 liiistem.cn/com (tm-define (get-update-download-url) (:secure #t) - (if (== (get-output-language) "chinese") - "https://liiistem.cn/install.html" - "https://liiistem.com/install.html")) + (if (community-stem?) + ;; 社区版官网 + (if (== (get-output-language) "chinese") + "https://mogan.app/zh/" + "https://mogan.app/en/") + ;; 商业版官网 + (if (== (get-output-language) "chinese") + "https://liiistem.cn/install.html" + "https://liiistem.com/install.html"))) diff --git a/devel/202_112.md b/devel/202_112.md index 0e0b1dc5d3..bde6002229 100644 --- a/devel/202_112.md +++ b/devel/202_112.md @@ -10,18 +10,17 @@ (clear-version-update-history) ``` -**步骤2:在 Scheme 会话中配置测试参数** -;; 如果是社区版,先开启版本更新提示,默认设置 Mock 远程版本("2026.3.0" 比当前版本高) -(set-version-update-for-community! #t) +**步骤2:重启应用**,等待10秒后查看提示条是否显示 -**步骤3:重启应用**,等待10秒后查看提示条是否显示 +(默认使用 Mock 远程版本 "2026.3.0" 进行测试,可在 `version-update.scm` 中修改 `MOCK-REMOTE-VERSION` 值) #### 3. 测试要点 - 新版本可用时正确显示提示条 - 点击"立即更新"打开浏览器,提示条不消失 - 点击"稍后提醒"3天后再次提示 - 版本号比较正确(如 2026.10.0 > 2026.2.0) -- 社区版通过 Scheme 指令可开启测试 +- 社区版和商业版都显示版本更新提示 +- 社区版跳转到 mogan.app,商业版跳转到 liiistem.cn/com --- @@ -32,7 +31,7 @@ 1. **自动检查版本** - 启动后延迟10秒自动检查远程版本 2. **语义化版本比较** - 正确比较版本号(如 2026.10.0 > 2026.2.0) 3. **多语言支持** - 根据语言环境显示不同官网链接 -4. **社区版测试支持** - 通过 Scheme 指令可在社区版开启测试 +4. **双版本支持** - 社区版和商业版都显示版本更新提示,但跳转到不同官网 ### 用户操作按钮 - **立即更新** - 打开浏览器跳转到官网下载页,提示条保持显示 @@ -62,11 +61,8 @@ TeXmacs/plugins/lang/dic/en_US/zh_CN.scm ;; 配置稍后提醒间隔(单位:天) (define SNOOZE-DAYS 3) -;; Mock 远程版本用于测试 +;; Mock 远程版本用于测试(设为 #f 则使用真实网络请求) (define MOCK-REMOTE-VERSION "2026.3.0") - -;; 社区版开启版本更新提示(用于测试) -(set-version-update-for-community! #t) ``` ### Scheme 控制接口 @@ -85,10 +81,6 @@ TeXmacs/plugins/lang/dic/en_US/zh_CN.scm ;; 清除所有记录 (clear-version-update-history) - -;; 社区版控制 -(version-update-for-community?) -(set-version-update-for-community! #t) ``` ### UI 布局 @@ -104,8 +96,11 @@ TeXmacs/plugins/lang/dic/en_US/zh_CN.scm ``` ### 官网链接 -- 中文:`https://liiistem.cn/install.html` -- 英文:`https://liiistem.com/install.html` + +| 版本 | 中文 | 英文 | +|------|------|------| +| 社区版 | `https://mogan.app/zh/` | `https://mogan.app/en/` | +| 商业版 | `https://liiistem.cn/install.html` | `https://liiistem.com/install.html` | ### 记录存储位置 | 平台 | 路径 | @@ -123,8 +118,6 @@ TeXmacs/plugins/lang/dic/en_US/zh_CN.scm ↓ 延迟10秒 ↓ -检查商业版/社区版开关 ──否──→ 结束(不显示) - ↓ 是(商业版 或 社区版已开启测试) 检查稍后提醒时间 ──否──→ 结束(不显示) ↓ 是(当前时间 > 设置的稍后提醒时间) 获取远程版本号(Mock优先) @@ -140,7 +133,6 @@ TeXmacs/plugins/lang/dic/en_US/zh_CN.scm | 检查项 | 说明 | Scheme变量/函数 | |--------|------|-----------------| -| 社区版开关 | 社区版默认关闭,需手动开启 | `VERSION-UPDATE-FOR-COMMUNITY` | | 稍后提醒时间 | 用户点击"稍后提醒"后记录的时间戳 | `version_snooze_until` | | 版本号比较 | 取前三位数字比较,如 `2026.10.0` vs `2026.2.1` | `isVersionNewer()` | @@ -153,5 +145,5 @@ TeXmacs/plugins/lang/dic/en_US/zh_CN.scm 1. 启动后延迟10秒检查版本 2. Mock 版本优先于网络请求(用于测试) 3. 语义化版本号比较(取前三位数字) -4. 商业版默认开启,社区版可通过 Scheme 指令测试 +4. 社区版和商业版都显示版本更新提示,根据版本类型跳转到不同官网 5. 用户操作后记录状态到本地持久化存储 diff --git a/src/Plugins/Qt/qt_tm_widget.cpp b/src/Plugins/Qt/qt_tm_widget.cpp index 8ce707d2ad..edcda47aa5 100644 --- a/src/Plugins/Qt/qt_tm_widget.cpp +++ b/src/Plugins/Qt/qt_tm_widget.cpp @@ -2272,16 +2272,12 @@ qt_tm_widget_rep::checkNetworkAvailable () { } // 检查版本更新,根据条件显示提示条 -// 流程:1.检查商业版/社区版开关 -> 2.检查稍后提醒时间 -> 3.获取远程版本 -// -> 4.比较并显示 +// 流程:1.检查稍后提醒时间 -> 2.获取远程版本 -> 3.比较并显示 +// 社区版和商业版都显示版本更新提示,但跳转到不同的官网 void qt_tm_widget_rep::checkVersionUpdate () { eval ("(use-modules (utils misc version-update))"); - // 非商业版且未开启社区版测试开关时不检查 - bool forCommunity= as_bool (call ("version-update-for-community?")); - if (is_community_stem () && !forCommunity) return; - // 检查是否处于稍后提醒期间 bool shouldCheck= as_bool (call ("should-check-version-update?")); if (!shouldCheck) return; From 584ede34608bfa7867b375ee1fae690fc54b3921 Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 1 Apr 2026 11:55:52 +0800 Subject: [PATCH 3/9] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20mock=20=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TeXmacs/progs/utils/misc/version-update.scm | 35 +++++++++-------- devel/202_112.md | 38 ++++++++++++------- .../QWindowKit/updatenotificationbar.cpp | 4 ++ .../QWindowKit/updatenotificationbar.hpp | 4 ++ src/Plugins/Qt/qt_tm_widget.cpp | 8 ++-- src/Plugins/Qt/qt_tm_widget.hpp | 4 +- 6 files changed, 55 insertions(+), 38 deletions(-) diff --git a/TeXmacs/progs/utils/misc/version-update.scm b/TeXmacs/progs/utils/misc/version-update.scm index 75e35c4b63..3f48dfe5bb 100644 --- a/TeXmacs/progs/utils/misc/version-update.scm +++ b/TeXmacs/progs/utils/misc/version-update.scm @@ -15,24 +15,35 @@ ;; Mock 远程版本号(用于测试,设为 #f 则使用真实网络请求) ;; 示例:(define MOCK-REMOTE-VERSION "2026.3.0") -(define MOCK-REMOTE-VERSION "2026.3.0") +(define MOCK-REMOTE-VERSION #f) ;; ============================================ ;; 内部实现 ;; ============================================ -;; 获取/设置 Mock 远程版本号(用于测试) +;; 获取 Mock 远程版本号(优先从持久化存储读取) (tm-define (get-mock-remote-version) (:secure #t) - MOCK-REMOTE-VERSION) + (let ((stored (persistent-get (get-texmacs-home-path) MOCK-VERSION-KEY))) + (if (and stored (!= stored "")) + stored + MOCK-REMOTE-VERSION))) +;; 设置 Mock 远程版本号(同时保存到持久化存储) (tm-define (set-mock-remote-version! version) (:secure #t) - (set! MOCK-REMOTE-VERSION version)) + (set! MOCK-REMOTE-VERSION version) + (persistent-set (get-texmacs-home-path) MOCK-VERSION-KEY version)) + +;; 清除 Mock 远程版本号(恢复默认 #f) +(tm-define (clear-mock-remote-version) + (:secure #t) + (set! MOCK-REMOTE-VERSION #f) + (persistent-remove (get-texmacs-home-path) MOCK-VERSION-KEY)) (define LAST-CHECK-KEY "version_last_check") -(define IGNORED-VERSION-KEY "version_ignored") (define SNOOZE-UNTIL-KEY "version_snooze_until") +(define MOCK-VERSION-KEY "version_mock_remote") (define (current-timestamp) (current-time)) @@ -49,8 +60,7 @@ (tm-define (clear-version-update-history) (:secure #t) (persistent-remove (get-texmacs-home-path) SNOOZE-UNTIL-KEY) - (persistent-remove (get-texmacs-home-path) IGNORED-VERSION-KEY) - (display "Version update history cleared\n")) + (clear-mock-remote-version)) ;; 稍后提醒(使用默认间隔) (tm-define (snooze-version-update) @@ -60,17 +70,6 @@ (persistent-set (get-texmacs-home-path) SNOOZE-UNTIL-KEY (number->string future)))) -;; 跳过此版本 -(tm-define (ignore-version version) - (:secure #t) - (persistent-set (get-texmacs-home-path) IGNORED-VERSION-KEY version) - (persistent-remove (get-texmacs-home-path) SNOOZE-UNTIL-KEY)) - -;; 检查版本是否被忽略 -(tm-define (is-version-ignored? version) - (:secure #t) - (== (persistent-get (get-texmacs-home-path) IGNORED-VERSION-KEY) version)) - ;; 获取下载页URL ;; 社区版跳转到 mogan.app,商业版跳转到 liiistem.cn/com (tm-define (get-update-download-url) diff --git a/devel/202_112.md b/devel/202_112.md index bde6002229..27cb4d6842 100644 --- a/devel/202_112.md +++ b/devel/202_112.md @@ -4,17 +4,29 @@ ### 如何测试 -**步骤1:清除历史记录(如需重置)** -在 Scheme 会话中执行: +#### 步骤1:设置 Mock 版本 +1. 因为测试版本一般都是最新的,测试版本号比远程获取的大,所以需要模拟一个更大的远程版本,在 Scheme 会话中执行: ```scheme -(clear-version-update-history) +(set-mock-remote-version! "2026.3.0") ``` -**步骤2:重启应用**,等待10秒后查看提示条是否显示 +#### 步骤2:重启应用&检查功能 +1. 重启应用后,等待10秒后查看提示条是否显示 +2. 点击立即更新,看是否跳转到mogan 官网(社区版跳转到 mogan 官网,商业版跳转到 liii stem 官网) +3. 点击稍后提示,看提示条是否消失(稍后提示 3 天后再提醒) -(默认使用 Mock 远程版本 "2026.3.0" 进行测试,可在 `version-update.scm` 中修改 `MOCK-REMOTE-VERSION` 值) +#### 步骤3:再次重启应用&清除记录 +1. 重启应用,等待 10 秒后查看是否无提示条显示(上面点击了稍后提醒,不应该显示) +```scheme +;; 查看存储的稍后提醒时间戳(Unix时间) +(persistent-get (get-texmacs-home-path) "version_snooze_until") +``` +2. 清除mock remote version 的设定和稍后提示的缓存标记 +```scheme +(clear-version-update-history) +``` -#### 3. 测试要点 +### 测试要点 - 新版本可用时正确显示提示条 - 点击"立即更新"打开浏览器,提示条不消失 - 点击"稍后提醒"3天后再次提示 @@ -60,26 +72,24 @@ TeXmacs/plugins/lang/dic/en_US/zh_CN.scm ```scheme ;; 配置稍后提醒间隔(单位:天) (define SNOOZE-DAYS 3) - -;; Mock 远程版本用于测试(设为 #f 则使用真实网络请求) -(define MOCK-REMOTE-VERSION "2026.3.0") ``` ### Scheme 控制接口 ```scheme (use-modules (utils misc version-update)) -;; 检查是否应该检查更新 +;; 检查是否应该检查更新(设置了稍后提醒不检查更新,否则检查更新) (should-check-version-update?) -;; Mock 版本控制(用于测试) -(get-mock-remote-version) -(set-mock-remote-version! "2026.3.0") +;; Mock 版本控制(用于测试,持久化存储,重启后生效) +(get-mock-remote-version) ; 查看当前 mock 版本 +(set-mock-remote-version! "2026.3.0") ; 设置 mock 版本,重启后生效 +(clear-mock-remote-version) ; 清除 mock 版本,恢复真实网络请求 ;; 稍后提醒 (snooze-version-update) -;; 清除所有记录 +;; 清除所有记录(包括 mock 版本) (clear-version-update-history) ``` diff --git a/src/Plugins/QWindowKit/updatenotificationbar.cpp b/src/Plugins/QWindowKit/updatenotificationbar.cpp index df6314f9ea..b1cb6d0705 100644 --- a/src/Plugins/QWindowKit/updatenotificationbar.cpp +++ b/src/Plugins/QWindowKit/updatenotificationbar.cpp @@ -9,6 +9,8 @@ #include +namespace QWK { + UpdateNotificationBar::UpdateNotificationBar (QWidget* parent) : QFrame (parent) { setupUI (); @@ -90,3 +92,5 @@ UpdateNotificationBar::setVersionInfo (const QString& currentVersion, .arg (currentVersion); m_messageLabel->setText (msg); } + +} // namespace QWK diff --git a/src/Plugins/QWindowKit/updatenotificationbar.hpp b/src/Plugins/QWindowKit/updatenotificationbar.hpp index 8ea43d2db2..79271005fb 100644 --- a/src/Plugins/QWindowKit/updatenotificationbar.hpp +++ b/src/Plugins/QWindowKit/updatenotificationbar.hpp @@ -12,6 +12,8 @@ #include #include +namespace QWK { + class UpdateNotificationBar : public QFrame { Q_OBJECT @@ -38,4 +40,6 @@ class UpdateNotificationBar : public QFrame { QPushButton* m_closeBtn; }; +} // namespace QWK + #endif // UPDATENOTIFICATIONBAR_H diff --git a/src/Plugins/Qt/qt_tm_widget.cpp b/src/Plugins/Qt/qt_tm_widget.cpp index edcda47aa5..8462a11da2 100644 --- a/src/Plugins/Qt/qt_tm_widget.cpp +++ b/src/Plugins/Qt/qt_tm_widget.cpp @@ -342,7 +342,7 @@ qt_tm_widget_rep::qt_tm_widget_rep (int mask, command _quit) notificationLayout->setSpacing (0); // 初始化版本更新提示条(在上) - updateNotificationBar= new UpdateNotificationBar (); + updateNotificationBar= new QWK::UpdateNotificationBar (); notificationLayout->addWidget (updateNotificationBar); updateNotificationBar->hide (); @@ -376,20 +376,20 @@ qt_tm_widget_rep::qt_tm_widget_rep (int mask, command _quit) // 连接版本更新提示条信号 QObject::connect (updateNotificationBar, - &UpdateNotificationBar::updateNowRequested, [this] () { + &QWK::UpdateNotificationBar::updateNowRequested, [this] () { eval ("(use-modules (utils misc version-update))"); string url= as_string (call ("get-update-download-url")); open_url (url); // 不隐藏提示条,保持显示直到用户实际更新版本 }); QObject::connect (updateNotificationBar, - &UpdateNotificationBar::snoozeRequested, [this] () { + &QWK::UpdateNotificationBar::snoozeRequested, [this] () { eval ("(use-modules (utils misc version-update))"); call ("snooze-version-update"); updateNotificationBar->hide (); }); QObject::connect (updateNotificationBar, - &UpdateNotificationBar::closeRequested, + &QWK::UpdateNotificationBar::closeRequested, [this] () { updateNotificationBar->hide (); }); // 延迟检查版本更新(启动后10秒) diff --git a/src/Plugins/Qt/qt_tm_widget.hpp b/src/Plugins/Qt/qt_tm_widget.hpp index c4850eea50..c3fc6eb738 100644 --- a/src/Plugins/Qt/qt_tm_widget.hpp +++ b/src/Plugins/Qt/qt_tm_widget.hpp @@ -81,8 +81,8 @@ class qt_tm_widget_rep : public qt_window_widget_rep { QTMTabPageContainer* tabPageContainer; QTMAuxiliaryWidget* auxiliaryWidget; QWK::WidgetWindowAgent* windowAgent; - QWK::GuestNotificationBar* guestNotificationBar; // 访客提示条 - UpdateNotificationBar* updateNotificationBar; // 版本更新提示条 + QWK::GuestNotificationBar* guestNotificationBar; // 访客提示条 + QWK::UpdateNotificationBar* updateNotificationBar; // 版本更新提示条 QWK::LoginButton* loginButton; QWK::LoginDialog* m_loginDialog; QLabel* avatarLabel; From dc5b21a3ad36351fcf46001e04747f9e55269d92 Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 1 Apr 2026 13:36:48 +0800 Subject: [PATCH 4/9] fix bugs --- src/Plugins/Qt/qt_tm_widget.cpp | 5 +++- src/Plugins/Qt/qt_tm_widget.hpp | 52 ++++++++++++++++----------------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/Plugins/Qt/qt_tm_widget.cpp b/src/Plugins/Qt/qt_tm_widget.cpp index 8462a11da2..cb07625ef9 100644 --- a/src/Plugins/Qt/qt_tm_widget.cpp +++ b/src/Plugins/Qt/qt_tm_widget.cpp @@ -2313,7 +2313,10 @@ qt_tm_widget_rep::checkVersionUpdate () { QString remoteVersion= parseVersionFromTM (data); QString localVersion = XMACS_VERSION; - if (isVersionNewer (remoteVersion, localVersion)) { + if (remoteVersion.isEmpty ()) { + std_error << "Failed to parse version from remote response" << LF; + } + else if (isVersionNewer (remoteVersion, localVersion)) { m_remoteVersion= remoteVersion; updateNotificationBar->setVersionInfo (localVersion, remoteVersion); updateNotificationBar->show (); diff --git a/src/Plugins/Qt/qt_tm_widget.hpp b/src/Plugins/Qt/qt_tm_widget.hpp index c3fc6eb738..c98e523b24 100644 --- a/src/Plugins/Qt/qt_tm_widget.hpp +++ b/src/Plugins/Qt/qt_tm_widget.hpp @@ -66,33 +66,33 @@ class qt_tm_widget_rep : public qt_window_widget_rep { tab_tools_visibility = 1024 } visibility_t; */ - QLabel* rightLabel; - QLabel* leftLabel; - QLabel* middleLabel; - QToolBar* menuToolBar; - QToolBar* mainToolBar; - QToolBar* modeToolBar; - QToolBar* focusToolBar; - QToolBar* userToolBar; - QDockWidget* sideTools; - QDockWidget* leftTools; - QDockWidget* bottomTools; - QDockWidget* extraTools; - QTMTabPageContainer* tabPageContainer; - QTMAuxiliaryWidget* auxiliaryWidget; - QWK::WidgetWindowAgent* windowAgent; + QLabel* rightLabel; + QLabel* leftLabel; + QLabel* middleLabel; + QToolBar* menuToolBar; + QToolBar* mainToolBar; + QToolBar* modeToolBar; + QToolBar* focusToolBar; + QToolBar* userToolBar; + QDockWidget* sideTools; + QDockWidget* leftTools; + QDockWidget* bottomTools; + QDockWidget* extraTools; + QTMTabPageContainer* tabPageContainer; + QTMAuxiliaryWidget* auxiliaryWidget; + QWK::WidgetWindowAgent* windowAgent; QWK::GuestNotificationBar* guestNotificationBar; // 访客提示条 QWK::UpdateNotificationBar* updateNotificationBar; // 版本更新提示条 - QWK::LoginButton* loginButton; - QWK::LoginDialog* m_loginDialog; - QLabel* avatarLabel; - QLabel* nameLabel; - QLabel* accountIdLabel; - QLabel* membershipPeriodLabel; - QLabel* membershipTitleLabel; - QPushButton* loginActionButton; - QPushButton* logoutButton; - QString m_remoteVersion; // 远程版本号 + QWK::LoginButton* loginButton; + QWK::LoginDialog* m_loginDialog; + QLabel* avatarLabel; + QLabel* nameLabel; + QLabel* accountIdLabel; + QLabel* membershipPeriodLabel; + QLabel* membershipTitleLabel; + QPushButton* loginActionButton; + QPushButton* logoutButton; + QString m_remoteVersion; // 远程版本号 #ifdef Q_OS_MAC QToolBar* dumbToolBar; @@ -128,10 +128,8 @@ class qt_tm_widget_rep : public qt_window_widget_rep { void logout (); // Version update notification - void setupUpdateNotificationBar (); void checkVersionUpdate (); QString parseVersionFromTM (const QByteArray& data); - void showUpdateNotification (const QString& version); bool isVersionNewer (const QString& remote, const QString& local); qt_widget main_widget; From 53db65d27adca7af448e9e6042ee78e364e68780 Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 1 Apr 2026 13:59:55 +0800 Subject: [PATCH 5/9] =?UTF-8?q?=E5=8C=BA=E5=88=86=E5=95=86=E4=B8=9A?= =?UTF-8?q?=E7=89=88=E5=92=8C=E7=A4=BE=E5=8C=BA=E7=89=88=E7=9A=84=E6=9C=80?= =?UTF-8?q?=E6=96=B0=E7=89=88=E6=9C=AC=E5=8F=B7=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Plugins/Qt/qt_tm_widget.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Plugins/Qt/qt_tm_widget.cpp b/src/Plugins/Qt/qt_tm_widget.cpp index cb07625ef9..820d72ec37 100644 --- a/src/Plugins/Qt/qt_tm_widget.cpp +++ b/src/Plugins/Qt/qt_tm_widget.cpp @@ -2300,9 +2300,17 @@ qt_tm_widget_rep::checkVersionUpdate () { } // 发送HTTP请求获取远程版本 + // 商业版和社区版使用不同的版本号接口 + QString versionUrl; + if (is_community_stem ()) { + versionUrl= "https://liiistem.cn/mogan_latest_version.tm"; + } + else { + versionUrl= "https://liiistem.cn/latest_version.tm"; + } + QNetworkAccessManager* manager= new QNetworkAccessManager (mainwindow ()); - QNetworkRequest request ( - QUrl ("https://liiistem.cn/mogan_latest_version.tm")); + QNetworkRequest request (QUrl (versionUrl)); request.setRawHeader ("User-Agent", to_qstring (stem_user_agent ()).toUtf8 ()); From 17965cfc0d3ca5bfe5eaf07235f621bde9edfccb Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 1 Apr 2026 14:36:30 +0800 Subject: [PATCH 6/9] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20debug=20=E6=97=A5?= =?UTF-8?q?=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Plugins/Qt/qt_tm_widget.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Plugins/Qt/qt_tm_widget.cpp b/src/Plugins/Qt/qt_tm_widget.cpp index 820d72ec37..a1d1fa33b2 100644 --- a/src/Plugins/Qt/qt_tm_widget.cpp +++ b/src/Plugins/Qt/qt_tm_widget.cpp @@ -2310,7 +2310,7 @@ qt_tm_widget_rep::checkVersionUpdate () { } QNetworkAccessManager* manager= new QNetworkAccessManager (mainwindow ()); - QNetworkRequest request (QUrl (versionUrl)); + QNetworkRequest request (versionUrl); request.setRawHeader ("User-Agent", to_qstring (stem_user_agent ()).toUtf8 ()); @@ -2321,8 +2321,12 @@ qt_tm_widget_rep::checkVersionUpdate () { QString remoteVersion= parseVersionFromTM (data); QString localVersion = XMACS_VERSION; + if (!remoteVersion.isEmpty ()) { + qDebug () << "[VersionUpdate] Parsed remote version:" << remoteVersion; + } + if (remoteVersion.isEmpty ()) { - std_error << "Failed to parse version from remote response" << LF; + qDebug () << "[VersionUpdate] Failed to parse version from response"; } else if (isVersionNewer (remoteVersion, localVersion)) { m_remoteVersion= remoteVersion; @@ -2330,6 +2334,10 @@ qt_tm_widget_rep::checkVersionUpdate () { updateNotificationBar->show (); } } + else { + qDebug () << "[VersionUpdate] Failed to fetch remote version:" + << reply->errorString (); + } reply->deleteLater (); manager->deleteLater (); }); @@ -2338,8 +2346,8 @@ qt_tm_widget_rep::checkVersionUpdate () { QString qt_tm_widget_rep::parseVersionFromTM (const QByteArray& data) { QString content= QString::fromUtf8 (data); - // 简单解析 标签内容 - QRegularExpression re ("\\s*([\\d\\.\\-rc]+)"); + // 解析 TeXmacs 格式的 <\body> 标签内容 + QRegularExpression re ("<\\\\?body>\\s*([\\d\\.\\-rc]+)"); QRegularExpressionMatch match= re.match (content); return match.captured (1).trimmed (); } From 4436a570b6e0e9f215d803f73369936b440f91fe Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 1 Apr 2026 14:57:14 +0800 Subject: [PATCH 7/9] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=97=A0=E7=94=A8?= =?UTF-8?q?=E7=9A=84=E5=A3=B0=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Plugins/QWindowKit/windowbar.hpp | 6 ------ src/Plugins/QWindowKit/windowbar_p.hpp | 9 --------- 2 files changed, 15 deletions(-) diff --git a/src/Plugins/QWindowKit/windowbar.hpp b/src/Plugins/QWindowKit/windowbar.hpp index e8f8e7c9e8..5d993b6369 100644 --- a/src/Plugins/QWindowKit/windowbar.hpp +++ b/src/Plugins/QWindowKit/windowbar.hpp @@ -13,8 +13,6 @@ namespace QWK { class WindowBarPrivate; -class GuestNotificationBar; -class UpdateNotificationBar; class WindowBar : public QFrame { Q_OBJECT @@ -34,10 +32,6 @@ class WindowBar : public QFrame { QAbstractButton* maxButton () const; QAbstractButton* closeButton () const; - // Notification bars - GuestNotificationBar* guestNotificationBar () const; - UpdateNotificationBar* updateNotificationBar () const; - void setMenuBar (QMenuBar* menuBar); void setTitleLabel (QLabel* label); void setTitleWidget (QWidget* widget); // 新接口:支持任意QWidget diff --git a/src/Plugins/QWindowKit/windowbar_p.hpp b/src/Plugins/QWindowKit/windowbar_p.hpp index 7b49325499..90ebefea37 100644 --- a/src/Plugins/QWindowKit/windowbar_p.hpp +++ b/src/Plugins/QWindowKit/windowbar_p.hpp @@ -11,9 +11,6 @@ namespace QWK { -class GuestNotificationBar; -class UpdateNotificationBar; - class WindowBarPrivate { Q_DECLARE_PUBLIC (WindowBar) public: @@ -41,12 +38,6 @@ class WindowBarPrivate { QHBoxLayout* layout; - // Notification bars container (vertical layout) - QWidget* notificationContainer; - QVBoxLayout* notificationLayout; - GuestNotificationBar* guestNotificationBar; - UpdateNotificationBar* updateNotificationBar; - inline QWidget* widgetAt (int index) const { return layout->itemAt (index)->widget (); } From 805c8c8cb6ebb11833508f1f76d39cd963160fe9 Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 1 Apr 2026 16:51:23 +0800 Subject: [PATCH 8/9] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E5=92=8C=E6=8C=89=E9=92=AE=E4=B9=8B=E9=97=B4=E7=9A=84=E9=97=B4?= =?UTF-8?q?=E8=B7=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Plugins/QWindowKit/updatenotificationbar.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Plugins/QWindowKit/updatenotificationbar.cpp b/src/Plugins/QWindowKit/updatenotificationbar.cpp index b1cb6d0705..c5cf615f10 100644 --- a/src/Plugins/QWindowKit/updatenotificationbar.cpp +++ b/src/Plugins/QWindowKit/updatenotificationbar.cpp @@ -41,6 +41,9 @@ UpdateNotificationBar::setupUI () { m_messageLabel->setWordWrap (false); m_layout->addWidget (m_messageLabel); + // 消息和按钮之间的间距 + m_layout->addSpacing (16); + // 按钮容器 QWidget* btnWidget= new QWidget (this); QHBoxLayout* btnLayout= new QHBoxLayout (btnWidget); From 4d500283b3fea4b395f41fb76465dd4b4eede385 Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 1 Apr 2026 17:09:56 +0800 Subject: [PATCH 9/9] =?UTF-8?q?=E7=BF=BB=E8=AF=91=E6=8C=89=E7=85=A7?= =?UTF-8?q?=E5=AD=97=E6=AF=8D=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TeXmacs/plugins/lang/dic/en_US/zh_CN.scm | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/TeXmacs/plugins/lang/dic/en_US/zh_CN.scm b/TeXmacs/plugins/lang/dic/en_US/zh_CN.scm index b95c27a9a1..71ed0b97b2 100644 --- a/TeXmacs/plugins/lang/dic/en_US/zh_CN.scm +++ b/TeXmacs/plugins/lang/dic/en_US/zh_CN.scm @@ -501,6 +501,7 @@ ("current graphical mode" "当前绘图模式") ("current user version" "当前用户版本") ("current version" "当前版本") +("current" "当前") ("cursor" "光标") ("cursors" "游标") ("curve intersections" "曲线交点") @@ -1493,6 +1494,7 @@ ("new row" "") ("new table" "") ("new version" "新版") +("New version available" "发现新版本") ("new window" "新窗口") ("new" "新建") ("newer version" "新版") @@ -1887,6 +1889,7 @@ ("Renew" "续费") ("Renew Early" "提前续费") ("Renew Now" "续费会员") +("Remind later" "稍后提醒") ("rendering" "渲染") ("renumber this page" "修改当前页码") ("repeat object" "") @@ -2397,6 +2400,7 @@ ("up" "") ("up" "上") ("Update buffer" "更新缓冲区") +("Update now" "立即更新") ("update from web" "") ("update image links" "") ("update this buffer" "更新此文档") @@ -2560,8 +2564,3 @@ ("You are currently in guest mode, login to enable AI, MathOCR,and other features" "您当前处于访客状态,登录激活AI和公式识别等功能") ("Login Now" "立即登录") ("Use extensible brackets" "使用可伸缩括号") -;; 版本更新提示 -("New version available" "发现新版本") -("current" "当前") -("Update now" "立即更新") -("Remind later" "稍后提醒")