mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-02-19 06:26:55 +00:00
Send from scheduled messages section.
This commit is contained in:
parent
3e895d0e85
commit
77ebdd3576
BIN
Telegram/Resources/icons/send_control_schedule.png
Normal file
BIN
Telegram/Resources/icons/send_control_schedule.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 743 B |
BIN
Telegram/Resources/icons/send_control_schedule@2x.png
Normal file
BIN
Telegram/Resources/icons/send_control_schedule@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
Telegram/Resources/icons/send_control_schedule@3x.png
Normal file
BIN
Telegram/Resources/icons/send_control_schedule@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
@ -543,10 +543,11 @@ void DeleteMessagesBox::prepare() {
|
||||
: tr::lng_selected_delete_sure(tr::now, lt_count, _ids.size());
|
||||
if (const auto peer = checkFromSinglePeer()) {
|
||||
auto count = int(_ids.size());
|
||||
if (auto revoke = revokeText(peer)) {
|
||||
if (hasScheduledMessages()) {
|
||||
} else if (auto revoke = revokeText(peer)) {
|
||||
_revoke.create(this, revoke->checkbox, false, st::defaultBoxCheckbox);
|
||||
appendDetails(std::move(revoke->description));
|
||||
} else if (peer && peer->isChannel()) {
|
||||
} else if (peer->isChannel()) {
|
||||
if (peer->isMegagroup()) {
|
||||
appendDetails({ tr::lng_delete_for_everyone_hint(tr::now, lt_count, count) });
|
||||
}
|
||||
@ -581,6 +582,17 @@ void DeleteMessagesBox::prepare() {
|
||||
setDimensions(st::boxWidth, fullHeight);
|
||||
}
|
||||
|
||||
bool DeleteMessagesBox::hasScheduledMessages() const {
|
||||
for (const auto fullId : std::as_const(_ids)) {
|
||||
if (const auto item = _session->data().message(fullId)) {
|
||||
if (item->isScheduled()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PeerData *DeleteMessagesBox::checkFromSinglePeer() const {
|
||||
auto result = (PeerData*)nullptr;
|
||||
for (const auto fullId : std::as_const(_ids)) {
|
||||
|
@ -176,8 +176,10 @@ private:
|
||||
TextWithEntities description;
|
||||
};
|
||||
void deleteAndClear();
|
||||
PeerData *checkFromSinglePeer() const;
|
||||
std::optional<RevokeConfig> revokeText(not_null<PeerData*> peer) const;
|
||||
[[nodiscard]] PeerData *checkFromSinglePeer() const;
|
||||
[[nodiscard]] bool hasScheduledMessages() const;
|
||||
[[nodiscard]] std::optional<RevokeConfig> revokeText(
|
||||
not_null<PeerData*> peer) const;
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
|
@ -220,6 +220,8 @@ historySendIcon: icon {{ "send_control_send", historySendIconFg }};
|
||||
historySendIconOver: icon {{ "send_control_send", historySendIconFgOver }};
|
||||
historySendIconPosition: point(11px, 11px);
|
||||
historySendSize: size(46px, 46px);
|
||||
historyScheduleIcon: icon {{ "send_control_schedule", historyComposeAreaBg }};
|
||||
historyScheduleIconPosition: point(8px, 8px);
|
||||
historyEditSaveIcon: icon {{ "send_control_save", historySendIconFg, point(3px, 7px) }};
|
||||
historyEditSaveIconOver: icon {{ "send_control_save", historySendIconFgOver, point(3px, 7px) }};
|
||||
|
||||
|
@ -79,6 +79,10 @@ rpl::producer<> ComposeControls::cancelRequests() const {
|
||||
return _cancelRequests.events();
|
||||
}
|
||||
|
||||
rpl::producer<> ComposeControls::sendRequests() const {
|
||||
return _send->clicks() | rpl::map([] { return rpl::empty_value(); });
|
||||
}
|
||||
|
||||
void ComposeControls::showStarted() {
|
||||
if (_inlineResults) {
|
||||
_inlineResults->hideFast();
|
||||
@ -103,9 +107,41 @@ void ComposeControls::showForGrab() {
|
||||
showFinished();
|
||||
}
|
||||
|
||||
TextWithTags ComposeControls::getTextWithAppliedMarkdown() const {
|
||||
return _field->getTextWithAppliedMarkdown();
|
||||
}
|
||||
|
||||
void ComposeControls::clear() {
|
||||
setText(TextWithTags());
|
||||
}
|
||||
|
||||
void ComposeControls::setText(const TextWithTags &textWithTags) {
|
||||
//_textUpdateEvents = events;
|
||||
_field->setTextWithTags(textWithTags, Ui::InputField::HistoryAction::Clear/*fieldHistoryAction*/);
|
||||
auto cursor = _field->textCursor();
|
||||
cursor.movePosition(QTextCursor::End);
|
||||
_field->setTextCursor(cursor);
|
||||
//_textUpdateEvents = TextUpdateEvent::SaveDraft
|
||||
// | TextUpdateEvent::SendTyping;
|
||||
|
||||
//previewCancel();
|
||||
//_previewCancelled = false;
|
||||
}
|
||||
|
||||
void ComposeControls::hidePanelsAnimated() {
|
||||
//_fieldAutocomplete->hideAnimated();
|
||||
if (_tabbedPanel) {
|
||||
_tabbedPanel->hideAnimated();
|
||||
}
|
||||
if (_inlineResults) {
|
||||
_inlineResults->hideAnimated();
|
||||
}
|
||||
}
|
||||
|
||||
void ComposeControls::init() {
|
||||
initField();
|
||||
initTabbedSelector();
|
||||
initSendButton();
|
||||
|
||||
_wrap->sizeValue(
|
||||
) | rpl::start_with_next([=](QSize size) {
|
||||
@ -182,6 +218,44 @@ void ComposeControls::initTabbedSelector() {
|
||||
}, wrap->lifetime());
|
||||
}
|
||||
|
||||
void ComposeControls::initSendButton() {
|
||||
updateSendButtonType();
|
||||
_send->finishAnimating();
|
||||
}
|
||||
|
||||
void ComposeControls::updateSendButtonType() {
|
||||
using Type = Ui::SendButton::Type;
|
||||
const auto type = [&] {
|
||||
//if (_editMsgId) {
|
||||
// return Type::Save;
|
||||
//} else if (_isInlineBot) {
|
||||
// return Type::Cancel;
|
||||
//} else if (showRecordButton()) {
|
||||
// return Type::Record;
|
||||
//}
|
||||
return Type::Schedule;
|
||||
}();
|
||||
_send->setType(type);
|
||||
|
||||
const auto delay = [&] {
|
||||
return /*(type != Type::Cancel && type != Type::Save && _peer)
|
||||
? _peer->slowmodeSecondsLeft()
|
||||
: */0;
|
||||
}();
|
||||
_send->setSlowmodeDelay(delay);
|
||||
//_send->setDisabled(_peer
|
||||
// && _peer->slowmodeApplied()
|
||||
// && (_history->latestSendingMessage() != nullptr)
|
||||
// && (type == Type::Send || type == Type::Record));
|
||||
|
||||
//if (delay != 0) {
|
||||
// App::CallDelayed(
|
||||
// kRefreshSlowmodeLabelTimeout,
|
||||
// this,
|
||||
// [=] { updateSendButtonType(); });
|
||||
//}
|
||||
}
|
||||
|
||||
void ComposeControls::updateControlsGeometry(QSize size) {
|
||||
// _attachToggle -- _inlineResults ------ _tabbedPanel -- _fieldBarCancel
|
||||
// (_attachDocument|_attachPhoto) _field _tabbedSelectorToggle _send
|
||||
|
@ -64,6 +64,7 @@ public:
|
||||
|
||||
void focus();
|
||||
[[nodiscard]] rpl::producer<> cancelRequests() const;
|
||||
[[nodiscard]] rpl::producer<> sendRequests() const;
|
||||
|
||||
void pushTabbedSelectorToThirdSection(const Window::SectionShow ¶ms);
|
||||
bool returnTabbedSelector();
|
||||
@ -72,10 +73,16 @@ public:
|
||||
void showStarted();
|
||||
void showFinished();
|
||||
|
||||
[[nodiscard]] TextWithTags getTextWithAppliedMarkdown() const;
|
||||
void clear();
|
||||
void hidePanelsAnimated();
|
||||
|
||||
private:
|
||||
void init();
|
||||
void initField();
|
||||
void initTabbedSelector();
|
||||
void initSendButton();
|
||||
void updateSendButtonType();
|
||||
void updateHeight();
|
||||
void updateControlsGeometry(QSize size);
|
||||
void updateOuterGeometry(QRect rect);
|
||||
@ -85,6 +92,7 @@ private:
|
||||
void toggleTabbedSelectorMode();
|
||||
void createTabbedPanel();
|
||||
void setTabbedPanel(std::unique_ptr<ChatHelpers::TabbedPanel> panel);
|
||||
void setText(const TextWithTags &text);
|
||||
|
||||
const not_null<QWidget*> _parent;
|
||||
const not_null<Window::SessionController*> _window;
|
||||
|
@ -507,9 +507,7 @@ void TimeInput::startBorderAnimation() {
|
||||
} // namespace
|
||||
|
||||
TimeId DefaultScheduleTime() {
|
||||
const auto result = base::unixtime::now() + 3600;
|
||||
const auto time = base::unixtime::parse(result).time();
|
||||
return result - (time.minute() % 5) * 60 - time.second();
|
||||
return base::unixtime::now() + 600;
|
||||
}
|
||||
|
||||
void ScheduleBox(
|
||||
@ -597,7 +595,8 @@ void ScheduleBox(
|
||||
timeInput->showError();
|
||||
return;
|
||||
}
|
||||
result.scheduled = QDateTime(date->current(), time).toTime_t();
|
||||
result.scheduled = base::unixtime::serialize(
|
||||
QDateTime(date->current(), time));
|
||||
if (result.scheduled <= base::unixtime::now() + kMinimalSchedule) {
|
||||
timeInput->showError();
|
||||
return;
|
||||
|
@ -10,11 +10,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/view/history_view_compose_controls.h"
|
||||
#include "history/view/history_view_top_bar_widget.h"
|
||||
#include "history/view/history_view_list_widget.h"
|
||||
#include "history/view/history_view_schedule_box.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/special_buttons.h"
|
||||
#include "api/api_common.h"
|
||||
#include "apiwrap.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "window/window_peer_menu.h"
|
||||
@ -103,6 +106,58 @@ void ScheduledWidget::setupComposeControls() {
|
||||
) | rpl::start_with_next([=] {
|
||||
controller()->showBackFromStack();
|
||||
}, lifetime());
|
||||
|
||||
_composeControls->sendRequests(
|
||||
) | rpl::start_with_next([=] {
|
||||
send();
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void ScheduledWidget::send() {
|
||||
if (_composeControls->getTextWithAppliedMarkdown().text.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
const auto callback = crl::guard(this, [=](Api::SendOptions options) {
|
||||
send(options);
|
||||
});
|
||||
Ui::show(
|
||||
Box(ScheduleBox, callback, DefaultScheduleTime()),
|
||||
LayerOption::KeepOther);
|
||||
}
|
||||
|
||||
void ScheduledWidget::send(Api::SendOptions options) {
|
||||
const auto webPageId = 0;/* _previewCancelled
|
||||
? CancelledWebPageId
|
||||
: ((_previewData && _previewData->pendingTill >= 0)
|
||||
? _previewData->id
|
||||
: WebPageId(0));*/
|
||||
|
||||
auto message = ApiWrap::MessageToSend(_history);
|
||||
message.textWithTags = _composeControls->getTextWithAppliedMarkdown();
|
||||
message.action.options = options;
|
||||
//message.action.replyTo = replyToId();
|
||||
message.webPageId = webPageId;
|
||||
|
||||
//const auto error = GetErrorTextForForward(
|
||||
// _peer,
|
||||
// _toForward,
|
||||
// message.textWithTags);
|
||||
//if (!error.isEmpty()) {
|
||||
// ShowErrorToast(error);
|
||||
// return;
|
||||
//}
|
||||
|
||||
session().api().sendMessage(std::move(message));
|
||||
|
||||
_composeControls->clear();
|
||||
//_saveDraftText = true;
|
||||
//_saveDraftStart = crl::now();
|
||||
//onDraftSave();
|
||||
|
||||
_composeControls->hidePanelsAnimated();
|
||||
|
||||
//if (_previewData && _previewData->pendingTill) previewCancel();
|
||||
_composeControls->focus();
|
||||
}
|
||||
|
||||
void ScheduledWidget::setupScrollDownButton() {
|
||||
@ -402,9 +457,42 @@ rpl::producer<Data::MessagesSlice> ScheduledWidget::listSource(
|
||||
data->scheduledMessages().updates(_history)
|
||||
) | rpl::map([=] {
|
||||
return data->scheduledMessages().list(_history);
|
||||
}) | rpl::after_next([=](const Data::MessagesSlice &slice) {
|
||||
highlightSingleNewMessage(slice);
|
||||
});
|
||||
}
|
||||
|
||||
void ScheduledWidget::highlightSingleNewMessage(
|
||||
const Data::MessagesSlice &slice) {
|
||||
const auto guard = gsl::finally([&] { _lastSlice = slice; });
|
||||
if (_lastSlice.ids.empty()
|
||||
|| (slice.ids.size() != _lastSlice.ids.size() + 1)) {
|
||||
return;
|
||||
}
|
||||
auto firstDifferent = 0;
|
||||
for (; firstDifferent != _lastSlice.ids.size(); ++firstDifferent) {
|
||||
if (slice.ids[firstDifferent] != _lastSlice.ids[firstDifferent]) {
|
||||
break;
|
||||
}
|
||||
++firstDifferent;
|
||||
}
|
||||
auto lastDifferent = slice.ids.size() - 1;
|
||||
for (; lastDifferent != firstDifferent;) {
|
||||
if (slice.ids[lastDifferent] != _lastSlice.ids[lastDifferent - 1]) {
|
||||
break;
|
||||
}
|
||||
--lastDifferent;
|
||||
}
|
||||
if (firstDifferent != lastDifferent) {
|
||||
return;
|
||||
}
|
||||
const auto newId = slice.ids[firstDifferent];
|
||||
if (const auto item = session().data().message(newId)) {
|
||||
// _highlightMessageId = newId;
|
||||
showAtPosition(item->position());
|
||||
}
|
||||
}
|
||||
|
||||
bool ScheduledWidget::listAllowsMultiSelect() {
|
||||
return true;
|
||||
}
|
||||
|
@ -10,9 +10,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "window/section_widget.h"
|
||||
#include "window/section_memento.h"
|
||||
#include "history/view/history_view_list_widget.h"
|
||||
#include "data/data_messages.h"
|
||||
|
||||
class History;
|
||||
|
||||
namespace Api {
|
||||
struct SendOptions;
|
||||
} // namespace Api
|
||||
|
||||
namespace Notify {
|
||||
struct PeerUpdate;
|
||||
} // namespace Notify
|
||||
@ -125,6 +130,10 @@ private:
|
||||
void confirmDeleteSelected();
|
||||
void clearSelected();
|
||||
|
||||
void send();
|
||||
void send(Api::SendOptions options);
|
||||
void highlightSingleNewMessage(const Data::MessagesSlice &slice);
|
||||
|
||||
const not_null<History*> _history;
|
||||
object_ptr<Ui::ScrollArea> _scroll;
|
||||
QPointer<ListWidget> _inner;
|
||||
@ -141,6 +150,8 @@ private:
|
||||
bool _scrollDownIsShown = false;
|
||||
object_ptr<Ui::HistoryDownButton> _scrollDown;
|
||||
|
||||
Data::MessagesSlice _lastSlice;
|
||||
|
||||
};
|
||||
|
||||
class ScheduledMemento : public Window::SectionMemento {
|
||||
|
@ -369,6 +369,7 @@ void SendButton::paintEvent(QPaintEvent *e) {
|
||||
case Type::Save: paintSave(p, over); break;
|
||||
case Type::Cancel: paintCancel(p, over); break;
|
||||
case Type::Send: paintSend(p, over); break;
|
||||
case Type::Schedule: paintSchedule(p, over); break;
|
||||
case Type::Slowmode: paintSlowmode(p); break;
|
||||
}
|
||||
}
|
||||
@ -426,6 +427,23 @@ void SendButton::paintSend(Painter &p, bool over) {
|
||||
}
|
||||
}
|
||||
|
||||
void SendButton::paintSchedule(Painter &p, bool over) {
|
||||
{
|
||||
PainterHighQualityEnabler hq(p);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(over ? st::historySendIconFgOver : st::historySendIconFg);
|
||||
p.drawEllipse(
|
||||
st::historyScheduleIconPosition.x(),
|
||||
st::historyScheduleIconPosition.y(),
|
||||
st::historyScheduleIcon.width(),
|
||||
st::historyScheduleIcon.height());
|
||||
}
|
||||
st::historyScheduleIcon.paint(
|
||||
p,
|
||||
st::historyScheduleIconPosition,
|
||||
width());
|
||||
}
|
||||
|
||||
void SendButton::paintSlowmode(Painter &p) {
|
||||
p.setFont(st::normalFont);
|
||||
p.setPen(st::windowSubTextFg);
|
||||
|
@ -82,6 +82,7 @@ public:
|
||||
|
||||
enum class Type {
|
||||
Send,
|
||||
Schedule,
|
||||
Save,
|
||||
Record,
|
||||
Cancel,
|
||||
@ -129,6 +130,7 @@ private:
|
||||
void paintSave(Painter &p, bool over);
|
||||
void paintCancel(Painter &p, bool over);
|
||||
void paintSend(Painter &p, bool over);
|
||||
void paintSchedule(Painter &p, bool over);
|
||||
void paintSlowmode(Painter &p);
|
||||
|
||||
Type _type = Type::Send;
|
||||
|
Loading…
Reference in New Issue
Block a user