mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-08-06 03:42:56 +00:00
Added poll stats action and dialog with API-backed chart loading.
This commit is contained in:
@@ -6947,7 +6947,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_polls_answers_count#other" = "{count} answers";
|
||||
"lng_polls_answers_none" = "No answers";
|
||||
"lng_polls_submit_votes" = "Vote";
|
||||
"lng_polls_view_stats" = "View Stats";
|
||||
"lng_polls_view_results" = "View results";
|
||||
"lng_polls_stats_title" = "Poll Stats";
|
||||
"lng_polls_view_votes#one" = "View Votes ({count})";
|
||||
"lng_polls_view_votes#other" = "View Votes ({count})";
|
||||
"lng_polls_admin_votes#one" = "{count} vote {arrow}";
|
||||
|
||||
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "api/api_polls.h"
|
||||
|
||||
#include "api/api_common.h"
|
||||
#include "api/api_statistics_data_deserialize.h"
|
||||
#include "api/api_text_entities.h"
|
||||
#include "api/api_updates.h"
|
||||
#include "apiwrap.h"
|
||||
@@ -18,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_histories.h"
|
||||
#include "data/data_poll.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_statistics_chart.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/history_item_helpers.h" // ShouldSendSilent
|
||||
@@ -473,4 +475,50 @@ void Polls::reloadResults(not_null<HistoryItem*> item) {
|
||||
_pollReloadRequestIds.emplace(itemId, requestId);
|
||||
}
|
||||
|
||||
void Polls::requestStats(
|
||||
FullMsgId itemId,
|
||||
Fn<void(Data::StatisticalGraph)> done,
|
||||
Fn<void(QString)> fail) {
|
||||
const auto item = _session->data().message(itemId);
|
||||
if (!item || !item->isRegular()) {
|
||||
if (fail) {
|
||||
fail(QString());
|
||||
}
|
||||
return;
|
||||
}
|
||||
const auto requestGraph = [=](const QString &token) {
|
||||
_api.request(MTPstats_LoadAsyncGraph(
|
||||
MTP_flags(MTPstats_LoadAsyncGraph::Flag(0)),
|
||||
MTP_string(token),
|
||||
MTP_long(0)
|
||||
)).done([=](const MTPStatsGraph &result) {
|
||||
if (done) {
|
||||
done(Api::StatisticalGraphFromTL(result));
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
if (fail) {
|
||||
fail(error.type());
|
||||
}
|
||||
}).send();
|
||||
};
|
||||
_api.request(MTPstats_GetPollStats(
|
||||
MTP_flags(MTPstats_GetPollStats::Flags(0)),
|
||||
item->history()->peer->input(),
|
||||
MTP_int(item->id)
|
||||
)).done([=](const MTPstats_PollStats &result) {
|
||||
auto graph = Api::StatisticalGraphFromTL(result.data().vvotes_graph());
|
||||
if (graph.chart || !graph.error.isEmpty() || graph.zoomToken.isEmpty()) {
|
||||
if (done) {
|
||||
done(std::move(graph));
|
||||
}
|
||||
} else {
|
||||
requestGraph(graph.zoomToken);
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
if (fail) {
|
||||
fail(error.type());
|
||||
}
|
||||
}).send();
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
|
||||
@@ -14,6 +14,9 @@ class ApiWrap;
|
||||
class HistoryItem;
|
||||
struct PollData;
|
||||
struct PollMedia;
|
||||
namespace Data {
|
||||
struct StatisticalGraph;
|
||||
} // namespace Data
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
@@ -45,6 +48,10 @@ public:
|
||||
void deleteAnswer(FullMsgId itemId, const QByteArray &option);
|
||||
void close(not_null<HistoryItem*> item);
|
||||
void reloadResults(not_null<HistoryItem*> item);
|
||||
void requestStats(
|
||||
FullMsgId itemId,
|
||||
Fn<void(Data::StatisticalGraph)> done,
|
||||
Fn<void(QString)> fail);
|
||||
|
||||
private:
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
@@ -188,6 +188,21 @@ bool PollData::applyResults(const MTPPollResults &results) {
|
||||
const auto newTotalVoters
|
||||
= results.vtotal_voters().value_or(totalVoters);
|
||||
auto changed = (newTotalVoters != totalVoters);
|
||||
const auto setCanViewStats = [&](bool value) {
|
||||
const auto previous = (_flags & Flag::CanViewStats);
|
||||
if (previous == value) {
|
||||
return;
|
||||
}
|
||||
if (value) {
|
||||
_flags |= Flag::CanViewStats;
|
||||
} else {
|
||||
_flags &= ~Flag::CanViewStats;
|
||||
}
|
||||
changed = true;
|
||||
};
|
||||
if (!results.is_min() || results.is_can_view_stats()) {
|
||||
setCanViewStats(results.is_can_view_stats());
|
||||
}
|
||||
if (const auto list = results.vresults()) {
|
||||
for (const auto &result : list->v) {
|
||||
if (applyResultToAnswers(result, results.is_min())) {
|
||||
@@ -382,6 +397,10 @@ bool PollData::subscribersOnly() const {
|
||||
return (_flags & Flag::SubscribersOnly);
|
||||
}
|
||||
|
||||
bool PollData::canViewStats() const {
|
||||
return (_flags & Flag::CanViewStats);
|
||||
}
|
||||
|
||||
QString PollData::debugString() const {
|
||||
auto result = QString();
|
||||
result += u"Poll #"_q + QString::number(id) + u'\n';
|
||||
@@ -401,6 +420,9 @@ QString PollData::debugString() const {
|
||||
if (subscribersOnly()) {
|
||||
result += u"[SubscribersOnly]"_q;
|
||||
}
|
||||
if (canViewStats()) {
|
||||
result += u"[CanViewStats]"_q;
|
||||
}
|
||||
if (!result.endsWith(u'\n')) {
|
||||
result += u'\n';
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ struct PollData {
|
||||
HideResultsUntilClose = 0x080,
|
||||
Creator = 0x100,
|
||||
SubscribersOnly = 0x200,
|
||||
CanViewStats = 0x400,
|
||||
};
|
||||
friend inline constexpr bool is_flag_type(Flag) { return true; };
|
||||
using Flags = base::flags<Flag>;
|
||||
@@ -103,6 +104,7 @@ struct PollData {
|
||||
[[nodiscard]] bool hideResultsUntilClose() const;
|
||||
[[nodiscard]] bool creator() const;
|
||||
[[nodiscard]] bool subscribersOnly() const;
|
||||
[[nodiscard]] bool canViewStats() const;
|
||||
|
||||
[[nodiscard]] QString debugString() const;
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/history_item_text.h"
|
||||
#include "history/view/history_view_schedule_box.h"
|
||||
#include "history/view/media/history_view_media.h"
|
||||
#include "history/view/media/menu/history_view_poll_menu.h"
|
||||
#include "history/view/media/history_view_save_document_action.h"
|
||||
#include "history/view/media/history_view_web_page.h"
|
||||
#include "history/view/reactions/history_view_reactions_list.h"
|
||||
@@ -1891,10 +1892,15 @@ void AddPollActions(
|
||||
&& (context != Context::ChatPreview)) {
|
||||
return;
|
||||
}
|
||||
const auto itemId = item->fullId();
|
||||
if (poll->canViewStats() && item->isRegular()) {
|
||||
menu->addAction(tr::lng_polls_view_stats(tr::now), [=] {
|
||||
ShowPollStatsBox(controller, itemId);
|
||||
}, &st::menuIconStats);
|
||||
}
|
||||
if (poll->closed()) {
|
||||
return;
|
||||
}
|
||||
const auto itemId = item->fullId();
|
||||
if (!skipRetractVote
|
||||
&& poll->voted()
|
||||
&& !poll->quiz()
|
||||
|
||||
@@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_photo_media.h"
|
||||
#include "data/data_poll.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_statistics_chart.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "editor/editor_layer_widget.h"
|
||||
#include "editor/photo_editor.h"
|
||||
@@ -29,21 +30,28 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/view/media/history_view_document.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "layout/layout_document_generic_preview.h"
|
||||
#include "lottie/lottie_icon.h"
|
||||
#include "main/main_session.h"
|
||||
#include "poll/poll_media_upload.h"
|
||||
#include "statistics/chart_widget.h"
|
||||
#include "mainwidget.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "storage/localimageloader.h"
|
||||
#include "storage/storage_media_prepare.h"
|
||||
#include "chat_helpers/tabbed_panel.h"
|
||||
#include "chat_helpers/tabbed_selector.h"
|
||||
#include "ui/chat/attach/attach_prepare.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/rect.h"
|
||||
#include "ui/vertical_list.h"
|
||||
#include "ui/text/format_song_name.h"
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/widgets/dropdown_menu.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/menu/menu_action.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_chat.h"
|
||||
@@ -51,6 +59,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_media_view.h"
|
||||
#include "styles/style_menu_icons.h"
|
||||
#include "styles/style_settings.h"
|
||||
#include "styles/style_statistics.h"
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
namespace HistoryView {
|
||||
@@ -249,6 +259,104 @@ void FillPollAnswerMenu(
|
||||
}
|
||||
}
|
||||
|
||||
void ShowPollStatsBox(
|
||||
not_null<Window::SessionController*> controller,
|
||||
FullMsgId itemId) {
|
||||
controller->show(Box([=](not_null<Ui::GenericBox*> box) {
|
||||
box->setTitle(tr::lng_polls_stats_title());
|
||||
box->setWidth(st::boxWideWidth);
|
||||
|
||||
const auto content = box->addRow(
|
||||
object_ptr<Ui::VerticalLayout>(box),
|
||||
Margins(0));
|
||||
const auto loadingWrap = content->add(
|
||||
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||
content,
|
||||
object_ptr<Ui::VerticalLayout>(content)));
|
||||
loadingWrap->toggle(true, anim::type::instant);
|
||||
const auto loading = loadingWrap->entity();
|
||||
const auto resultWrap = content->add(
|
||||
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||
content,
|
||||
object_ptr<Ui::VerticalLayout>(content)));
|
||||
resultWrap->toggle(false, anim::type::instant);
|
||||
const auto result = resultWrap->entity();
|
||||
|
||||
auto icon = ::Settings::CreateLottieIcon(
|
||||
loading,
|
||||
{ .name = u"stats"_q, .sizeOverride = st::normalBoxLottieSize },
|
||||
st::settingsBlockedListIconPadding);
|
||||
loading->add(std::move(icon.widget));
|
||||
auto startAnimation = std::move(icon.animate);
|
||||
box->showFinishes(
|
||||
) | rpl::take(1) | rpl::on_next([=]() mutable {
|
||||
startAnimation(anim::repeat::loop);
|
||||
}, loading->lifetime());
|
||||
loading->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
loading,
|
||||
tr::lng_stats_loading(),
|
||||
st::changePhoneTitle),
|
||||
st::changePhoneTitlePadding + st::boxRowPadding,
|
||||
style::al_top);
|
||||
loading->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
loading,
|
||||
tr::lng_stats_loading_subtext(),
|
||||
st::statisticsLoadingSubtext),
|
||||
st::changePhoneDescriptionPadding + st::boxRowPadding,
|
||||
style::al_top
|
||||
)->setTryMakeSimilarLines(true);
|
||||
Ui::AddSkip(loading, st::settingsBlockedListIconPadding.top());
|
||||
const auto finishLoading = [=] {
|
||||
loading->clear();
|
||||
loadingWrap->toggle(false, anim::type::instant);
|
||||
resultWrap->toggle(true, anim::type::instant);
|
||||
};
|
||||
const auto showError = [=](QString error) {
|
||||
finishLoading();
|
||||
result->clear();
|
||||
result->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
result,
|
||||
error.isEmpty()
|
||||
? tr::lng_polls_votes_none(tr::now)
|
||||
: std::move(error),
|
||||
st::defaultFlatLabel),
|
||||
st::boxRowPadding + st::statisticsLayerMargins,
|
||||
style::al_center);
|
||||
};
|
||||
|
||||
controller->session().api().polls().requestStats(
|
||||
itemId,
|
||||
crl::guard(box, [=](Data::StatisticalGraph graph) {
|
||||
if (graph.chart) {
|
||||
finishLoading();
|
||||
result->clear();
|
||||
const auto chart = result->add(
|
||||
object_ptr<Statistic::ChartWidget>(result),
|
||||
st::statisticsLayerMargins);
|
||||
chart->setChartData(
|
||||
std::move(graph.chart),
|
||||
Statistic::ChartViewType::Linear);
|
||||
chart->setTitle(tr::lng_notification_reactions_poll_votes());
|
||||
Statistic::FixCacheForHighDPIChartWidget(result);
|
||||
} else {
|
||||
showError(!graph.error.isEmpty()
|
||||
? graph.error
|
||||
: tr::lng_polls_votes_none(tr::now));
|
||||
}
|
||||
}),
|
||||
crl::guard(box, [=](QString error) {
|
||||
showError(std::move(error));
|
||||
}));
|
||||
|
||||
box->addButton(tr::lng_box_ok(), [=] {
|
||||
box->closeBox();
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void AddRemoveAction(
|
||||
|
||||
@@ -52,6 +52,10 @@ void FillPollAnswerMenu(
|
||||
FullMsgId itemId,
|
||||
not_null<Window::SessionController*> controller);
|
||||
|
||||
void ShowPollStatsBox(
|
||||
not_null<Window::SessionController*> controller,
|
||||
FullMsgId itemId);
|
||||
|
||||
void ShowPollStickerPreview(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<DocumentData*> document,
|
||||
|
||||
Reference in New Issue
Block a user