mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-08-31 14:38:15 +00:00
Support task lists view/update/actions.
This commit is contained in:
204
Telegram/SourceFiles/api/api_todo_lists.cpp
Normal file
204
Telegram/SourceFiles/api/api_todo_lists.cpp
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "api/api_todo_lists.h"
|
||||
|
||||
//#include "api/api_common.h"
|
||||
//#include "api/api_updates.h"
|
||||
#include "apiwrap.h"
|
||||
//#include "base/random.h"
|
||||
//#include "data/business/data_shortcut_messages.h"
|
||||
//#include "data/data_changes.h"
|
||||
//#include "data/data_histories.h"
|
||||
#include "data/data_todo_list.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
//#include "history/history_item_helpers.h" // ShouldSendSilent
|
||||
#include "main/main_session.h"
|
||||
|
||||
namespace Api {
|
||||
namespace {
|
||||
|
||||
constexpr auto kSendTogglesDelay = 3 * crl::time(1000);
|
||||
|
||||
[[nodiscard]] TimeId UnixtimeFromMsgId(mtpMsgId msgId) {
|
||||
return TimeId(msgId >> 32);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TodoLists::TodoLists(not_null<ApiWrap*> api)
|
||||
: _session(&api->session())
|
||||
, _api(&api->instance())
|
||||
, _sendTimer([=] { sendAccumulatedToggles(false); }) {
|
||||
}
|
||||
//
|
||||
//void TodoLists::create(
|
||||
// const PollData &data,
|
||||
// SendAction action,
|
||||
// Fn<void()> done,
|
||||
// Fn<void()> fail) {
|
||||
// _session->api().sendAction(action);
|
||||
//
|
||||
// const auto history = action.history;
|
||||
// const auto peer = history->peer;
|
||||
// const auto topicRootId = action.replyTo.messageId
|
||||
// ? action.replyTo.topicRootId
|
||||
// : 0;
|
||||
// const auto monoforumPeerId = action.replyTo.monoforumPeerId;
|
||||
// auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
||||
// if (action.replyTo) {
|
||||
// sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to;
|
||||
// }
|
||||
// const auto clearCloudDraft = action.clearDraft;
|
||||
// if (clearCloudDraft) {
|
||||
// sendFlags |= MTPmessages_SendMedia::Flag::f_clear_draft;
|
||||
// history->clearLocalDraft(topicRootId, monoforumPeerId);
|
||||
// history->clearCloudDraft(topicRootId, monoforumPeerId);
|
||||
// history->startSavingCloudDraft(topicRootId, monoforumPeerId);
|
||||
// }
|
||||
// const auto silentPost = ShouldSendSilent(peer, action.options);
|
||||
// const auto starsPaid = std::min(
|
||||
// peer->starsPerMessageChecked(),
|
||||
// action.options.starsApproved);
|
||||
// if (silentPost) {
|
||||
// sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||
// }
|
||||
// if (action.options.scheduled) {
|
||||
// sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
|
||||
// }
|
||||
// if (action.options.shortcutId) {
|
||||
// sendFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut;
|
||||
// }
|
||||
// if (action.options.effectId) {
|
||||
// sendFlags |= MTPmessages_SendMedia::Flag::f_effect;
|
||||
// }
|
||||
// if (starsPaid) {
|
||||
// action.options.starsApproved -= starsPaid;
|
||||
// sendFlags |= MTPmessages_SendMedia::Flag::f_allow_paid_stars;
|
||||
// }
|
||||
// const auto sendAs = action.options.sendAs;
|
||||
// if (sendAs) {
|
||||
// sendFlags |= MTPmessages_SendMedia::Flag::f_send_as;
|
||||
// }
|
||||
// auto &histories = history->owner().histories();
|
||||
// const auto randomId = base::RandomValue<uint64>();
|
||||
// histories.sendPreparedMessage(
|
||||
// history,
|
||||
// action.replyTo,
|
||||
// randomId,
|
||||
// Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
|
||||
// MTP_flags(sendFlags),
|
||||
// peer->input,
|
||||
// Data::Histories::ReplyToPlaceholder(),
|
||||
// PollDataToInputMedia(&data),
|
||||
// MTP_string(),
|
||||
// MTP_long(randomId),
|
||||
// MTPReplyMarkup(),
|
||||
// MTPVector<MTPMessageEntity>(),
|
||||
// MTP_int(action.options.scheduled),
|
||||
// (sendAs ? sendAs->input : MTP_inputPeerEmpty()),
|
||||
// Data::ShortcutIdToMTP(_session, action.options.shortcutId),
|
||||
// MTP_long(action.options.effectId),
|
||||
// MTP_long(starsPaid)
|
||||
// ), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
// if (clearCloudDraft) {
|
||||
// history->finishSavingCloudDraft(
|
||||
// topicRootId,
|
||||
// monoforumPeerId,
|
||||
// UnixtimeFromMsgId(response.outerMsgId));
|
||||
// }
|
||||
// _session->changes().historyUpdated(
|
||||
// history,
|
||||
// (action.options.scheduled
|
||||
// ? Data::HistoryUpdate::Flag::ScheduledSent
|
||||
// : Data::HistoryUpdate::Flag::MessageSent));
|
||||
// done();
|
||||
// }, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||
// if (clearCloudDraft) {
|
||||
// history->finishSavingCloudDraft(
|
||||
// topicRootId,
|
||||
// monoforumPeerId,
|
||||
// UnixtimeFromMsgId(response.outerMsgId));
|
||||
// }
|
||||
// fail();
|
||||
// });
|
||||
//}
|
||||
|
||||
void TodoLists::toggleCompletion(FullMsgId itemId, int id, bool completed) {
|
||||
auto &entry = _toggles[itemId];
|
||||
if (completed) {
|
||||
if (!entry.completed.emplace(id).second) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!entry.incompleted.emplace(id).second) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
entry.scheduled = crl::now();
|
||||
if (!entry.requestId && !_sendTimer.isActive()) {
|
||||
_sendTimer.callOnce(kSendTogglesDelay);
|
||||
}
|
||||
}
|
||||
|
||||
void TodoLists::sendAccumulatedToggles(bool force) {
|
||||
const auto now = crl::now();
|
||||
auto nearest = crl::time(0);
|
||||
for (auto &[itemId, entry] : _toggles) {
|
||||
if (entry.requestId) {
|
||||
continue;
|
||||
}
|
||||
const auto wait = entry.scheduled + kSendTogglesDelay - now;
|
||||
if (wait <= 0) {
|
||||
entry.scheduled = 0;
|
||||
send(itemId, entry);
|
||||
} else if (!nearest || nearest > wait) {
|
||||
nearest = wait;
|
||||
}
|
||||
}
|
||||
if (nearest > 0) {
|
||||
_sendTimer.callOnce(nearest);
|
||||
}
|
||||
}
|
||||
|
||||
void TodoLists::send(FullMsgId itemId, Accumulated &entry) {
|
||||
const auto item = _session->data().message(itemId);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
auto completed = entry.completed
|
||||
| ranges::views::transform([](int id) { return MTP_int(id); });
|
||||
auto incompleted = entry.incompleted
|
||||
| ranges::views::transform([](int id) { return MTP_int(id); });
|
||||
entry.requestId = _api.request(MTPmessages_ToggleTodoCompleted(
|
||||
item->history()->peer->input,
|
||||
MTP_int(item->id),
|
||||
MTP_vector_from_range(completed),
|
||||
MTP_vector_from_range(incompleted)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
_session->api().applyUpdates(result);
|
||||
finishRequest(itemId);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
finishRequest(itemId);
|
||||
}).send();
|
||||
entry.completed.clear();
|
||||
entry.incompleted.clear();
|
||||
}
|
||||
|
||||
void TodoLists::finishRequest(FullMsgId itemId) {
|
||||
auto &entry = _toggles[itemId];
|
||||
entry.requestId = 0;
|
||||
if (entry.completed.empty() && entry.incompleted.empty()) {
|
||||
_toggles.remove(itemId);
|
||||
} else {
|
||||
sendAccumulatedToggles(false);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Api
|
56
Telegram/SourceFiles/api/api_todo_lists.h
Normal file
56
Telegram/SourceFiles/api/api_todo_lists.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "base/timer.h"
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
class ApiWrap;
|
||||
class HistoryItem;
|
||||
struct TodoListData;
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Api {
|
||||
|
||||
struct SendAction;
|
||||
|
||||
class TodoLists final {
|
||||
public:
|
||||
explicit TodoLists(not_null<ApiWrap*> api);
|
||||
|
||||
//void create(
|
||||
// const PollData &data,
|
||||
// SendAction action,
|
||||
// Fn<void()> done,
|
||||
// Fn<void()> fail);
|
||||
void toggleCompletion(FullMsgId itemId, int id, bool completed);
|
||||
|
||||
private:
|
||||
struct Accumulated {
|
||||
base::flat_set<int> completed;
|
||||
base::flat_set<int> incompleted;
|
||||
crl::time scheduled = 0;
|
||||
mtpRequestId requestId = 0;
|
||||
};
|
||||
|
||||
void sendAccumulatedToggles(bool force);
|
||||
void send(FullMsgId itemId, Accumulated &entry);
|
||||
void finishRequest(FullMsgId itemId);
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
MTP::Sender _api;
|
||||
|
||||
base::flat_map<FullMsgId, Accumulated> _toggles;
|
||||
base::Timer _sendTimer;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Api
|
@@ -1916,7 +1916,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
|
||||
// Update web page anyway.
|
||||
session().data().processWebpage(d.vwebpage());
|
||||
session().data().sendWebPageGamePollNotifications();
|
||||
session().data().sendWebPageGamePollTodoListNotifications();
|
||||
|
||||
updateAndApply(d.vpts().v, d.vpts_count().v, update);
|
||||
} break;
|
||||
@@ -1926,7 +1926,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||
|
||||
// Update web page anyway.
|
||||
session().data().processWebpage(d.vwebpage());
|
||||
session().data().sendWebPageGamePollNotifications();
|
||||
session().data().sendWebPageGamePollTodoListNotifications();
|
||||
|
||||
auto channel = session().data().channelLoaded(d.vchannel_id());
|
||||
if (channel && !_handlingChannelDifference) {
|
||||
|
Reference in New Issue
Block a user