mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-02-23 16:56:55 +00:00
Choose a channel to send messages as.
This commit is contained in:
parent
4691cff3f6
commit
1bd74fe478
@ -17,6 +17,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_location.h"
|
||||
#include "data/data_histories.h"
|
||||
#include "data/data_group_call.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/session/send_as_peers.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "history/history.h"
|
||||
#include "main/main_session.h"
|
||||
@ -915,6 +917,12 @@ void ApplyChannelUpdate(
|
||||
MTP_inputNotifyPeer(channel->input),
|
||||
update.vnotify_settings());
|
||||
|
||||
if (const auto sendAs = update.vdefault_send_as()) {
|
||||
session->sendAsPeers().setChosen(channel, peerFromMTP(*sendAs));
|
||||
} else {
|
||||
session->sendAsPeers().setChosen(channel, PeerId());
|
||||
}
|
||||
|
||||
// For clearUpTill() call.
|
||||
channel->owner().sendHistoryChangeNotifications();
|
||||
}
|
||||
|
@ -470,7 +470,7 @@ rpl::producer<QImage> PeerUserpicImageValue(
|
||||
const auto state = result.make_state<State>();
|
||||
state->push = [=] {
|
||||
const auto key = peer->userpicUniqueKey(state->view);
|
||||
const auto loading = !state->view || state->view->image();
|
||||
const auto loading = state->view && !state->view->image();
|
||||
|
||||
if (loading && !state->waiting) {
|
||||
peer->session().downloaderTaskFinished(
|
||||
|
@ -37,6 +37,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/chat/forward_options_box.h"
|
||||
#include "ui/chat/message_bar.h"
|
||||
#include "ui/chat/attach/attach_send_files_way.h"
|
||||
#include "ui/chat/choose_send_as.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/special_buttons.h"
|
||||
#include "ui/controls/emoji_button.h"
|
||||
@ -53,7 +54,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_web_page.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "data/data_media_types.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
@ -2397,23 +2397,7 @@ void HistoryWidget::refreshSendAsToggle() {
|
||||
return;
|
||||
}
|
||||
_sendAs.create(this, st::sendAsButton);
|
||||
|
||||
using namespace rpl::mappers;
|
||||
controller()->activeChatValue(
|
||||
) | rpl::map([=](const Dialogs::Key &key) -> PeerData* {
|
||||
if (const auto history = key.history()) {
|
||||
return history->peer;
|
||||
}
|
||||
return nullptr;
|
||||
}) | rpl::filter_nullptr(
|
||||
) | rpl::map([=](not_null<PeerData*> peer) {
|
||||
return Data::PeerUserpicImageValue(
|
||||
peer,
|
||||
st::sendAsButton.size * style::DevicePixelRatio());
|
||||
}) | rpl::flatten_latest(
|
||||
) | rpl::start_with_next([=](QImage &&userpic) {
|
||||
_sendAs->setUserpic(std::move(userpic));
|
||||
}, _sendAs->lifetime());
|
||||
Ui::SetupSendAsButton(_sendAs.data(), controller());
|
||||
}
|
||||
|
||||
bool HistoryWidget::contentOverlapped(const QRect &globalRect) {
|
||||
|
@ -38,7 +38,8 @@ void SendAsPeers::refresh(not_null<PeerData*> peer) {
|
||||
request(peer);
|
||||
}
|
||||
|
||||
const std::vector<not_null<PeerData*>> &SendAsPeers::list(not_null<PeerData*> peer) {
|
||||
const std::vector<not_null<PeerData*>> &SendAsPeers::list(
|
||||
not_null<PeerData*> peer) const {
|
||||
const auto i = _lists.find(peer);
|
||||
return (i != end(_lists)) ? i->second : _onlyMe;
|
||||
}
|
||||
@ -47,12 +48,60 @@ rpl::producer<not_null<PeerData*>> SendAsPeers::updated() const {
|
||||
return _updates.events();
|
||||
}
|
||||
|
||||
void SendAsPeers::saveChosen(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<PeerData*> chosen) {
|
||||
peer->session().api().request(MTPmessages_SaveDefaultSendAs(
|
||||
peer->input,
|
||||
chosen->input
|
||||
)).send();
|
||||
|
||||
setChosen(peer, chosen->id);
|
||||
}
|
||||
|
||||
void SendAsPeers::setChosen(not_null<PeerData*> peer, PeerId chosenId) {
|
||||
if (chosen(peer) == chosenId) {
|
||||
return;
|
||||
}
|
||||
const auto fallback = peer->amAnonymous()
|
||||
? peer
|
||||
: peer->session().user();
|
||||
if (fallback->id == chosenId) {
|
||||
_chosen.remove(peer);
|
||||
} else {
|
||||
_chosen[peer] = chosenId;
|
||||
}
|
||||
_updates.fire_copy(peer);
|
||||
}
|
||||
|
||||
PeerId SendAsPeers::chosen(not_null<PeerData*> peer) const {
|
||||
const auto i = _chosen.find(peer);
|
||||
return (i != end(_chosen)) ? i->second : PeerId();
|
||||
}
|
||||
|
||||
not_null<PeerData*> SendAsPeers::resolveChosen(
|
||||
not_null<PeerData*> peer) const {
|
||||
return ResolveChosen(peer, list(peer), chosen(peer));
|
||||
}
|
||||
|
||||
not_null<PeerData*> SendAsPeers::ResolveChosen(
|
||||
not_null<PeerData*> peer,
|
||||
const std::vector<not_null<PeerData*>> &list,
|
||||
PeerId chosen) {
|
||||
const auto i = ranges::find(list, chosen, &PeerData::id);
|
||||
return (i != end(list))
|
||||
? (*i)
|
||||
: (peer->isMegagroup() && peer->amAnonymous())
|
||||
? peer
|
||||
: peer->session().user();
|
||||
}
|
||||
|
||||
void SendAsPeers::request(not_null<PeerData*> peer) {
|
||||
_session->api().request(MTPchannels_GetSendAs(
|
||||
peer->session().api().request(MTPchannels_GetSendAs(
|
||||
peer->input
|
||||
)).done([=](const MTPchannels_SendAsPeers &result) {
|
||||
auto list = std::vector<not_null<PeerData*>>();
|
||||
auto &owner = _session->data();
|
||||
auto &owner = peer->owner();
|
||||
result.match([&](const MTPDchannels_sendAsPeers &data) {
|
||||
owner.processUsers(data.vusers());
|
||||
owner.processChats(data.vchats());
|
||||
|
@ -19,9 +19,20 @@ public:
|
||||
|
||||
void refresh(not_null<PeerData*> peer);
|
||||
[[nodiscard]] const std::vector<not_null<PeerData*>> &list(
|
||||
not_null<PeerData*> peer);
|
||||
not_null<PeerData*> peer) const;
|
||||
[[nodiscard]] rpl::producer<not_null<PeerData*>> updated() const;
|
||||
|
||||
void saveChosen(not_null<PeerData*> peer, not_null<PeerData*> chosen);
|
||||
void setChosen(not_null<PeerData*> peer, PeerId chosenId);
|
||||
[[nodiscard]] PeerId chosen(not_null<PeerData*> peer) const;
|
||||
[[nodiscard]] not_null<PeerData*> resolveChosen(
|
||||
not_null<PeerData*> peer) const;
|
||||
|
||||
[[nodiscard]] static not_null<PeerData*> ResolveChosen(
|
||||
not_null<PeerData*> peer,
|
||||
const std::vector<not_null<PeerData*>> &list,
|
||||
PeerId chosen);
|
||||
|
||||
private:
|
||||
void request(not_null<PeerData*> peer);
|
||||
|
||||
@ -32,6 +43,7 @@ private:
|
||||
not_null<PeerData*>,
|
||||
std::vector<not_null<PeerData*>>> _lists;
|
||||
base::flat_map<not_null<PeerData*>, crl::time> _lastRequestTime;
|
||||
base::flat_map<not_null<PeerData*>, PeerId> _chosen;
|
||||
|
||||
rpl::event_stream<not_null<PeerData*>> _updates;
|
||||
|
||||
|
210
Telegram/SourceFiles/ui/chat/choose_send_as.cpp
Normal file
210
Telegram/SourceFiles/ui/chat/choose_send_as.cpp
Normal file
@ -0,0 +1,210 @@
|
||||
/*
|
||||
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 "ui/chat/choose_send_as.h"
|
||||
|
||||
#include "boxes/peer_list_box.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "history/history.h"
|
||||
#include "ui/controls/send_as_button.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/session/send_as_peers.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "styles/style_calls.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_chat.h"
|
||||
|
||||
namespace Ui {
|
||||
namespace {
|
||||
|
||||
class ListController final : public PeerListController {
|
||||
public:
|
||||
ListController(
|
||||
std::vector<not_null<PeerData*>> list,
|
||||
not_null<PeerData*> selected);
|
||||
|
||||
Main::Session &session() const override;
|
||||
void prepare() override;
|
||||
void rowClicked(not_null<PeerListRow*> row) override;
|
||||
|
||||
[[nodiscard]] not_null<PeerData*> selected() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<PeerListRow> createRow(not_null<PeerData*> peer);
|
||||
|
||||
std::vector<not_null<PeerData*>> _list;
|
||||
not_null<PeerData*> _selected;
|
||||
|
||||
};
|
||||
|
||||
ListController::ListController(
|
||||
std::vector<not_null<PeerData*>> list,
|
||||
not_null<PeerData*> selected)
|
||||
: PeerListController()
|
||||
, _list(std::move(list))
|
||||
, _selected(selected) {
|
||||
}
|
||||
|
||||
Main::Session &ListController::session() const {
|
||||
return _selected->session();
|
||||
}
|
||||
|
||||
std::unique_ptr<PeerListRow> ListController::createRow(
|
||||
not_null<PeerData*> peer) {
|
||||
auto result = std::make_unique<PeerListRow>(peer);
|
||||
if (peer->isSelf()) {
|
||||
result->setCustomStatus(
|
||||
tr::lng_group_call_join_as_personal(tr::now));
|
||||
} else if (peer->isMegagroup()) {
|
||||
result->setCustomStatus(u"Anonymous admin"_q);
|
||||
} else if (const auto channel = peer->asChannel()) {
|
||||
result->setCustomStatus(tr::lng_chat_status_subscribers(
|
||||
tr::now,
|
||||
lt_count,
|
||||
channel->membersCount()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ListController::prepare() {
|
||||
delegate()->peerListSetSearchMode(PeerListSearchMode::Disabled);
|
||||
for (const auto &peer : _list) {
|
||||
auto row = createRow(peer);
|
||||
const auto raw = row.get();
|
||||
delegate()->peerListAppendRow(std::move(row));
|
||||
if (peer == _selected) {
|
||||
delegate()->peerListSetRowChecked(raw, true);
|
||||
raw->finishCheckedAnimation();
|
||||
}
|
||||
}
|
||||
delegate()->peerListRefreshRows();
|
||||
}
|
||||
|
||||
void ListController::rowClicked(not_null<PeerListRow*> row) {
|
||||
const auto peer = row->peer();
|
||||
if (peer == _selected) {
|
||||
return;
|
||||
}
|
||||
const auto previous = delegate()->peerListFindRow(_selected->id.value);
|
||||
Assert(previous != nullptr);
|
||||
delegate()->peerListSetRowChecked(previous, false);
|
||||
delegate()->peerListSetRowChecked(row, true);
|
||||
_selected = peer;
|
||||
}
|
||||
|
||||
not_null<PeerData*> ListController::selected() const {
|
||||
return _selected;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ChooseSendAsBox(
|
||||
not_null<GenericBox*> box,
|
||||
std::vector<not_null<PeerData*>> list,
|
||||
not_null<PeerData*> chosen,
|
||||
Fn<void(not_null<PeerData*>)> done) {
|
||||
Expects(ranges::contains(list, chosen));
|
||||
Expects(done != nullptr);
|
||||
|
||||
box->setWidth(st::groupCallJoinAsWidth);
|
||||
box->setTitle(rpl::single(u"Send message as..."_q));
|
||||
const auto &labelSt = st::confirmPhoneAboutLabel;
|
||||
box->addRow(object_ptr<Ui::FlatLabel>(
|
||||
box,
|
||||
tr::lng_group_call_join_as_about(),
|
||||
labelSt));
|
||||
|
||||
auto &lifetime = box->lifetime();
|
||||
const auto delegate = lifetime.make_state<
|
||||
PeerListContentDelegateSimple
|
||||
>();
|
||||
const auto controller = lifetime.make_state<ListController>(
|
||||
list,
|
||||
chosen);
|
||||
controller->setStyleOverrides(
|
||||
&st::peerListJoinAsList,
|
||||
nullptr);
|
||||
const auto content = box->addRow(
|
||||
object_ptr<PeerListContent>(box, controller),
|
||||
style::margins());
|
||||
delegate->setContent(content);
|
||||
controller->setDelegate(delegate);
|
||||
box->addButton(tr::lng_settings_save(), [=] {
|
||||
done(controller->selected());
|
||||
});
|
||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||
}
|
||||
|
||||
void SetupSendAsButton(
|
||||
not_null<SendAsButton*> button,
|
||||
not_null<Window::SessionController*> window) {
|
||||
using namespace rpl::mappers;
|
||||
button->setClickedCallback([=] {
|
||||
const auto history = window->activeChatCurrent().history();
|
||||
if (!history) {
|
||||
return;
|
||||
}
|
||||
const auto peer = history->peer;
|
||||
const auto session = &peer->session();
|
||||
const auto &list = session->sendAsPeers().list(peer);
|
||||
if (list.size() < 2) {
|
||||
return;
|
||||
}
|
||||
const auto done = [=](not_null<PeerData*> sendAs) {
|
||||
session->sendAsPeers().saveChosen(peer, sendAs);
|
||||
};
|
||||
window->show(Box(
|
||||
Ui::ChooseSendAsBox,
|
||||
list,
|
||||
session->sendAsPeers().resolveChosen(peer),
|
||||
done));
|
||||
});
|
||||
|
||||
auto userpic = window->activeChatValue(
|
||||
) | rpl::map([=](const Dialogs::Key &key) -> PeerData* {
|
||||
if (const auto history = key.history()) {
|
||||
return history->peer->isMegagroup()
|
||||
? history->peer.get()
|
||||
: nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}) | rpl::filter_nullptr(
|
||||
) | rpl::map([=](not_null<PeerData*> peer) {
|
||||
const auto channel = peer->asMegagroup();
|
||||
|
||||
auto updates = rpl::single(
|
||||
rpl::empty_value()
|
||||
) | rpl::then(channel->session().sendAsPeers().updated(
|
||||
) | rpl::filter(
|
||||
_1 == channel
|
||||
) | rpl::to_empty);
|
||||
|
||||
return rpl::combine(
|
||||
std::move(updates),
|
||||
channel->adminRightsValue()
|
||||
) | rpl::map([=] {
|
||||
return channel->session().sendAsPeers().resolveChosen(channel);
|
||||
}) | rpl::distinct_until_changed(
|
||||
) | rpl::map([=](not_null<PeerData*> chosen) {
|
||||
return Data::PeerUserpicImageValue(
|
||||
chosen,
|
||||
st::sendAsButton.size * style::DevicePixelRatio());
|
||||
}) | rpl::flatten_latest();
|
||||
}) | rpl::flatten_latest();
|
||||
|
||||
std::move(
|
||||
userpic
|
||||
) | rpl::start_with_next([=](QImage &&userpic) {
|
||||
button->setUserpic(std::move(userpic));
|
||||
}, button->lifetime());
|
||||
|
||||
}
|
||||
|
||||
} // namespace Ui
|
33
Telegram/SourceFiles/ui/chat/choose_send_as.h
Normal file
33
Telegram/SourceFiles/ui/chat/choose_send_as.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
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/object_ptr.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
|
||||
class PeerData;
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace Ui {
|
||||
|
||||
class SendAsButton;
|
||||
|
||||
void ChooseSendAsBox(
|
||||
not_null<GenericBox*> box,
|
||||
std::vector<not_null<PeerData*>> list,
|
||||
not_null<PeerData*> chosen,
|
||||
Fn<void(not_null<PeerData*>)> done);
|
||||
|
||||
void SetupSendAsButton(
|
||||
not_null<SendAsButton*> button,
|
||||
not_null<Window::SessionController*> window);
|
||||
|
||||
} // namespace Ui
|
Loading…
Reference in New Issue
Block a user