mirror of https://github.com/procxx/kepka.git
Allow to schedule created polls.
This commit is contained in:
parent
8eac2dcb78
commit
ef7087348a
|
@ -16,6 +16,11 @@ struct SendOptions {
|
||||||
bool removeWebPageId = false;
|
bool removeWebPageId = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class SendType {
|
||||||
|
Normal,
|
||||||
|
Scheduled,
|
||||||
|
};
|
||||||
|
|
||||||
struct SendAction {
|
struct SendAction {
|
||||||
explicit SendAction(not_null<History*> history) : history(history) {
|
explicit SendAction(not_null<History*> history) : history(history) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "core/event_filter.h"
|
#include "core/event_filter.h"
|
||||||
#include "chat_helpers/emoji_suggestions_widget.h"
|
#include "chat_helpers/emoji_suggestions_widget.h"
|
||||||
|
#include "chat_helpers/message_field.h"
|
||||||
|
#include "history/view/history_view_schedule_box.h"
|
||||||
#include "settings/settings_common.h"
|
#include "settings/settings_common.h"
|
||||||
#include "base/unique_qptr.h"
|
#include "base/unique_qptr.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
|
@ -592,11 +594,15 @@ void Options::checkLastOption() {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
CreatePollBox::CreatePollBox(QWidget*, not_null<Main::Session*> session)
|
CreatePollBox::CreatePollBox(
|
||||||
: _session(session) {
|
QWidget*,
|
||||||
|
not_null<Main::Session*> session,
|
||||||
|
Api::SendType sendType)
|
||||||
|
: _session(session)
|
||||||
|
, _sendType(sendType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<PollData> CreatePollBox::submitRequests() const {
|
rpl::producer<CreatePollBox::Result> CreatePollBox::submitRequests() const {
|
||||||
return _submitRequests.events();
|
return _submitRequests.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -703,6 +709,19 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
|
||||||
result.answers = options->toPollAnswers();
|
result.answers = options->toPollAnswers();
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
const auto send = [=](Api::SendOptions options) {
|
||||||
|
_submitRequests.fire({ collectResult(), options });
|
||||||
|
};
|
||||||
|
const auto sendSilent = [=] {
|
||||||
|
auto options = Api::SendOptions();
|
||||||
|
options.silent = true;
|
||||||
|
send(options);
|
||||||
|
};
|
||||||
|
const auto sendScheduled = [=] {
|
||||||
|
Ui::show(
|
||||||
|
HistoryView::PrepareScheduleBox(this, send),
|
||||||
|
LayerOption::KeepOther);
|
||||||
|
};
|
||||||
const auto updateValid = [=] {
|
const auto updateValid = [=] {
|
||||||
valid->fire(isValidQuestion() && options->isValid());
|
valid->fire(isValidQuestion() && options->isValid());
|
||||||
};
|
};
|
||||||
|
@ -715,9 +734,16 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
|
||||||
) | rpl::start_with_next([=](bool valid) {
|
) | rpl::start_with_next([=](bool valid) {
|
||||||
clearButtons();
|
clearButtons();
|
||||||
if (valid) {
|
if (valid) {
|
||||||
addButton(
|
const auto submit = addButton(
|
||||||
tr::lng_polls_create_button(),
|
tr::lng_polls_create_button(),
|
||||||
[=] { _submitRequests.fire(collectResult()); });
|
[=] { send({}); });
|
||||||
|
if (_sendType == Api::SendType::Normal) {
|
||||||
|
SetupSendMenu(
|
||||||
|
submit.data(),
|
||||||
|
[=] { return true; },
|
||||||
|
sendSilent,
|
||||||
|
sendScheduled);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
|
@ -8,6 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "boxes/abstract_box.h"
|
#include "boxes/abstract_box.h"
|
||||||
|
#include "api/api_common.h"
|
||||||
|
#include "data/data_poll.h"
|
||||||
|
|
||||||
struct PollData;
|
struct PollData;
|
||||||
|
|
||||||
|
@ -21,9 +23,17 @@ class Session;
|
||||||
|
|
||||||
class CreatePollBox : public BoxContent {
|
class CreatePollBox : public BoxContent {
|
||||||
public:
|
public:
|
||||||
CreatePollBox(QWidget*, not_null<Main::Session*> session);
|
struct Result {
|
||||||
|
PollData poll;
|
||||||
|
Api::SendOptions options;
|
||||||
|
};
|
||||||
|
|
||||||
rpl::producer<PollData> submitRequests() const;
|
CreatePollBox(
|
||||||
|
QWidget*,
|
||||||
|
not_null<Main::Session*> session,
|
||||||
|
Api::SendType sendType);
|
||||||
|
|
||||||
|
rpl::producer<Result> submitRequests() const;
|
||||||
void submitFailed(const QString &error);
|
void submitFailed(const QString &error);
|
||||||
|
|
||||||
void setInnerFocus() override;
|
void setInnerFocus() override;
|
||||||
|
@ -37,8 +47,9 @@ private:
|
||||||
not_null<Ui::VerticalLayout*> container);
|
not_null<Ui::VerticalLayout*> container);
|
||||||
|
|
||||||
const not_null<Main::Session*> _session;
|
const not_null<Main::Session*> _session;
|
||||||
|
const Api::SendType _sendType = Api::SendType();
|
||||||
Fn<void()> _setInnerFocus;
|
Fn<void()> _setInnerFocus;
|
||||||
Fn<rpl::producer<bool>()> _dataIsValidValue;
|
Fn<rpl::producer<bool>()> _dataIsValidValue;
|
||||||
rpl::event_stream<PollData> _submitRequests;
|
rpl::event_stream<Result> _submitRequests;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1368,8 +1368,10 @@ SendFilesBox::SendFilesBox(
|
||||||
Storage::PreparedList &&list,
|
Storage::PreparedList &&list,
|
||||||
const TextWithTags &caption,
|
const TextWithTags &caption,
|
||||||
CompressConfirm compressed,
|
CompressConfirm compressed,
|
||||||
SendLimit limit)
|
SendLimit limit,
|
||||||
|
Api::SendType sendType)
|
||||||
: _controller(controller)
|
: _controller(controller)
|
||||||
|
, _sendType(sendType)
|
||||||
, _list(std::move(list))
|
, _list(std::move(list))
|
||||||
, _compressConfirmInitial(compressed)
|
, _compressConfirmInitial(compressed)
|
||||||
, _compressConfirm(compressed)
|
, _compressConfirm(compressed)
|
||||||
|
@ -1471,11 +1473,13 @@ void SendFilesBox::setupShadows(
|
||||||
|
|
||||||
void SendFilesBox::prepare() {
|
void SendFilesBox::prepare() {
|
||||||
_send = addButton(tr::lng_send_button(), [=] { send({}); });
|
_send = addButton(tr::lng_send_button(), [=] { send({}); });
|
||||||
SetupSendWithoutSound(
|
if (_sendType == Api::SendType::Normal) {
|
||||||
_send,
|
SetupSendMenu(
|
||||||
[=] { return true; },
|
_send,
|
||||||
[=] { sendSilent(); },
|
[=] { return true; },
|
||||||
[=] { sendScheduled(); });
|
[=] { sendSilent(); },
|
||||||
|
[=] { sendScheduled(); });
|
||||||
|
}
|
||||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||||
initSendWay();
|
initSendWay();
|
||||||
setupCaption();
|
setupCaption();
|
||||||
|
@ -1922,6 +1926,10 @@ void SendFilesBox::setInnerFocus() {
|
||||||
void SendFilesBox::send(
|
void SendFilesBox::send(
|
||||||
Api::SendOptions options,
|
Api::SendOptions options,
|
||||||
bool ctrlShiftEnter) {
|
bool ctrlShiftEnter) {
|
||||||
|
if (_sendType == Api::SendType::Scheduled && !options.scheduled) {
|
||||||
|
return sendScheduled();
|
||||||
|
}
|
||||||
|
|
||||||
using Way = SendFilesWay;
|
using Way = SendFilesWay;
|
||||||
const auto way = _sendWay ? _sendWay->value() : Way::Files;
|
const auto way = _sendWay ? _sendWay->value() : Way::Files;
|
||||||
|
|
||||||
|
@ -1963,14 +1971,9 @@ void SendFilesBox::sendSilent() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendFilesBox::sendScheduled() {
|
void SendFilesBox::sendScheduled() {
|
||||||
const auto callback = crl::guard(this, [=](Api::SendOptions options) {
|
const auto callback = [=](Api::SendOptions options) { send(options); };
|
||||||
send(options);
|
|
||||||
});
|
|
||||||
Ui::show(
|
Ui::show(
|
||||||
Box(
|
HistoryView::PrepareScheduleBox(this, callback),
|
||||||
HistoryView::ScheduleBox,
|
|
||||||
callback,
|
|
||||||
HistoryView::DefaultScheduleTime()),
|
|
||||||
LayerOption::KeepOther);
|
LayerOption::KeepOther);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ class SessionController;
|
||||||
|
|
||||||
namespace Api {
|
namespace Api {
|
||||||
struct SendOptions;
|
struct SendOptions;
|
||||||
|
enum class SendType;
|
||||||
} // namespace Api
|
} // namespace Api
|
||||||
|
|
||||||
namespace ChatHelpers {
|
namespace ChatHelpers {
|
||||||
|
@ -57,7 +58,8 @@ public:
|
||||||
Storage::PreparedList &&list,
|
Storage::PreparedList &&list,
|
||||||
const TextWithTags &caption,
|
const TextWithTags &caption,
|
||||||
CompressConfirm compressed,
|
CompressConfirm compressed,
|
||||||
SendLimit limit);
|
SendLimit limit,
|
||||||
|
Api::SendType sendType);
|
||||||
|
|
||||||
void setConfirmedCallback(
|
void setConfirmedCallback(
|
||||||
Fn<void(
|
Fn<void(
|
||||||
|
@ -119,7 +121,8 @@ private:
|
||||||
bool canAddUrls(const QList<QUrl> &urls) const;
|
bool canAddUrls(const QList<QUrl> &urls) const;
|
||||||
bool addFiles(not_null<const QMimeData*> data);
|
bool addFiles(not_null<const QMimeData*> data);
|
||||||
|
|
||||||
not_null<Window::SessionController*> _controller;
|
const not_null<Window::SessionController*> _controller;
|
||||||
|
const Api::SendType _sendType = Api::SendType();
|
||||||
|
|
||||||
QString _titleText;
|
QString _titleText;
|
||||||
int _titleHeight = 0;
|
int _titleHeight = 0;
|
||||||
|
|
|
@ -415,7 +415,7 @@ void ShareBox::createButtons() {
|
||||||
const auto send = addButton(tr::lng_share_confirm(), [=] {
|
const auto send = addButton(tr::lng_share_confirm(), [=] {
|
||||||
submit({});
|
submit({});
|
||||||
});
|
});
|
||||||
SetupSendWithoutSound(
|
SetupSendMenu(
|
||||||
send,
|
send,
|
||||||
[=] { return true; },
|
[=] { return true; },
|
||||||
[=] { submitSilent(); },
|
[=] { submitSilent(); },
|
||||||
|
@ -469,14 +469,9 @@ void ShareBox::submitSilent() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShareBox::submitScheduled() {
|
void ShareBox::submitScheduled() {
|
||||||
const auto callback = crl::guard(this, [=](Api::SendOptions options) {
|
const auto callback = [=](Api::SendOptions options) { submit(options); };
|
||||||
submit(options);
|
|
||||||
});
|
|
||||||
Ui::show(
|
Ui::show(
|
||||||
Box(
|
HistoryView::PrepareScheduleBox(this, callback),
|
||||||
HistoryView::ScheduleBox,
|
|
||||||
callback,
|
|
||||||
HistoryView::DefaultScheduleTime()),
|
|
||||||
LayerOption::KeepOther);
|
LayerOption::KeepOther);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -784,7 +784,7 @@ void MessageLinksParser::apply(
|
||||||
_list = std::move(parsed);
|
_list = std::move(parsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetupSendWithoutSound(
|
void SetupSendMenu(
|
||||||
not_null<Ui::RpWidget*> button,
|
not_null<Ui::RpWidget*> button,
|
||||||
Fn<bool()> enabled,
|
Fn<bool()> enabled,
|
||||||
Fn<void()> send,
|
Fn<void()> send,
|
||||||
|
|
|
@ -106,7 +106,7 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void SetupSendWithoutSound(
|
void SetupSendMenu(
|
||||||
not_null<Ui::RpWidget*> button,
|
not_null<Ui::RpWidget*> button,
|
||||||
Fn<bool()> enabled,
|
Fn<bool()> enabled,
|
||||||
Fn<void()> send,
|
Fn<void()> send,
|
||||||
|
|
|
@ -237,7 +237,6 @@ void ScheduledMessages::parse(
|
||||||
auto &request = _requests[history];
|
auto &request = _requests[history];
|
||||||
request.requestId = 0;
|
request.requestId = 0;
|
||||||
|
|
||||||
auto element = _data.find(history);
|
|
||||||
list.match([&](const MTPDmessages_messagesNotModified &data) {
|
list.match([&](const MTPDmessages_messagesNotModified &data) {
|
||||||
}, [&](const auto &data) {
|
}, [&](const auto &data) {
|
||||||
_session->data().processUsers(data.vusers());
|
_session->data().processUsers(data.vusers());
|
||||||
|
@ -245,38 +244,24 @@ void ScheduledMessages::parse(
|
||||||
|
|
||||||
const auto &messages = data.vmessages().v;
|
const auto &messages = data.vmessages().v;
|
||||||
if (messages.isEmpty()) {
|
if (messages.isEmpty()) {
|
||||||
if (element != end(_data)) {
|
clearNotSending(history);
|
||||||
_data.erase(element);
|
|
||||||
element = end(_data);
|
|
||||||
_updates.fire_copy(history);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
element = _data.emplace(history, List()).first;
|
|
||||||
auto received = base::flat_set<not_null<HistoryItem*>>();
|
auto received = base::flat_set<not_null<HistoryItem*>>();
|
||||||
auto &list = element->second;
|
auto clear = base::flat_set<not_null<HistoryItem*>>();
|
||||||
|
auto &list = _data.emplace(history, List()).first->second;
|
||||||
for (const auto &message : messages) {
|
for (const auto &message : messages) {
|
||||||
if (const auto item = append(history, list, message)) {
|
if (const auto item = append(history, list, message)) {
|
||||||
received.emplace(item);
|
received.emplace(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto clear = base::flat_set<not_null<HistoryItem*>>();
|
|
||||||
for (const auto &owned : list.items) {
|
for (const auto &owned : list.items) {
|
||||||
const auto item = owned.get();
|
const auto item = owned.get();
|
||||||
if (!item->isSending() && !received.contains(item)) {
|
if (!item->isSending() && !received.contains(item)) {
|
||||||
clear.emplace(item);
|
clear.emplace(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const auto item : clear) {
|
updated(history, received, clear);
|
||||||
item->destroy();
|
|
||||||
}
|
|
||||||
if (!list.items.empty()) {
|
|
||||||
sort(list);
|
|
||||||
} else {
|
|
||||||
_data.erase(element);
|
|
||||||
element = end(_data);
|
|
||||||
}
|
|
||||||
_updates.fire_copy(history);
|
|
||||||
});
|
});
|
||||||
if (!request.requestId) {
|
if (!request.requestId) {
|
||||||
_requests.remove(history);
|
_requests.remove(history);
|
||||||
|
@ -320,6 +305,38 @@ HistoryItem *ScheduledMessages::append(
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScheduledMessages::clearNotSending(not_null<History*> history) {
|
||||||
|
const auto i = _data.find(history);
|
||||||
|
if (i == end(_data)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto clear = base::flat_set<not_null<HistoryItem*>>();
|
||||||
|
for (const auto &owned : i->second.items) {
|
||||||
|
if (!owned->isSending()) {
|
||||||
|
clear.emplace(owned.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updated(history, {}, clear);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledMessages::updated(
|
||||||
|
not_null<History*> history,
|
||||||
|
const base::flat_set<not_null<HistoryItem*>> &added,
|
||||||
|
const base::flat_set<not_null<HistoryItem*>> &clear) {
|
||||||
|
if (!clear.empty()) {
|
||||||
|
for (const auto item : clear) {
|
||||||
|
item->destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const auto i = _data.find(history);
|
||||||
|
if (i != end(_data)) {
|
||||||
|
sort(i->second);
|
||||||
|
}
|
||||||
|
if (!added.empty() || !clear.empty()) {
|
||||||
|
_updates.fire_copy(history);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ScheduledMessages::sort(List &list) {
|
void ScheduledMessages::sort(List &list) {
|
||||||
ranges::sort(list.items, ranges::less(), &HistoryItem::position);
|
ranges::sort(list.items, ranges::less(), &HistoryItem::position);
|
||||||
}
|
}
|
||||||
|
@ -330,11 +347,12 @@ void ScheduledMessages::remove(not_null<const HistoryItem*> item) {
|
||||||
Assert(i != end(_data));
|
Assert(i != end(_data));
|
||||||
auto &list = i->second;
|
auto &list = i->second;
|
||||||
|
|
||||||
const auto j = list.idByItem.find(item);
|
if (!item->isSending()) {
|
||||||
Assert(j != end(list.idByItem));
|
const auto j = list.idByItem.find(item);
|
||||||
list.itemById.remove(j->second);
|
Assert(j != end(list.idByItem));
|
||||||
list.idByItem.erase(j);
|
list.itemById.remove(j->second);
|
||||||
|
list.idByItem.erase(j);
|
||||||
|
}
|
||||||
const auto k = ranges::find(list.items, item, &OwnedItem::get);
|
const auto k = ranges::find(list.items, item, &OwnedItem::get);
|
||||||
Assert(k != list.items.end());
|
Assert(k != list.items.end());
|
||||||
k->release();
|
k->release();
|
||||||
|
|
|
@ -61,6 +61,11 @@ private:
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
List &list,
|
List &list,
|
||||||
const MTPMessage &message);
|
const MTPMessage &message);
|
||||||
|
void clearNotSending(not_null<History*> history);
|
||||||
|
void updated(
|
||||||
|
not_null<History*> history,
|
||||||
|
const base::flat_set<not_null<HistoryItem*>> &added,
|
||||||
|
const base::flat_set<not_null<HistoryItem*>> &clear);
|
||||||
void sort(List &list);
|
void sort(List &list);
|
||||||
void remove(not_null<const HistoryItem*> item);
|
void remove(not_null<const HistoryItem*> item);
|
||||||
[[nodiscard]] int32 countListHash(const List &list) const;
|
[[nodiscard]] int32 countListHash(const List &list) const;
|
||||||
|
|
|
@ -300,7 +300,7 @@ HistoryWidget::HistoryWidget(
|
||||||
_unreadMentions->addClickHandler([=] { showNextUnreadMention(); });
|
_unreadMentions->addClickHandler([=] { showNextUnreadMention(); });
|
||||||
_fieldBarCancel->addClickHandler([=] { cancelFieldAreaState(); });
|
_fieldBarCancel->addClickHandler([=] { cancelFieldAreaState(); });
|
||||||
_send->addClickHandler([=] { sendButtonClicked(); });
|
_send->addClickHandler([=] { sendButtonClicked(); });
|
||||||
SetupSendWithoutSound(_send, [=] {
|
SetupSendMenu(_send, [=] {
|
||||||
return (_send->type() == Ui::SendButton::Type::Send)
|
return (_send->type() == Ui::SendButton::Type::Send)
|
||||||
&& !_send->isDisabled();
|
&& !_send->isDisabled();
|
||||||
}, [=] { sendSilent(); }, [=] { sendScheduled(); });
|
}, [=] { sendSilent(); }, [=] { sendScheduled(); });
|
||||||
|
@ -1747,11 +1747,11 @@ void HistoryWidget::showHistory(
|
||||||
updateControlsGeometry();
|
updateControlsGeometry();
|
||||||
}, _contactStatus->lifetime());
|
}, _contactStatus->lifetime());
|
||||||
orderWidgets();
|
orderWidgets();
|
||||||
|
controller()->tabbedSelector()->setCurrentPeer(_peer);
|
||||||
} else {
|
} else {
|
||||||
_contactStatus = nullptr;
|
_contactStatus = nullptr;
|
||||||
}
|
}
|
||||||
refreshTabbedPanel();
|
refreshTabbedPanel();
|
||||||
controller()->tabbedSelector()->setCurrentPeer(_peer);
|
|
||||||
|
|
||||||
if (_peer) {
|
if (_peer) {
|
||||||
_unblock->setText(((_peer->isUser()
|
_unblock->setText(((_peer->isUser()
|
||||||
|
@ -2970,14 +2970,9 @@ void HistoryWidget::sendScheduled() {
|
||||||
if (!_list) {
|
if (!_list) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto callback = crl::guard(_list, [=](Api::SendOptions options) {
|
const auto callback = [=](Api::SendOptions options) { send(options); };
|
||||||
send(options);
|
|
||||||
});
|
|
||||||
Ui::show(
|
Ui::show(
|
||||||
Box(
|
HistoryView::PrepareScheduleBox(_list, callback),
|
||||||
HistoryView::ScheduleBox,
|
|
||||||
callback,
|
|
||||||
HistoryView::DefaultScheduleTime()),
|
|
||||||
LayerOption::KeepOther);
|
LayerOption::KeepOther);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4192,7 +4187,8 @@ bool HistoryWidget::confirmSendingFiles(
|
||||||
std::move(list),
|
std::move(list),
|
||||||
text,
|
text,
|
||||||
boxCompressConfirm,
|
boxCompressConfirm,
|
||||||
_peer->slowmodeApplied() ? SendLimit::One : SendLimit::Many);
|
_peer->slowmodeApplied() ? SendLimit::One : SendLimit::Many,
|
||||||
|
Api::SendType::Normal);
|
||||||
_field->setTextWithTags({});
|
_field->setTextWithTags({});
|
||||||
box->setConfirmedCallback(crl::guard(this, [=](
|
box->setConfirmedCallback(crl::guard(this, [=](
|
||||||
Storage::PreparedList &&list,
|
Storage::PreparedList &&list,
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/special_buttons.h"
|
#include "ui/special_buttons.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "core/event_filter.h"
|
#include "core/event_filter.h"
|
||||||
|
#include "history/history.h"
|
||||||
#include "chat_helpers/tabbed_panel.h"
|
#include "chat_helpers/tabbed_panel.h"
|
||||||
#include "chat_helpers/tabbed_section.h"
|
#include "chat_helpers/tabbed_section.h"
|
||||||
#include "chat_helpers/tabbed_selector.h"
|
#include "chat_helpers/tabbed_selector.h"
|
||||||
|
@ -54,6 +55,15 @@ Main::Session &ComposeControls::session() const {
|
||||||
return _window->session();
|
return _window->session();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ComposeControls::setHistory(History *history) {
|
||||||
|
if (_history == history) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_history = history;
|
||||||
|
_window->tabbedSelector()->setCurrentPeer(
|
||||||
|
history ? history->peer.get() : nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
void ComposeControls::move(int x, int y) {
|
void ComposeControls::move(int x, int y) {
|
||||||
_wrap->move(x, y);
|
_wrap->move(x, y);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,8 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] Main::Session &session() const;
|
[[nodiscard]] Main::Session &session() const;
|
||||||
|
|
||||||
|
void setHistory(History *history);
|
||||||
|
|
||||||
void move(int x, int y);
|
void move(int x, int y);
|
||||||
void resizeToWidth(int width);
|
void resizeToWidth(int width);
|
||||||
[[nodiscard]] rpl::producer<int> height() const;
|
[[nodiscard]] rpl::producer<int> height() const;
|
||||||
|
@ -102,6 +104,7 @@ private:
|
||||||
|
|
||||||
const not_null<QWidget*> _parent;
|
const not_null<QWidget*> _parent;
|
||||||
const not_null<Window::SessionController*> _window;
|
const not_null<Window::SessionController*> _window;
|
||||||
|
History *_history = nullptr;
|
||||||
Mode _mode = Mode::Normal;
|
Mode _mode = Mode::Normal;
|
||||||
|
|
||||||
const std::unique_ptr<Ui::RpWidget> _wrap;
|
const std::unique_ptr<Ui::RpWidget> _wrap;
|
||||||
|
|
|
@ -13,7 +13,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "boxes/calendar_box.h"
|
#include "boxes/calendar_box.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
#include "ui/widgets/labels.h"
|
#include "ui/widgets/labels.h"
|
||||||
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/wrap/padding_wrap.h"
|
#include "ui/wrap/padding_wrap.h"
|
||||||
|
#include "chat_helpers/message_field.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
#include "styles/style_history.h"
|
#include "styles/style_history.h"
|
||||||
|
|
||||||
|
@ -88,6 +90,7 @@ public:
|
||||||
|
|
||||||
bool setFocusFast();
|
bool setFocusFast();
|
||||||
rpl::producer<QString> value() const;
|
rpl::producer<QString> value() const;
|
||||||
|
rpl::producer<> submitRequests() const;
|
||||||
QString valueCurrent() const;
|
QString valueCurrent() const;
|
||||||
void showError();
|
void showError();
|
||||||
|
|
||||||
|
@ -117,6 +120,7 @@ private:
|
||||||
object_ptr<Ui::PaddingWrap<Ui::FlatLabel>> _separator1;
|
object_ptr<Ui::PaddingWrap<Ui::FlatLabel>> _separator1;
|
||||||
object_ptr<TimePart> _minute;
|
object_ptr<TimePart> _minute;
|
||||||
rpl::variable<QString> _value;
|
rpl::variable<QString> _value;
|
||||||
|
rpl::event_stream<> _submitRequests;
|
||||||
|
|
||||||
style::cursor _cursor = style::cur_default;
|
style::cursor _cursor = style::cur_default;
|
||||||
Ui::Animations::Simple _a_borderShown;
|
Ui::Animations::Simple _a_borderShown;
|
||||||
|
@ -293,6 +297,29 @@ TimeInput::TimeInput(QWidget *parent, const QString &value)
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
setErrorShown(false);
|
setErrorShown(false);
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
const auto submitHour = [=] {
|
||||||
|
if (hour()) {
|
||||||
|
_minute->setFocus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const auto submitMinute = [=] {
|
||||||
|
if (minute()) {
|
||||||
|
if (hour()) {
|
||||||
|
_submitRequests.fire({});
|
||||||
|
} else {
|
||||||
|
_hour->setFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
connect(
|
||||||
|
_hour,
|
||||||
|
&Ui::MaskedInputField::submitted,
|
||||||
|
submitHour);
|
||||||
|
connect(
|
||||||
|
_minute,
|
||||||
|
&Ui::MaskedInputField::submitted,
|
||||||
|
submitMinute);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimeInput::putNext(const object_ptr<TimePart> &field, QChar ch) {
|
void TimeInput::putNext(const object_ptr<TimePart> &field, QChar ch) {
|
||||||
|
@ -350,6 +377,10 @@ rpl::producer<QString> TimeInput::value() const {
|
||||||
return _value.value();
|
return _value.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpl::producer<> TimeInput::submitRequests() const {
|
||||||
|
return _submitRequests.events();
|
||||||
|
}
|
||||||
|
|
||||||
void TimeInput::paintEvent(QPaintEvent *e) {
|
void TimeInput::paintEvent(QPaintEvent *e) {
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
|
|
||||||
|
@ -584,23 +615,30 @@ void ScheduleBox(
|
||||||
|
|
||||||
const auto shared = std::make_shared<FnMut<void(Api::SendOptions)>>(
|
const auto shared = std::make_shared<FnMut<void(Api::SendOptions)>>(
|
||||||
std::move(done));
|
std::move(done));
|
||||||
const auto save = [=] {
|
const auto collect = [=] {
|
||||||
auto result = Api::SendOptions();
|
|
||||||
|
|
||||||
const auto timeValue = timeInput->valueCurrent().split(':');
|
const auto timeValue = timeInput->valueCurrent().split(':');
|
||||||
if (timeValue.size() != 2) {
|
if (timeValue.size() != 2) {
|
||||||
timeInput->showError();
|
timeInput->showError();
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
const auto time = QTime(timeValue[0].toInt(), timeValue[1].toInt());
|
const auto time = QTime(timeValue[0].toInt(), timeValue[1].toInt());
|
||||||
if (!time.isValid()) {
|
if (!time.isValid()) {
|
||||||
timeInput->showError();
|
timeInput->showError();
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
result.scheduled = base::unixtime::serialize(
|
const auto result = base::unixtime::serialize(
|
||||||
QDateTime(date->current(), time));
|
QDateTime(date->current(), time));
|
||||||
if (result.scheduled <= base::unixtime::now() + kMinimalSchedule) {
|
if (result <= base::unixtime::now() + kMinimalSchedule) {
|
||||||
timeInput->showError();
|
timeInput->showError();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
const auto save = [=](bool silent) {
|
||||||
|
auto result = Api::SendOptions();
|
||||||
|
result.silent = silent;
|
||||||
|
result.scheduled = collect();
|
||||||
|
if (!result.scheduled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -608,9 +646,20 @@ void ScheduleBox(
|
||||||
box->closeBox();
|
box->closeBox();
|
||||||
(*copy)(result);
|
(*copy)(result);
|
||||||
};
|
};
|
||||||
|
timeInput->submitRequests(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
save(false);
|
||||||
|
}, timeInput->lifetime());
|
||||||
|
|
||||||
box->setFocusCallback([=] { timeInput->setFocusFast(); });
|
box->setFocusCallback([=] { timeInput->setFocusFast(); });
|
||||||
box->addButton(tr::lng_settings_save(), save);
|
const auto submit = box->addButton(tr::lng_settings_save(), [=] {
|
||||||
|
save(false);
|
||||||
|
});
|
||||||
|
SetupSendMenu(
|
||||||
|
submit.data(),
|
||||||
|
[=] { return true; },
|
||||||
|
[=] { save(true); },
|
||||||
|
nullptr);
|
||||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,4 +21,14 @@ void ScheduleBox(
|
||||||
FnMut<void(Api::SendOptions)> done,
|
FnMut<void(Api::SendOptions)> done,
|
||||||
TimeId time);
|
TimeId time);
|
||||||
|
|
||||||
|
template <typename Guard, typename Submit>
|
||||||
|
[[nodiscard]] object_ptr<GenericBox> PrepareScheduleBox(
|
||||||
|
Guard &&guard,
|
||||||
|
Submit &&submit) {
|
||||||
|
return Box(
|
||||||
|
ScheduleBox,
|
||||||
|
crl::guard(std::forward<Guard>(guard), std::forward<Submit>(submit)),
|
||||||
|
DefaultScheduleTime());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace HistoryView
|
} // namespace HistoryView
|
||||||
|
|
|
@ -117,6 +117,8 @@ ScheduledWidget::ScheduledWidget(
|
||||||
ScheduledWidget::~ScheduledWidget() = default;
|
ScheduledWidget::~ScheduledWidget() = default;
|
||||||
|
|
||||||
void ScheduledWidget::setupComposeControls() {
|
void ScheduledWidget::setupComposeControls() {
|
||||||
|
_composeControls->setHistory(_history);
|
||||||
|
|
||||||
_composeControls->height(
|
_composeControls->height(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
updateControlsGeometry();
|
updateControlsGeometry();
|
||||||
|
@ -232,7 +234,8 @@ bool ScheduledWidget::confirmSendingFiles(
|
||||||
std::move(list),
|
std::move(list),
|
||||||
text,
|
text,
|
||||||
boxCompressConfirm,
|
boxCompressConfirm,
|
||||||
_history->peer->slowmodeApplied() ? SendLimit::One : SendLimit::Many);
|
_history->peer->slowmodeApplied() ? SendLimit::One : SendLimit::Many,
|
||||||
|
Api::SendType::Scheduled);
|
||||||
//_field->setTextWithTags({});
|
//_field->setTextWithTags({});
|
||||||
|
|
||||||
box->setConfirmedCallback(crl::guard(this, [=](
|
box->setConfirmedCallback(crl::guard(this, [=](
|
||||||
|
@ -314,39 +317,28 @@ void ScheduledWidget::uploadFilesAfterConfirmation(
|
||||||
ShowErrorToast(tr::lng_slowmode_no_many(tr::now));
|
ShowErrorToast(tr::lng_slowmode_no_many(tr::now));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto callback = crl::guard(this, [
|
auto action = Api::SendAction(_history);
|
||||||
=,
|
action.replyTo = replyTo;
|
||||||
list = std::move(list),
|
action.options = options;
|
||||||
caption = std::move(caption),
|
session().api().sendFiles(
|
||||||
// Strange thing, otherwise std::is_copy_constructible is true. O_o
|
std::move(list),
|
||||||
msvc_bug_workaround = std::make_unique<int>()
|
type,
|
||||||
](Api::SendOptions options) mutable {
|
std::move(caption),
|
||||||
auto action = Api::SendAction(_history);
|
album,
|
||||||
action.replyTo = replyTo;
|
action);
|
||||||
action.options = options;
|
|
||||||
session().api().sendFiles(
|
|
||||||
std::move(list),
|
|
||||||
type,
|
|
||||||
std::move(caption),
|
|
||||||
album,
|
|
||||||
action);
|
|
||||||
});
|
|
||||||
Ui::show(
|
|
||||||
Box(ScheduleBox, std::move(callback), DefaultScheduleTime()),
|
|
||||||
LayerOption::KeepOther);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScheduledWidget::uploadFile(
|
void ScheduledWidget::uploadFile(
|
||||||
const QByteArray &fileContent,
|
const QByteArray &fileContent,
|
||||||
SendMediaType type) {
|
SendMediaType type) {
|
||||||
const auto callback = crl::guard(this, [=](Api::SendOptions options) {
|
const auto callback = [=](Api::SendOptions options) {
|
||||||
auto action = Api::SendAction(_history);
|
auto action = Api::SendAction(_history);
|
||||||
//action.replyTo = replyToId();
|
//action.replyTo = replyToId();
|
||||||
action.options = options;
|
action.options = options;
|
||||||
session().api().sendFile(fileContent, type, action);
|
session().api().sendFile(fileContent, type, action);
|
||||||
});
|
};
|
||||||
Ui::show(
|
Ui::show(
|
||||||
Box(ScheduleBox, callback, DefaultScheduleTime()),
|
PrepareScheduleBox(this, callback),
|
||||||
LayerOption::KeepOther);
|
LayerOption::KeepOther);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,11 +379,9 @@ void ScheduledWidget::send() {
|
||||||
if (_composeControls->getTextWithAppliedMarkdown().text.isEmpty()) {
|
if (_composeControls->getTextWithAppliedMarkdown().text.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto callback = crl::guard(this, [=](Api::SendOptions options) {
|
const auto callback = [=](Api::SendOptions options) { send(options); };
|
||||||
send(options);
|
|
||||||
});
|
|
||||||
Ui::show(
|
Ui::show(
|
||||||
Box(ScheduleBox, callback, DefaultScheduleTime()),
|
PrepareScheduleBox(this, callback),
|
||||||
LayerOption::KeepOther);
|
LayerOption::KeepOther);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,11 +422,11 @@ void ScheduledWidget::send(Api::SendOptions options) {
|
||||||
|
|
||||||
void ScheduledWidget::sendExistingDocument(
|
void ScheduledWidget::sendExistingDocument(
|
||||||
not_null<DocumentData*> document) {
|
not_null<DocumentData*> document) {
|
||||||
const auto callback = crl::guard(this, [=](Api::SendOptions options) {
|
const auto callback = [=](Api::SendOptions options) {
|
||||||
sendExistingDocument(document, options);
|
sendExistingDocument(document, options);
|
||||||
});
|
};
|
||||||
Ui::show(
|
Ui::show(
|
||||||
Box(ScheduleBox, callback, DefaultScheduleTime()),
|
PrepareScheduleBox(this, callback),
|
||||||
LayerOption::KeepOther);
|
LayerOption::KeepOther);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,11 +460,11 @@ bool ScheduledWidget::sendExistingDocument(
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScheduledWidget::sendExistingPhoto(not_null<PhotoData*> photo) {
|
void ScheduledWidget::sendExistingPhoto(not_null<PhotoData*> photo) {
|
||||||
const auto callback = crl::guard(this, [=](Api::SendOptions options) {
|
const auto callback = [=](Api::SendOptions options) {
|
||||||
sendExistingPhoto(photo, options);
|
sendExistingPhoto(photo, options);
|
||||||
});
|
};
|
||||||
Ui::show(
|
Ui::show(
|
||||||
Box(ScheduleBox, callback, DefaultScheduleTime()),
|
PrepareScheduleBox(this, callback),
|
||||||
LayerOption::KeepOther);
|
LayerOption::KeepOther);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -507,11 +497,11 @@ void ScheduledWidget::sendInlineResult(
|
||||||
Ui::show(Box<InformBox>(errorText));
|
Ui::show(Box<InformBox>(errorText));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto callback = crl::guard(this, [=](Api::SendOptions options) {
|
const auto callback = [=](Api::SendOptions options) {
|
||||||
sendInlineResult(result, bot, options);
|
sendInlineResult(result, bot, options);
|
||||||
});
|
};
|
||||||
Ui::show(
|
Ui::show(
|
||||||
Box(ScheduleBox, callback, DefaultScheduleTime()),
|
PrepareScheduleBox(this, callback),
|
||||||
LayerOption::KeepOther);
|
LayerOption::KeepOther);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "observer_peer.h"
|
#include "observer_peer.h"
|
||||||
|
#include "api/api_common.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
|
@ -700,14 +701,17 @@ void PeerMenuShareContactBox(
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeerMenuCreatePoll(not_null<PeerData*> peer) {
|
void PeerMenuCreatePoll(not_null<PeerData*> peer) {
|
||||||
const auto box = Ui::show(Box<CreatePollBox>(&peer->session()));
|
const auto box = Ui::show(Box<CreatePollBox>(
|
||||||
|
&peer->session(),
|
||||||
|
Api::SendType::Normal));
|
||||||
const auto lock = box->lifetime().make_state<bool>(false);
|
const auto lock = box->lifetime().make_state<bool>(false);
|
||||||
box->submitRequests(
|
box->submitRequests(
|
||||||
) | rpl::start_with_next([=](const PollData &result) {
|
) | rpl::start_with_next([=](const CreatePollBox::Result &result) {
|
||||||
if (std::exchange(*lock, true)) {
|
if (std::exchange(*lock, true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto action = Api::SendAction(peer->owner().history(peer));
|
auto action = Api::SendAction(peer->owner().history(peer));
|
||||||
|
action.options = result.options;
|
||||||
if (const auto id = App::main()->currentReplyToIdFor(action.history)) {
|
if (const auto id = App::main()->currentReplyToIdFor(action.history)) {
|
||||||
action.replyTo = id;
|
action.replyTo = id;
|
||||||
}
|
}
|
||||||
|
@ -715,7 +719,7 @@ void PeerMenuCreatePoll(not_null<PeerData*> peer) {
|
||||||
action.clearDraft = localDraft->textWithTags.text.isEmpty();
|
action.clearDraft = localDraft->textWithTags.text.isEmpty();
|
||||||
}
|
}
|
||||||
const auto api = &peer->session().api();
|
const auto api = &peer->session().api();
|
||||||
api->createPoll(result, action, crl::guard(box, [=] {
|
api->createPoll(result.poll, action, crl::guard(box, [=] {
|
||||||
box->closeBox();
|
box->closeBox();
|
||||||
}), crl::guard(box, [=](const RPCError &error) {
|
}), crl::guard(box, [=](const RPCError &error) {
|
||||||
*lock = false;
|
*lock = false;
|
||||||
|
|
Loading…
Reference in New Issue