From 6cba1d1b652245352bf264541d71b4bb789421b0 Mon Sep 17 00:00:00 2001 From: RadRussianRus Date: Thu, 15 Apr 2021 17:07:27 +0300 Subject: [PATCH] Custom changelog box --- Telegram/CMakeLists.txt | 2 + Telegram/Resources/langs/lang.strings | 10 + Telegram/Resources/langs/rewrites/en.json | 9 + Telegram/Resources/langs/rewrites/ru.json | 9 + Telegram/SourceFiles/core/application.cpp | 4 +- .../SourceFiles/core/local_url_handlers.cpp | 23 + .../kotato/customboxes/changelog_box.cpp | 644 ++++++++++++++++++ .../kotato/customboxes/changelog_box.h | 75 ++ .../SourceFiles/window/window_main_menu.cpp | 2 +- Telegram/lib_ui | 2 +- 10 files changed, 777 insertions(+), 3 deletions(-) create mode 100644 Telegram/SourceFiles/kotato/customboxes/changelog_box.cpp create mode 100644 Telegram/SourceFiles/kotato/customboxes/changelog_box.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 08ba7a13e..d3f777cfb 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -678,6 +678,8 @@ PRIVATE intro/intro_step.h intro/intro_widget.cpp intro/intro_widget.h + kotato/customboxes/changelog_box.cpp + kotato/customboxes/changelog_box.h kotato/customboxes/confirm_box.cpp kotato/customboxes/confirm_box.h kotato/customboxes/fonts_box.cpp diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 2b8212d73..7cbf577d9 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -2942,4 +2942,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "ktg_filters_hide_all_chats_toast" = "\"All Chats\" folder is hidden.\nYou can enable it back in Kotatogram Settings."; "ktg_filters_hide_edit_toast" = "Edit button is hidden.\nYou can enable it back in Kotatogram Settings."; +"ktg_changelog_title" = "Change log"; +"ktg_changelog_base_version" = "Based on Telegram Desktop {td_version}"; +"ktg_changelog_release_date" = "Release date: {date}"; +"ktg_changelog_what_to_test" = "What to test"; +"ktg_changelog_features" = "New features"; +"ktg_changelog_changes" = "Changes"; +"ktg_changelog_fixes" = "Fixes"; +"ktg_changelog_more_info" = "More info"; +"ktg_changelog_load_error" = "Error loading changelog."; + // Keys finished diff --git a/Telegram/Resources/langs/rewrites/en.json b/Telegram/Resources/langs/rewrites/en.json index 8c828daa4..317f237a4 100644 --- a/Telegram/Resources/langs/rewrites/en.json +++ b/Telegram/Resources/langs/rewrites/en.json @@ -216,5 +216,14 @@ "ktg_filters_hide_button": "Hide button", "ktg_filters_hide_all_chats_toast": "\"All Chats\" folder is hidden.\nYou can enable it back in Kotatogram Settings.", "ktg_filters_hide_edit_toast": "Edit button is hidden.\nYou can enable it back in Kotatogram Settings.", + "ktg_changelog_title": "Change log", + "ktg_changelog_base_version": "Based on Telegram Desktop {td_version}", + "ktg_changelog_release_date": "Release date: {date}", + "ktg_changelog_what_to_test": "What to test", + "ktg_changelog_features": "New features", + "ktg_changelog_changes": "Changes", + "ktg_changelog_fixes": "Fixes", + "ktg_changelog_more_info": "More info", + "ktg_changelog_load_error": "Error loading changelog.", "dummy_last_string": "" } diff --git a/Telegram/Resources/langs/rewrites/ru.json b/Telegram/Resources/langs/rewrites/ru.json index 96c961099..5342b15a5 100644 --- a/Telegram/Resources/langs/rewrites/ru.json +++ b/Telegram/Resources/langs/rewrites/ru.json @@ -216,5 +216,14 @@ "ktg_filters_hide_button": "Скрыть кнопку", "ktg_filters_hide_all_chats_toast": "Папка «Все чаты» скрыта.\nВы можете включить её обратно в настройках Kotatogram.", "ktg_filters_hide_edit_toast": "Кнопка изменения скрыта.\nВы можете включить её обратно в настройках Kotatogram.", + "ktg_changelog_title": "Список изменений", + "ktg_changelog_base_version": "Основано на Telegram Desktop {td_version}", + "ktg_changelog_release_date": "Дата выхода: {date}", + "ktg_changelog_what_to_test": "Что тестировать", + "ktg_changelog_features": "Новые функции", + "ktg_changelog_changes": "Изменения", + "ktg_changelog_fixes": "Исправления", + "ktg_changelog_more_info": "Подробнее", + "ktg_changelog_load_error": "Ошибка загрузки списка изменений.", "dummy_last_string": "" } diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp index 48e224418..1b31f56e0 100644 --- a/Telegram/SourceFiles/core/application.cpp +++ b/Telegram/SourceFiles/core/application.cpp @@ -781,7 +781,8 @@ bool Application::openInternalUrl(const QString &url, QVariant context) { } QString Application::changelogLink() const { - const auto base = u"https://desktop.telegram.org/changelog"_q; + const auto base = u"tg://kotato/changelog"_q; + /* const auto languages = { "id", "de", @@ -810,6 +811,7 @@ QString Application::changelogLink() const { return base + "?setln=" + language; } } + */ return base; } diff --git a/Telegram/SourceFiles/core/local_url_handlers.cpp b/Telegram/SourceFiles/core/local_url_handlers.cpp index 925eb6535..ff4bc4706 100644 --- a/Telegram/SourceFiles/core/local_url_handlers.cpp +++ b/Telegram/SourceFiles/core/local_url_handlers.cpp @@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/sticker_set_box.h" #include "boxes/sessions_box.h" #include "boxes/language_box.h" +#include "kotato/customboxes/changelog_box.h" #include "passport/passport_form_controller.h" #include "window/window_session_controller.h" #include "ui/toast/toast.h" @@ -351,6 +352,24 @@ bool ResolvePrivatePost( return true; } +bool ResolveChangelog( + Window::SessionController *controller, + const Match &match, + const QVariant &context) { + if (!controller) { + return false; + } + const auto version = (match->lastCapturedIndex() == 1) + ? match->captured(1) + : QString::fromLatin1(AppKotatoVersionStr) + + (cAlphaVersion() + ? qsl("-%1.%2").arg(AppKotatoTestBranch).arg(cAlphaVersion() % 1000) + : QString()); + + Ui::show(Box(version)); + return true; +} + bool ResolveSettings( Window::SessionController *controller, const Match &match, @@ -524,6 +543,10 @@ const std::vector &LocalUrlHandlers() { qsl("^settings(/folders|/devices|/language|/kotato)?$"), ResolveSettings }, + { + qsl("^kotato/changelog/?(?:\\?v=(.+))?$"), + ResolveChangelog + }, { qsl("^([^\\?]+)(\\?|#|$)"), HandleUnknown diff --git a/Telegram/SourceFiles/kotato/customboxes/changelog_box.cpp b/Telegram/SourceFiles/kotato/customboxes/changelog_box.cpp new file mode 100644 index 000000000..8aab05f39 --- /dev/null +++ b/Telegram/SourceFiles/kotato/customboxes/changelog_box.cpp @@ -0,0 +1,644 @@ +/* +This file is part of Kotatogram Desktop, +the unofficial app based on Telegram Desktop. + +For license and copyright information please follow this link: +https://github.com/kotatogram/kotatogram-desktop/blob/dev/LEGAL +*/ +#include "kotato/customboxes/changelog_box.h" + +#include "lang/lang_keys.h" +#include "lang/lang_instance.h" +#include "base/qt_adapters.h" +#include "core/click_handler_types.h" +#include "info/profile/info_profile_icon.h" +#include "ui/wrap/vertical_layout.h" +#include "ui/widgets/buttons.h" +#include "ui/widgets/labels.h" +#include "styles/style_info.h" +#include "styles/style_layers.h" +#include "styles/style_boxes.h" +#include "styles/style_settings.h" + +#include +#include +#include +#include + +namespace Kotato { +namespace { + +bool ReadOption(QJsonObject obj, QString key, std::function callback) { + const auto it = obj.constFind(key); + if (it == obj.constEnd()) { + return false; + } + callback(*it); + return true; +} + +bool ReadObjectOption(QJsonObject obj, QString key, std::function callback) { + auto readResult = false; + auto readValueResult = ReadOption(obj, key, [&](QJsonValue v) { + if (v.isObject()) { + callback(v.toObject()); + readResult = true; + } + }); + return (readValueResult && readResult); +} + +bool ReadArrayOption(QJsonObject obj, QString key, std::function callback) { + auto readResult = false; + auto readValueResult = ReadOption(obj, key, [&](QJsonValue v) { + if (v.isArray()) { + callback(v.toArray()); + readResult = true; + } + }); + return (readValueResult && readResult); +} + +bool ReadStringOption(QJsonObject obj, QString key, std::function callback) { + auto readResult = false; + auto readValueResult = ReadOption(obj, key, [&](QJsonValue v) { + if (v.isString()) { + callback(v.toString()); + readResult = true; + } + }); + return (readValueResult && readResult); +} + +ChangelogBox::Entry ParseJSONChangelog(const QByteArray &json) { + auto error = QJsonParseError{ 0, QJsonParseError::NoError }; + const auto document = QJsonDocument::fromJson(json, &error); + + if (error.error != QJsonParseError::NoError) { + return ChangelogBox::Entry(); + } else if (!document.isObject()) { + return ChangelogBox::Entry(); + } + + const auto obj = document.object(); + auto changelog = ChangelogBox::Entry(); + + ReadStringOption(obj, "version", [&] (auto v) { + changelog.version = v; + }); + + ReadStringOption(obj, "tdVersion", [&] (auto v) { + changelog.tdVersion = v; + }); + + ReadStringOption(obj, "nextVersion", [&] (auto v) { + changelog.nextVersion = v; + }); + + ReadStringOption(obj, "prevVersion", [&] (auto v) { + changelog.prevVersion = v; + }); + + ReadStringOption(obj, "releaseDate", [&] (auto v) { + changelog.releaseDate = QDateTime::fromString(v, Qt::ISODate).toLocalTime(); + }); + + ReadStringOption(obj, "whatToTest", [&] (auto v) { + changelog.whatToTest = v; + }); + + ReadStringOption(obj, "features", [&] (auto v) { + changelog.features = v; + }); + + ReadStringOption(obj, "changes", [&] (auto v) { + changelog.changes = v; + }); + + ReadStringOption(obj, "fixes", [&] (auto v) { + changelog.fixes = v; + }); + + ReadArrayOption(obj, "links", [&] (auto a) { + for (auto i = a.constBegin(), e = a.constEnd(); i != e; ++i) { + if (!(*i).isObject()) { + continue; + } + + auto link = (*i).toObject(); + + auto linkTitle = QString(); + auto linkTarget = QString(); + + ReadStringOption(link, "title", [&] (auto v) { + linkTitle = v; + }); + + ReadStringOption(link, "link", [&] (auto v) { + linkTarget = v; + }); + + changelog.links.push_back(QPair(linkTitle, linkTarget)); + } + + }); + + return changelog; +} + +} // namespace + +class ChangelogBox::Context { +public: + Context(const QString &version); + + void start() { + _version.setForced(_version.value(), true); + } + + const base::Variable &version() { + return _version; + } + + void setVersion(const QString &version) { + _error.set(QString()); + _version.set(version); + } + + const base::Variable &error() { + return _error; + } + + void setError(const QString &error) { + _error.set(error); + } + + const base::Variable &loaded() { + return _loaded; + } + + const ChangelogBox::Entry &changelog() { + return _changelog; + } + + void setChangelog(const ChangelogBox::Entry &changelog) { + _loaded.set(changelog.version); + _changelog = changelog; + } + +private: + base::Variable _version; + base::Variable _error; + base::Variable _loaded; + ChangelogBox::Entry _changelog; +}; + +ChangelogBox::Context::Context(const QString &version) +: _version(version) { +} + +class ChangelogBox::Title : public TWidget, private base::Subscriber { +public: + Title(QWidget *parent, not_null context) + : TWidget(parent) + , _context(context) + , _title(tr::ktg_changelog_title(tr::now)) { + subscribe(_context->version(), [this](QString version) { + versionChanged(version); + }); + + _titleWidth = st::semiboldFont->width(_title); + } + +protected: + void paintEvent(QPaintEvent *e); + +private: + void versionChanged(const QString &version); + + not_null _context; + + QString _title; + QString _version; + int _titleWidth = 0; + int _versionWidth = 0; +}; + +void ChangelogBox::Title::versionChanged(const QString &version) { + _version = tr::lng_about_version(tr::now, lt_version, version); + _versionWidth = st::normalFont->width(_version); + update(); +} + +void ChangelogBox::Title::paintEvent(QPaintEvent *e) { + Painter p(this); + + p.setFont(st::semiboldFont); + p.setPen(st::boxTitleFg); + p.drawTextLeft(0, style::ConvertScale(6), width(), _title, _titleWidth); + + p.setFont(st::normalFont); + p.setPen(st::windowSubTextFg); + p.drawTextLeft(0, style::ConvertScale(26), width(), _version, _versionWidth); +} + +class ChangelogBox::Inner : public RpWidget, private base::Subscriber { +public: + Inner(QWidget *parent, not_null context); + + void setLoadingText(const QString &text); + void showChangelog(const ChangelogBox::Entry &changelog); + +private: + void recountHeightAndResize(); + + struct Row { + object_ptr widget; + }; + + bool _isLoading = true; + not_null _context; + object_ptr _whatToTestTitle; + object_ptr _featuresTitle; + object_ptr _changesTitle; + object_ptr _fixesTitle; + object_ptr _linksTitle; + + object_ptr _loadingText; + + object_ptr _tdVersion; + object_ptr _releaseDate; + + object_ptr _whatToTest; + object_ptr _features; + object_ptr _changes; + object_ptr _fixes; + + std::vector _links; + + int _maxWidth = 0; +}; + +ChangelogBox::Inner::Inner(QWidget*, not_null context) +: _context(context) +, _whatToTestTitle(this, st::settingsSubsectionTitle) +, _featuresTitle(this, st::settingsSubsectionTitle) +, _changesTitle(this, st::settingsSubsectionTitle) +, _fixesTitle(this, st::settingsSubsectionTitle) +, _linksTitle(this, st::settingsSubsectionTitle) +, _loadingText(this, st::boxLabel) +, _tdVersion(this, st::aboutLabel) +, _releaseDate(this, st::aboutLabel) +, _whatToTest(this, st::aboutLabel) +, _features(this, st::aboutLabel) +, _changes(this, st::aboutLabel) +, _fixes(this, st::aboutLabel) { + subscribe(_context->version(), [this](QString version) { + setLoadingText(tr::lng_contacts_loading(tr::now)); + }); + + subscribe(_context->error(), [this](QString error) { + if (!error.isEmpty()) { + setLoadingText(error); + } + }); + + subscribe(_context->loaded(), [this](QString version) { + showChangelog(_context->changelog()); + }); + + _maxWidth = st::boxWideWidth - st::boxPadding.left() - st::boxPadding.right(); + + _whatToTestTitle->setText(tr::ktg_changelog_what_to_test(tr::now)); + _whatToTestTitle->resizeToWidth(_maxWidth); + _featuresTitle->setText(tr::ktg_changelog_features(tr::now)); + _featuresTitle->resizeToWidth(_maxWidth); + _changesTitle->setText(tr::ktg_changelog_changes(tr::now)); + _changesTitle->resizeToWidth(_maxWidth); + _fixesTitle->setText(tr::ktg_changelog_fixes(tr::now)); + _fixesTitle->resizeToWidth(_maxWidth); + _linksTitle->setText(tr::ktg_changelog_more_info(tr::now)); + _linksTitle->resizeToWidth(_maxWidth); + + _whatToTestTitle->hide(); + _featuresTitle->hide(); + _changesTitle->hide(); + _fixesTitle->hide(); + _linksTitle->hide(); + _loadingText->hide(); + _tdVersion->hide(); + _releaseDate->hide(); + _whatToTest->hide(); + _features->hide(); + _changes->hide(); + _fixes->hide(); + + recountHeightAndResize(); +} + +void ChangelogBox::Inner::setLoadingText(const QString &text) { + _isLoading = true; + _loadingText->setText(text); + _loadingText->resizeToWidth(_maxWidth); + _links.clear(); + recountHeightAndResize(); +} + +void ChangelogBox::Inner::showChangelog(const ChangelogBox::Entry &changelog) { + _tdVersion->setText( + tr::ktg_changelog_base_version(tr::now, + lt_td_version, + changelog.tdVersion)); + _tdVersion->resizeToWidth(_maxWidth); + + _releaseDate->setText( + tr::ktg_changelog_release_date(tr::now, + lt_date, + langDateTimeFull(changelog.releaseDate))); + _releaseDate->resizeToWidth(_maxWidth); + + _whatToTest->setText(changelog.whatToTest); + _whatToTest->resizeToWidth(_maxWidth); + _features->setText(changelog.features); + _features->resizeToWidth(_maxWidth); + _changes->setText(changelog.changes); + _changes->resizeToWidth(_maxWidth); + _fixes->setText(changelog.fixes); + _fixes->resizeToWidth(_maxWidth); + + _links.reserve(changelog.links.size()); + + for (auto i = changelog.links.begin(), e = changelog.links.end(); i != e; ++i) { + auto button = object_ptr(this, + rpl::single(i->first), + st::inviteViaLinkButton); + object_ptr( + button, + st::inviteViaLinkIcon, + st::inviteViaLinkIconPosition); + const auto link = i->second; + button->addClickHandler([this, link] { + UrlClickHandler::Open(link); + }); + button->resizeToWidth(_maxWidth + st::boxPadding.left() + st::boxPadding.right()); + _links.push_back(Row{ + .widget = std::move(button) + }); + } + + _isLoading = false; + recountHeightAndResize(); +} + +void ChangelogBox::Inner::recountHeightAndResize() { + auto newHeight = 0; + if (_isLoading) { + newHeight = st::calendarTitleHeight + st::noContactsHeight; + _whatToTestTitle->hide(); + _featuresTitle->hide(); + _changesTitle->hide(); + _fixesTitle->hide(); + _linksTitle->hide(); + _tdVersion->hide(); + _releaseDate->hide(); + _whatToTest->hide(); + _features->hide(); + _changes->hide(); + _fixes->hide(); + + _loadingText->move( + (_maxWidth - _loadingText->naturalWidth()) / 2 + st::boxPadding.left(), + (newHeight - _loadingText->heightNoMargins()) / 2); + _loadingText->show(); + } else { + _loadingText->hide(); + + int left = st::boxPadding.left(); + + _tdVersion->move(left, newHeight); + newHeight += _tdVersion->heightNoMargins(); + + _releaseDate->move(left, newHeight); + newHeight += _releaseDate->heightNoMargins() + + st::boxPadding.bottom(); + + _tdVersion->show(); + _releaseDate->show(); + + if (_whatToTest->heightNoMargins() > 0) { + newHeight += (st::boxPadding.bottom() * 2); + _whatToTestTitle->move(left, newHeight); + + newHeight += _whatToTestTitle->heightNoMargins() + + (st::boxPadding.bottom() * 2); + _whatToTest->move(left, newHeight); + newHeight += _whatToTest->heightNoMargins() + + st::boxPadding.bottom(); + + _whatToTestTitle->show(); + _whatToTest->show(); + } + + if (_features->heightNoMargins() > 0) { + newHeight += (st::boxPadding.bottom() * 2); + _featuresTitle->move(left, newHeight); + + newHeight += _featuresTitle->heightNoMargins() + + (st::boxPadding.bottom() * 2); + _features->move(left, newHeight); + newHeight += _features->heightNoMargins() + + st::boxPadding.bottom(); + + _featuresTitle->show(); + _features->show(); + } + + if (_changes->heightNoMargins() > 0) { + newHeight += (st::boxPadding.bottom() * 2); + _changesTitle->move(left, newHeight); + + newHeight += _changesTitle->heightNoMargins() + + (st::boxPadding.bottom() * 2); + _changes->move(left, newHeight); + newHeight += _changes->heightNoMargins() + + st::boxPadding.bottom(); + + _changesTitle->show(); + _changes->show(); + } + + if (_fixes->heightNoMargins() > 0) { + newHeight += (st::boxPadding.bottom() * 2); + _fixesTitle->move(left, newHeight); + + newHeight += _fixesTitle->heightNoMargins() + + (st::boxPadding.bottom() * 2); + _fixes->move(left, newHeight); + newHeight += _fixes->heightNoMargins() + + st::boxPadding.bottom(); + + _fixesTitle->show(); + _fixes->show(); + } + + if (_links.size() > 0) { + newHeight += (st::boxPadding.bottom() * 2); + _linksTitle->move(left, newHeight); + + newHeight += _linksTitle->heightNoMargins() + + st::boxPadding.bottom(); + _linksTitle->show(); + + for (auto i = _links.begin(), e = _links.end(); i != e; ++i) { + i->widget->move(0, newHeight); + newHeight += i->widget->heightNoMargins(); + + i->widget->show(); + } + + newHeight += st::boxPadding.bottom(); + } + } + + resize(width(), newHeight); +} + +ChangelogBox::ChangelogBox( + QWidget*, + const QString &version) +: _context(std::make_unique(version)) +, _title(this, _context.get()) +, _previous(this, st::calendarPrevious) +, _next(this, st::calendarNext) +, _changelogManager(std::make_unique()) { + setTopShadowWithSkip(true); +} + +void ChangelogBox::prepare() { + _previous->setClickedCallback([this] { + if (!_prevVersion.isEmpty()) { + _context->setVersion(_prevVersion); + } + }); + _next->setClickedCallback([this] { + if (!_nextVersion.isEmpty()) { + _context->setVersion(_nextVersion); + } + }); + + addButton(tr::lng_close(), [this] { closeBox(); }); + subscribe(_context->version(), [this](QString version) { versionChanged(version); }); + + _inner = setInnerWidget( + object_ptr(this, _context.get()), + st::calendarTitleHeight); + + _inner->resizeToWidth(st::boxWideWidth); + _inner->heightValue( + ) | rpl::start_with_next([=](int height) { + setDimensions(st::boxWideWidth, st::calendarTitleHeight + height); + }, _inner->lifetime()); + _context->start(); +} + +void ChangelogBox::requestChangelog() { + auto baseLang = Lang::GetInstance().baseId().replace("-raw", ""); + auto currentLang = Lang::Id().replace("-raw", ""); + QString languagePath; + + for (const auto language : { "ru", "uk", "be" }) { + if (baseLang == QString(language) || currentLang == QString(language)) { + languagePath = "ru/"; + break; + } + } + + const auto request = QNetworkRequest(qsl("https://kotatogram.github.io/%1json/changelog/%2.json").arg( + languagePath, + _context->version().value())); + _changelogReply = _changelogManager->get(request); + _changelogReply->connect(_changelogReply, &QNetworkReply::finished, [=] { + onRequestFinished(); + }); + _changelogReply->connect(_changelogReply, base::QNetworkReply_error, [=](auto e) { + onRequestError(e); + }); +} + +void ChangelogBox::onRequestError(QNetworkReply::NetworkError e) { + if (_changelogReply) { + _changelogReply->deleteLater(); + _changelogReply = nullptr; + }; + + _context->setError(tr::ktg_changelog_load_error(tr::now)); +} + +void ChangelogBox::onRequestFinished() { + if (!_changelogReply) { + _context->setError(tr::ktg_changelog_load_error(tr::now)); + return; + } + + auto result = _changelogReply->readAll().trimmed(); + _changelogReply->deleteLater(); + _changelogReply = nullptr; + + const auto changelog = ParseJSONChangelog(result); + + if (!changelog.version.isEmpty()) { + _context->setChangelog(changelog); + refreshTitleButtons(changelog.prevVersion, changelog.nextVersion); + } else { + _context->setError(tr::ktg_changelog_load_error(tr::now)); + } +} + +void ChangelogBox::versionChanged(const QString &version) { + refreshTitleButtons(); + requestChangelog(); +} + +void ChangelogBox::refreshTitleButtons( + const QString &prevVersion, + const QString &nextVersion) { + + _prevVersion = prevVersion; + auto previousEnabled = !_prevVersion.isEmpty(); + _previous->setIconOverride(previousEnabled ? nullptr : &st::calendarPreviousDisabled); + _previous->setRippleColorOverride(previousEnabled ? nullptr : &st::boxBg); + _previous->setCursor(previousEnabled ? style::cur_pointer : style::cur_default); + + _nextVersion = nextVersion; + auto nextEnabled = !_nextVersion.isEmpty(); + _next->setIconOverride(nextEnabled ? nullptr : &st::calendarNextDisabled); + _next->setRippleColorOverride(nextEnabled ? nullptr : &st::boxBg); + _next->setCursor(nextEnabled ? style::cur_pointer : style::cur_default); +} + +void ChangelogBox::resizeEvent(QResizeEvent *e) { + _previous->moveToRight(_next->width(), 0); + _next->moveToRight(0, 0); + _title->setGeometryToLeft( + st::boxPadding.left(), + 0, + width() - _previous->width() - _next->width() - st::boxPadding.left(), + st::calendarTitleHeight); + BoxContent::resizeEvent(e); +} + +void ChangelogBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Left) { + if (!_prevVersion.isEmpty()) { + _context->setVersion(_prevVersion); + } + } else if (e->key() == Qt::Key_Right) { + if (!_nextVersion.isEmpty()) { + _context->setVersion(_nextVersion); + } + } else { + BoxContent::keyPressEvent(e); + } +} + +} // namespace Kotato \ No newline at end of file diff --git a/Telegram/SourceFiles/kotato/customboxes/changelog_box.h b/Telegram/SourceFiles/kotato/customboxes/changelog_box.h new file mode 100644 index 000000000..d365847d2 --- /dev/null +++ b/Telegram/SourceFiles/kotato/customboxes/changelog_box.h @@ -0,0 +1,75 @@ +/* +This file is part of Kotatogram Desktop, +the unofficial app based on Telegram Desktop. + +For license and copyright information please follow this link: +https://github.com/kotatogram/kotatogram-desktop/blob/dev/LEGAL +*/ +#pragma once + +#include "boxes/abstract_box.h" + +#include +#include + +namespace Ui { +class FlatLabel; +class IconButton; +class VerticalLayout; +} // namespace Ui + +namespace Kotato { +class ChangelogBox : public Ui::BoxContent, private base::Subscriber { +public: + ChangelogBox(QWidget*, const QString &version); + + struct Entry { + QString version; + QString tdVersion; + QString nextVersion; + QString prevVersion; + QDateTime releaseDate; + QString whatToTest; + QString features; + QString changes; + QString fixes; + QVector> links; + }; + +protected: + void prepare() override; + + void resizeEvent(QResizeEvent *e) override; + void keyPressEvent(QKeyEvent *e) override; + +private: + void requestChangelog(); + + void versionChanged(const QString &version); + void refreshTitleButtons( + const QString &prevVersion = QString(), + const QString &nextVersion = QString()); + + void onRequestError(QNetworkReply::NetworkError e); + void onRequestFinished(); + + class Context; + std::unique_ptr _context; + + class Inner; + QPointer _inner; + + class Title; + object_ptr _title; + object_ptr<Ui::IconButton> _previous; + object_ptr<Ui::IconButton> _next; + + QString _prevVersion; + QString _nextVersion; + + std::unique_ptr<QNetworkAccessManager> _changelogManager; + QNetworkReply *_changelogReply = nullptr; + +}; + +} // namespace Kotato \ No newline at end of file diff --git a/Telegram/SourceFiles/window/window_main_menu.cpp b/Telegram/SourceFiles/window/window_main_menu.cpp index 810de9284..7f159f5c7 100644 --- a/Telegram/SourceFiles/window/window_main_menu.cpp +++ b/Telegram/SourceFiles/window/window_main_menu.cpp @@ -626,7 +626,7 @@ MainMenu::MainMenu( _telegram->setRichText(textcmdLink(1, qsl("Kotatogram Desktop"))); _telegram->setLink(1, std::make_shared<LambdaClickHandler>([] { Ui::show(Box<AboutBox>()); })); _version->setRichText(textcmdLink(1, currentVersionText())); - _version->setLink(1, std::make_shared<UrlClickHandler>(qsl("https://github.com/kotatogram/kotatogram-desktop"))); + _version->setLink(1, std::make_shared<UrlClickHandler>(Core::App().changelogLink())); _controller->session().downloaderTaskFinished( ) | rpl::start_with_next([=] { diff --git a/Telegram/lib_ui b/Telegram/lib_ui index ac0480096..68ca7c4be 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit ac048009624150564b5a07655105564cf2947bdf +Subproject commit 68ca7c4be9fc27091a6eccadc67bdc8e42272ae0