diff --git a/CHANGELOG.md b/CHANGELOG.md index db01809..8420aea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 deletion (#33, #43, #46, #48). - Windows: six-second reversible deletion for individual and selected tasks (#47). +- Linux: the About dialog now carries the same website and Report-an-Issue + links as macOS and Windows (GtkAboutDialog cannot hold a second link, + so the dialog is built on the plain family layout); Windows and Linux + also gain the About © line, and the README and product site name the + issue tracker as the feedback channel (#55). ### Changed - Add an executable cross-platform product acceptance contract. Windows, diff --git a/README.md b/README.md index c0221c3..41e29cb 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,16 @@ suite and byte-identical i18n on every push. The source-controlled verified package, and accessibility-driven product behavior on Windows, macOS arm64/x64, and Linux. +## Feedback + +Taskly is offline-first and ships no telemetry — +[GitHub issues](https://github.com/turinglambdaai/taskly/issues) are the +feedback channel, with templates for both +[bug reports](https://github.com/turinglambdaai/taskly/issues/new?template=bug_report.md) +and +[feature requests](https://github.com/turinglambdaai/taskly/issues/new?template=feature_request.md). +The in-app About dialog links to the same tracker on every platform. + ## License [AGPL-3.0](LICENSE). diff --git a/README.zh-CN.md b/README.zh-CN.md index a11f5ac..185f4d3 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -83,6 +83,10 @@ python3 shared/cli-golden/runner.py --binary scripts/taskly-cli.sh # 63 例 go 一套规格保证所有端一致:产品行为([PRODUCT-SPEC](shared/spec/PRODUCT-SPEC.md))、数据格式、CLI 契约、设计令牌、更新契约——都在 [shared/spec/](shared/spec/) 下。CI 在每次推送时用 golden 套件和字节级一致的 i18n 强制执行 CLI 契约;源码中的 `rivet-acceptance.rktd` 还要求 Windows、macOS arm64/x64、Linux 分别通过真实 RVT1、原生构建、已验证安装包和无障碍树驱动的产品行为验收。 +## 反馈 + +Taskly 本地优先、无遥测,反馈统一走 [GitHub issues](https://github.com/turinglambdaai/taskly/issues):[Bug 报告](https://github.com/turinglambdaai/taskly/issues/new?template=bug_report.md)和[功能请求](https://github.com/turinglambdaai/taskly/issues/new?template=feature_request.md)都有模板。各平台的「关于」对话框内也有同一入口。 + ## 许可证 [AGPL-3.0](LICENSE)。 diff --git a/docs/index.html b/docs/index.html index 9921a28..ffc2439 100644 --- a/docs/index.html +++ b/docs/index.html @@ -242,6 +242,7 @@

开放核心 · AGPL-3.0

GitHub Rivet 更新日志 + 问题反馈
© 2026 Taskly. AGPL-3.0 协议。
diff --git a/docs/script.js b/docs/script.js index c1a9d9b..644e526 100644 --- a/docs/script.js +++ b/docs/script.js @@ -142,6 +142,7 @@ const i18n = { 'cta.manual': 'Read the manual', 'release.note': 'Every release carries SHA256SUMS plus a signed update manifest; macOS builds are ad-hoc signed \u2014 clear the Gatekeeper quarantine with `xattr -cr /Applications/Taskly.app` on first launch.', 'footer.changelog': 'Changelog', + 'footer.feedback': 'Feedback', 'footer.license': 'AGPL-3.0 license.' }, zh: { @@ -196,6 +197,7 @@ const i18n = { 'cta.manual': '阅读手册', 'release.note': '每个版本都带 SHA256SUMS 与签名更新清单;macOS 包为 ad-hoc 签名——首次启动如被 Gatekeeper 拦截,执行 `xattr -cr /Applications/Taskly.app` 即可。', 'footer.changelog': '更新日志', + 'footer.feedback': '问题反馈', 'footer.license': 'AGPL-3.0 协议。' } }; diff --git a/linux/src/main.cpp b/linux/src/main.cpp index e298069..4d714cb 100644 --- a/linux/src/main.cpp +++ b/linux/src/main.cpp @@ -1774,20 +1774,56 @@ void confirm_dialog(char const* title, char const* body, gtk_window_present(GTK_WINDOW(dialog)); } +// Same About content as the macOS and Windows hosts: tagline, license, +// and two links — website plus the issue tracker. GtkAboutDialog cannot +// carry a second link, so the family layout is built on a plain dialog; +// GtkLinkButton opens the URI through the system browser itself. void show_about_dialog() { - auto* dialog = gtk_about_dialog_new(); - gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(dialog), "Taskly"); - gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), rivet_app::kVersion); - gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog), - tr("aboutContent").c_str()); - gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(dialog), - tr("aboutLicense").c_str()); - gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), - "https://taskly.jrtx.site"); - gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(dialog), - tr("aboutWebsite").c_str()); - gtk_window_set_transient_for(GTK_WINDOW(dialog), g_state.window); - gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); + auto* dialog = gtk_dialog_new_with_buttons( + ("Taskly v" + std::string(rivet_app::kVersion)).c_str(), + g_state.window, + static_cast(GTK_DIALOG_MODAL | + GTK_DIALOG_DESTROY_WITH_PARENT), + tr("dialogConfirm").c_str(), GTK_RESPONSE_CLOSE, nullptr); + auto* area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + auto* content = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); + gtk_widget_set_margin_top(content, 12); + gtk_widget_set_margin_bottom(content, 6); + gtk_widget_set_margin_start(content, 12); + gtk_widget_set_margin_end(content, 12); + gtk_box_append(GTK_BOX(area), content); + auto* copyright = gtk_label_new("© 2026 Taskly Team"); + gtk_widget_set_opacity(copyright, 0.75); + gtk_box_append(GTK_BOX(content), copyright); + auto* comments = gtk_label_new(tr("aboutContent").c_str()); + gtk_label_set_wrap(GTK_LABEL(comments), TRUE); + gtk_label_set_justify(GTK_LABEL(comments), GTK_JUSTIFY_CENTER); + gtk_label_set_max_width_chars(GTK_LABEL(comments), 60); + gtk_box_append(GTK_BOX(content), comments); + auto* license = gtk_label_new(tr("aboutLicense").c_str()); + gtk_label_set_wrap(GTK_LABEL(license), TRUE); + gtk_label_set_justify(GTK_LABEL(license), GTK_JUSTIFY_CENTER); + gtk_label_set_max_width_chars(GTK_LABEL(license), 60); + gtk_widget_set_opacity(license, 0.75); + gtk_box_append(GTK_BOX(content), license); + auto* links = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 24); + gtk_widget_set_halign(links, GTK_ALIGN_CENTER); + gtk_box_append(GTK_BOX(content), links); + auto* website = gtk_link_button_new("https://taskly.jrtx.site"); + gtk_button_set_label(GTK_BUTTON(website), tr("aboutWebsite").c_str()); + gtk_widget_set_hexpand(website, FALSE); + gtk_box_append(GTK_BOX(links), website); + auto* issue = gtk_link_button_new( + "https://github.com/turinglambdaai/taskly/issues"); + gtk_button_set_label(GTK_BUTTON(issue), tr("aboutReportIssue").c_str()); + gtk_widget_set_hexpand(issue, FALSE); + gtk_box_append(GTK_BOX(links), issue); + g_signal_connect( + dialog, "response", + G_CALLBACK(+[](GtkDialog* dialog, gint, gpointer) { + gtk_window_destroy(GTK_WINDOW(dialog)); + }), + nullptr); gtk_window_present(GTK_WINDOW(dialog)); } diff --git a/shared/spec/PRODUCT-SPEC.md b/shared/spec/PRODUCT-SPEC.md index c07dd0d..9d1efba 100644 --- a/shared/spec/PRODUCT-SPEC.md +++ b/shared/spec/PRODUCT-SPEC.md @@ -168,9 +168,10 @@ pickers. Save (blank text silently ignored), Delete (confirm first), Cancel - Help: About — `Taskly v` + `© 2026 Taskly Team` + `aboutContent` + license line (`aboutLicense`) + two link buttons on every host: Website (`aboutWebsite` → taskly.jrtx.site) and Report an - Issue (`aboutReportIssue` → the GitHub issue tracker). Linux uses the - GTK about dialog's native version/license/website rows; macOS and - Windows render the same fields inside their sheet/dialog. + Issue (`aboutReportIssue` → the GitHub issue tracker). macOS and + Windows render the fields inside their sheet/dialog; Linux builds the + same layout on a plain GtkDialog — GtkAboutDialog cannot carry a + second link, so the native about dialog is not used. - All accelerators work window-wide without opening the menu. ## 9. Reminders (all platforms) diff --git a/windows/MainWindow.xaml.cpp b/windows/MainWindow.xaml.cpp index 70e0858..43eae6c 100644 --- a/windows/MainWindow.xaml.cpp +++ b/windows/MainWindow.xaml.cpp @@ -2427,6 +2427,12 @@ winrt::fire_and_forget MainWindow::OnAbout( Microsoft::UI::Xaml::RoutedEventArgs const&) { auto panel = mxc::StackPanel{}; panel.Spacing(4); + auto copyright = mxc::TextBlock{}; + copyright.Text(L"© 2026 Taskly Team"); + copyright.TextAlignment(mx::TextAlignment::Center); + copyright.FontSize(12); + copyright.Opacity(0.75); + panel.Children().Append(copyright); auto tagline = mxc::TextBlock{}; tagline.Text(t("aboutContent")); tagline.TextAlignment(mx::TextAlignment::Center);