Skip to content

Commit

Permalink
Multi-select in mini app send prepared.
Browse files Browse the repository at this point in the history
  • Loading branch information
john-preston committed Nov 17, 2024
1 parent 60f4587 commit 7552328
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 49 deletions.
79 changes: 49 additions & 30 deletions Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1826,11 +1826,56 @@ void WebViewInstance::botSendPreparedMessage(
});
struct State {
QPointer<Ui::BoxContent> preview;
QPointer<Ui::BoxContent> choose;
rpl::event_stream<not_null<Data::Thread*>> recipient;
bool sent = false;
};
const auto state = std::make_shared<State>();
auto recipient = state->recipient.events();
const auto send = [=](std::vector<not_null<Data::Thread*>> list) {
if (state->sent) {
return;
}
state->sent = true;
const auto failed = std::make_shared<int>();
const auto count = int(list.size());
const auto weak1 = state->preview;
const auto weak2 = state->choose;
const auto close = [=] {
if (const auto strong = weak1.data()) {
strong->closeBox();
}
if (const auto strong = weak2.data()) {
strong->closeBox();
}
};
const auto done = [=](bool success) {
if (*failed < 0) {
return;
}
if (success) {
*failed = -1;
if (const auto strong2 = weak2.data()) {
strong2->showToast({ tr::lng_share_done(tr::now) });
} else if (const auto strong1 = weak1.data()) {
strong1->showToast({ tr::lng_share_done(tr::now) });
}
base::call_delayed(Ui::Toast::kDefaultDuration, close);
callback(QString());
} else if (++*failed == count) {
close();
callback(u"MESSAGE_SEND_FAILED"_q);
}
};
for (const auto &thread : list) {
bot->session().api().sendInlineResult(
bot,
parsed.get(),
Api::SendAction(thread),
std::nullopt,
done);
}
};
auto box = Box(PreparedPreviewBox, item, std::move(recipient), [=] {
if (state->sent) {
return;
Expand All @@ -1850,38 +1895,12 @@ void WebViewInstance::botSendPreparedMessage(
chosen,
tr::lng_inline_switch_choose(),
nullptr,
types);
types,
send);
state->choose = box.data();
panel->showBox(std::move(box));
}, [=](not_null<Data::Thread*> thread) {
if (state->sent) {
return;
}
state->sent = true;
const auto weak = state->preview;
const auto done = [=](bool success) {
if (success) {
if (const auto strong = weak.data()) {
strong->showToast({ tr::lng_share_done(tr::now) });
}
base::call_delayed(Ui::Toast::kDefaultDuration, [weak] {
if (const auto strong = weak.data()) {
strong->closeBox();
}
});
callback(QString());
} else {
if (const auto strong = weak.data()) {
strong->closeBox();
}
callback(u"MESSAGE_SEND_FAILED"_q);
}
};
bot->session().api().sendInlineResult(
bot,
parsed.get(),
Api::SendAction(thread),
std::nullopt,
done);
send({ thread });
});
box->boxClosing() | rpl::start_with_next([=] {
if (!state->sent) {
Expand Down
125 changes: 107 additions & 18 deletions Telegram/SourceFiles/window/window_peer_menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1886,8 +1886,83 @@ object_ptr<Ui::BoxContent> PrepareChooseRecipientBox(
FnMut<bool(not_null<Data::Thread*>)> &&chosen,
rpl::producer<QString> titleOverride,
FnMut<void()> &&successCallback,
InlineBots::PeerTypes typesRestriction) {
const auto weak = std::make_shared<QPointer<Ui::BoxContent>>();
InlineBots::PeerTypes typesRestriction,
Fn<void(std::vector<not_null<Data::Thread*>>)> sendMany) {
const auto weak = std::make_shared<QPointer<PeerListBox>>();
const auto selectable = (sendMany != nullptr);
class Controller final : public ChooseRecipientBoxController {
public:
using Chosen = not_null<Data::Thread*>;

Controller(
not_null<Main::Session*> session,
FnMut<void(Chosen)> callback,
Fn<bool(Chosen)> filter,
bool selectable)
: ChooseRecipientBoxController({
.session = session,
.callback = std::move(callback),
.filter = filter,
.premiumRequiredError = WritePremiumRequiredError,
})
, _selectable(selectable) {
}

using PeerListController::setSearchNoResultsText;

void rowClicked(not_null<PeerListRow*> row) override final {
if (!_selectable) {
return ChooseRecipientBoxController::rowClicked(row);
}
const auto count = delegate()->peerListSelectedRowsCount();
if (showLockedError(row) || (count && row->peer()->isForum())) {
return;
} else if (row->peer()->isForum()) {
ChooseRecipientBoxController::rowClicked(row);
} else {
delegate()->peerListSetRowChecked(row, !row->checked());
_hasSelectedChanges.fire(
delegate()->peerListSelectedRowsCount() > 0);
}
}

base::unique_qptr<Ui::PopupMenu> rowContextMenu(
QWidget *parent,
not_null<PeerListRow*> row) override final {
if (!_selectable) {
return ChooseRecipientBoxController::rowContextMenu(
parent,
row);
}
if (!row->checked() && !row->peer()->isForum()) {
auto menu = base::make_unique_q<Ui::PopupMenu>(
parent,
st::popupMenuWithIcons);
menu->addAction(tr::lng_bot_choose_chat(tr::now), [=] {
delegate()->peerListSetRowChecked(row, true);
_hasSelectedChanges.fire(
delegate()->peerListSelectedRowsCount() > 0);
}, &st::menuIconSelect);
return menu;
}
return nullptr;
}

[[nodiscard]] rpl::producer<bool> hasSelectedChanges() const {
return _hasSelectedChanges.events_starting_with(false);
}

[[nodiscard]] rpl::producer<Chosen> singleChosen() const {
return _singleChosen.events();
}

private:
rpl::event_stream<Chosen> _singleChosen;
rpl::event_stream<bool> _hasSelectedChanges;
bool _selectable = false;

};

auto callback = [
chosen = std::move(chosen),
success = std::move(successCallback),
Expand Down Expand Up @@ -1919,23 +1994,40 @@ object_ptr<Ui::BoxContent> PrepareChooseRecipientBox(
}
}
: Fn<bool(not_null<Data::Thread*>)>();
auto controller = std::make_unique<Controller>(
session,
std::move(callback),
std::move(filter),
selectable);
const auto raw = controller.get();
auto initBox = [=](not_null<PeerListBox*> box) {
box->addButton(tr::lng_cancel(), [box] {
box->closeBox();
});
raw->hasSelectedChanges(
) | rpl::start_with_next([=](bool shown) {
box->clearButtons();
if (shown) {
box->addButton(tr::lng_send_button(), [=] {
const auto peers = box->collectSelectedRows();
sendMany(ranges::views::all(
peers
) | ranges::views::transform([&](
not_null<PeerData*> peer) -> Controller::Chosen {
return peer->owner().history(peer);
}) | ranges::to_vector);
});
}
box->addButton(tr::lng_cancel(), [=] {
box->closeBox();
});
}, box->lifetime());
if (titleOverride) {
box->setTitle(std::move(titleOverride));
}
};
auto result = Box<PeerListBox>(
std::make_unique<ChooseRecipientBoxController>(ChooseRecipientArgs{
.session = session,
.callback = std::move(callback),
.filter = std::move(filter),
.premiumRequiredError = WritePremiumRequiredError,
}),
std::move(controller),
std::move(initBox));
*weak = result.data();

return result;
}

Expand Down Expand Up @@ -2014,9 +2106,7 @@ QPointer<Ui::BoxContent> ShowForwardMessagesBox(
}) {
}

void setSearchNoResultsText(const QString &text) {
PeerListController::setSearchNoResultsText(text);
}
using PeerListController::setSearchNoResultsText;

void rowClicked(not_null<PeerListRow*> row) override final {
const auto count = delegate()->peerListSelectedRowsCount();
Expand All @@ -2034,13 +2124,12 @@ QPointer<Ui::BoxContent> ShowForwardMessagesBox(
base::unique_qptr<Ui::PopupMenu> rowContextMenu(
QWidget *parent,
not_null<PeerListRow*> row) override final {
const auto count = delegate()->peerListSelectedRowsCount();
if (!count && !row->peer()->isForum()) {
if (!row->checked() && !row->peer()->isForum()) {
auto menu = base::make_unique_q<Ui::PopupMenu>(
parent,
st::popupMenuWithIcons);
menu->addAction(tr::lng_bot_choose_chat(tr::now), [=] {
delegate()->peerListSetRowChecked(row, !row->checked());
delegate()->peerListSetRowChecked(row, true);
_hasSelectedChanges.fire(
delegate()->peerListSelectedRowsCount() > 0);
}, &st::menuIconSelect);
Expand All @@ -2049,7 +2138,7 @@ QPointer<Ui::BoxContent> ShowForwardMessagesBox(
return nullptr;
}

[[nodiscard]] rpl::producer<bool> hasSelectedChanges() const{
[[nodiscard]] rpl::producer<bool> hasSelectedChanges() const {
return _hasSelectedChanges.events_starting_with(false);
}

Expand Down
3 changes: 2 additions & 1 deletion Telegram/SourceFiles/window/window_peer_menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ object_ptr<Ui::BoxContent> PrepareChooseRecipientBox(
FnMut<bool(not_null<Data::Thread*>)> &&chosen,
rpl::producer<QString> titleOverride = nullptr,
FnMut<void()> &&successCallback = nullptr,
InlineBots::PeerTypes typesRestriction = 0);
InlineBots::PeerTypes typesRestriction = 0,
Fn<void(std::vector<not_null<Data::Thread*>>)> sendMany = nullptr);
QPointer<Ui::BoxContent> ShowChooseRecipientBox(
not_null<Window::SessionNavigation*> navigation,
FnMut<bool(not_null<Data::Thread*>)> &&chosen,
Expand Down

0 comments on commit 7552328

Please sign in to comment.