mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-07-26 07:23:02 +02:00
Allow enabling direct messages in channels.
This commit is contained in:
parent
23eedb468f
commit
d3f9a84a0a
39 changed files with 685 additions and 242 deletions
|
@ -1886,6 +1886,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_manage_linked_channel_posted" = "All new posts from this channel are forwarded to the group.";
|
"lng_manage_linked_channel_posted" = "All new posts from this channel are forwarded to the group.";
|
||||||
"lng_manage_discussion_group_warning" = "\"Chat history for new members\" will be switched to **Visible**.";
|
"lng_manage_discussion_group_warning" = "\"Chat history for new members\" will be switched to **Visible**.";
|
||||||
|
|
||||||
|
"lng_manage_monoforum" = "Direct Messages";
|
||||||
|
"lng_manage_monoforum_off" = "Off";
|
||||||
|
"lng_manage_monoforum_free" = "Free";
|
||||||
|
"lng_manage_monoforum_allow" = "Allow Direct Messages";
|
||||||
|
"lng_manage_monoforum_about" = "Allow users to write direct private messages to your channel, with the option to charge a fee for every message.";
|
||||||
|
"lng_manage_monoforum_price_about" = "Charge users for the ability to write a direct message to your channel. Your channel will receive {percent} of the selected fee ({amount}) for each incoming message.";
|
||||||
|
|
||||||
"lng_manage_history_visibility_title" = "Chat history for new members";
|
"lng_manage_history_visibility_title" = "Chat history for new members";
|
||||||
"lng_manage_history_visibility_shown" = "Visible";
|
"lng_manage_history_visibility_shown" = "Visible";
|
||||||
"lng_manage_history_visibility_shown_about" = "New members will see messages that were sent before they joined.";
|
"lng_manage_history_visibility_shown_about" = "New members will see messages that were sent before they joined.";
|
||||||
|
@ -2243,6 +2250,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_action_message_price_free" = "Messages are now free in this group.";
|
"lng_action_message_price_free" = "Messages are now free in this group.";
|
||||||
"lng_action_message_price_paid#one" = "Messages now cost {count} Star each in this group.";
|
"lng_action_message_price_paid#one" = "Messages now cost {count} Star each in this group.";
|
||||||
"lng_action_message_price_paid#other" = "Messages now cost {count} Stars each in this group.";
|
"lng_action_message_price_paid#other" = "Messages now cost {count} Stars each in this group.";
|
||||||
|
"lng_action_direct_messages_enabled" = "Channel enabled Direct Messages.";
|
||||||
|
"lng_action_direct_messages_paid#one" = "Channel allows Direct Messages for {count} Star each.";
|
||||||
|
"lng_action_direct_messages_paid#other" = "Channel allows Direct Messages for {count} Stars each";
|
||||||
|
"lng_action_direct_messages_disabled" = "Channel disabled Direct Messages.";
|
||||||
"lng_you_paid_stars#one" = "You paid {count} Star.";
|
"lng_you_paid_stars#one" = "You paid {count} Star.";
|
||||||
"lng_you_paid_stars#other" = "You paid {count} Stars.";
|
"lng_you_paid_stars#other" = "You paid {count} Stars.";
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_folder.h"
|
#include "data/data_folder.h"
|
||||||
#include "data/data_forum_topic.h"
|
#include "data/data_forum_topic.h"
|
||||||
#include "data/data_forum.h"
|
#include "data/data_forum.h"
|
||||||
|
#include "data/data_saved_messages.h"
|
||||||
#include "data/data_saved_sublist.h"
|
#include "data/data_saved_sublist.h"
|
||||||
#include "data/data_search_controller.h"
|
#include "data/data_search_controller.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
|
@ -381,6 +382,9 @@ void ApiWrap::savePinnedOrder(not_null<Data::Forum*> forum) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiWrap::savePinnedOrder(not_null<Data::SavedMessages*> saved) {
|
void ApiWrap::savePinnedOrder(not_null<Data::SavedMessages*> saved) {
|
||||||
|
if (saved->parentChat()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const auto &order = _session->data().pinnedChatsOrder(saved);
|
const auto &order = _session->data().pinnedChatsOrder(saved);
|
||||||
const auto input = [](Dialogs::Key key) {
|
const auto input = [](Dialogs::Key key) {
|
||||||
if (const auto sublist = key.sublist()) {
|
if (const auto sublist = key.sublist()) {
|
||||||
|
|
|
@ -1168,12 +1168,13 @@ rpl::producer<int> SetupChargeSlider(
|
||||||
struct State {
|
struct State {
|
||||||
rpl::variable<int> stars;
|
rpl::variable<int> stars;
|
||||||
};
|
};
|
||||||
const auto group = !peer->isUser();
|
const auto broadcast = peer->isBroadcast();
|
||||||
|
const auto group = !broadcast && !peer->isUser();
|
||||||
const auto state = container->lifetime().make_state<State>();
|
const auto state = container->lifetime().make_state<State>();
|
||||||
const auto chargeStars = savedValue ? savedValue : kDefaultChargeStars;
|
const auto chargeStars = savedValue ? savedValue : kDefaultChargeStars;
|
||||||
state->stars = chargeStars;
|
state->stars = chargeStars;
|
||||||
|
|
||||||
Ui::AddSubsectionTitle(container, group
|
Ui::AddSubsectionTitle(container, (group || broadcast)
|
||||||
? tr::lng_rights_charge_price()
|
? tr::lng_rights_charge_price()
|
||||||
: tr::lng_messages_privacy_price());
|
: tr::lng_messages_privacy_price());
|
||||||
|
|
||||||
|
@ -1225,7 +1226,9 @@ rpl::producer<int> SetupChargeSlider(
|
||||||
const auto percent = peer->session().appConfig().paidMessageCommission();
|
const auto percent = peer->session().appConfig().paidMessageCommission();
|
||||||
Ui::AddDividerText(
|
Ui::AddDividerText(
|
||||||
container,
|
container,
|
||||||
(group
|
(broadcast
|
||||||
|
? tr::lng_manage_monoforum_price_about
|
||||||
|
: group
|
||||||
? tr::lng_rights_charge_price_about
|
? tr::lng_rights_charge_price_about
|
||||||
: tr::lng_messages_privacy_price_about)(
|
: tr::lng_messages_privacy_price_about)(
|
||||||
lt_percent,
|
lt_percent,
|
||||||
|
@ -1235,3 +1238,54 @@ rpl::producer<int> SetupChargeSlider(
|
||||||
|
|
||||||
return state->stars.value();
|
return state->stars.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditDirectMessagesPriceBox(
|
||||||
|
not_null<Ui::GenericBox*> box,
|
||||||
|
not_null<ChannelData*> channel,
|
||||||
|
std::optional<int> savedValue,
|
||||||
|
Fn<void(std::optional<int>)> callback) {
|
||||||
|
box->setTitle(tr::lng_manage_monoforum());
|
||||||
|
|
||||||
|
const auto toggle = box->addRow(object_ptr<Ui::SettingsButton>(
|
||||||
|
box,
|
||||||
|
tr::lng_manage_monoforum_allow(),
|
||||||
|
st::settingsButtonNoIcon
|
||||||
|
), {})->toggleOn(rpl::single(savedValue.has_value()));
|
||||||
|
Ui::AddSkip(box->verticalLayout());
|
||||||
|
|
||||||
|
Ui::AddDividerText(
|
||||||
|
box->verticalLayout(),
|
||||||
|
tr::lng_manage_monoforum_about());
|
||||||
|
|
||||||
|
const auto wrap = box->addRow(
|
||||||
|
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||||
|
box,
|
||||||
|
object_ptr<Ui::VerticalLayout>(box)),
|
||||||
|
{});
|
||||||
|
wrap->toggle(savedValue.has_value(), anim::type::instant);
|
||||||
|
wrap->toggleOn(toggle->toggledChanges());
|
||||||
|
|
||||||
|
const auto result = box->lifetime().make_state<int>(
|
||||||
|
savedValue.value_or(0));
|
||||||
|
|
||||||
|
const auto inner = wrap->entity();
|
||||||
|
Ui::AddSkip(inner);
|
||||||
|
SetupChargeSlider(
|
||||||
|
inner,
|
||||||
|
channel,
|
||||||
|
savedValue.value_or(0)
|
||||||
|
) | rpl::start_with_next([=](int stars) {
|
||||||
|
*result = stars;
|
||||||
|
}, box->lifetime());
|
||||||
|
|
||||||
|
box->addButton(tr::lng_settings_save(), [=] {
|
||||||
|
const auto weak = Ui::MakeWeak(box);
|
||||||
|
callback(toggle->toggled() ? *result : std::optional<int>());
|
||||||
|
if (const auto strong = weak.data()) {
|
||||||
|
strong->closeBox();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
box->addButton(tr::lng_cancel(), [=] {
|
||||||
|
box->closeBox();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -174,3 +174,9 @@ void EditMessagesPrivacyBox(
|
||||||
not_null<Ui::VerticalLayout*> container,
|
not_null<Ui::VerticalLayout*> container,
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
int savedValue);
|
int savedValue);
|
||||||
|
|
||||||
|
void EditDirectMessagesPriceBox(
|
||||||
|
not_null<Ui::GenericBox*> box,
|
||||||
|
not_null<ChannelData*> channel,
|
||||||
|
std::optional<int> savedValue,
|
||||||
|
Fn<void(std::optional<int>)> callback);
|
||||||
|
|
|
@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "boxes/peers/replace_boost_box.h"
|
#include "boxes/peers/replace_boost_box.h"
|
||||||
#include "boxes/peers/verify_peers_box.h"
|
#include "boxes/peers/verify_peers_box.h"
|
||||||
#include "boxes/peer_list_controllers.h"
|
#include "boxes/peer_list_controllers.h"
|
||||||
|
#include "boxes/edit_privacy_box.h" // EditDirectMessagesPriceBox
|
||||||
#include "boxes/stickers_box.h"
|
#include "boxes/stickers_box.h"
|
||||||
#include "boxes/username_box.h"
|
#include "boxes/username_box.h"
|
||||||
#include "chat_helpers/emoji_suggestions_widget.h"
|
#include "chat_helpers/emoji_suggestions_widget.h"
|
||||||
|
@ -220,28 +221,41 @@ void SaveSlowmodeSeconds(
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveStarsPerMessage(
|
void SaveStarsPerMessage(
|
||||||
|
std::shared_ptr<Ui::Show> show,
|
||||||
not_null<ChannelData*> channel,
|
not_null<ChannelData*> channel,
|
||||||
int starsPerMessage,
|
int starsPerMessage,
|
||||||
Fn<void()> done) {
|
Fn<void(bool)> done) {
|
||||||
const auto api = &channel->session().api();
|
const auto api = &channel->session().api();
|
||||||
const auto key = Api::RequestKey("stars_per_message", channel->id);
|
const auto key = Api::RequestKey("stars_per_message", channel->id);
|
||||||
|
|
||||||
|
const auto broadcast = channel->isBroadcast();
|
||||||
|
|
||||||
|
using Flag = MTPchannels_UpdatePaidMessagesPrice::Flag;
|
||||||
|
const auto broadcastAllowed = broadcast && (starsPerMessage >= 0);
|
||||||
const auto requestId = api->request(MTPchannels_UpdatePaidMessagesPrice(
|
const auto requestId = api->request(MTPchannels_UpdatePaidMessagesPrice(
|
||||||
MTP_flags(0), // #TODO Support broadcast_messages_allowed flag in UI
|
MTP_flags(broadcastAllowed
|
||||||
|
? Flag::f_broadcast_messages_allowed
|
||||||
|
: Flag(0)),
|
||||||
channel->inputChannel,
|
channel->inputChannel,
|
||||||
MTP_long(starsPerMessage)
|
MTP_long(starsPerMessage)
|
||||||
)).done([=](const MTPUpdates &result) {
|
)).done([=](const MTPUpdates &result) {
|
||||||
api->clearModifyRequest(key);
|
api->clearModifyRequest(key);
|
||||||
api->applyUpdates(result);
|
api->applyUpdates(result);
|
||||||
channel->setStarsPerMessage(starsPerMessage);
|
if (!broadcast) {
|
||||||
done();
|
channel->setStarsPerMessage(starsPerMessage);
|
||||||
|
}
|
||||||
|
done(true);
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
api->clearModifyRequest(key);
|
api->clearModifyRequest(key);
|
||||||
if (error.type() != u"CHAT_NOT_MODIFIED"_q) {
|
if (error.type() != u"CHAT_NOT_MODIFIED"_q) {
|
||||||
return;
|
show->showToast(error.type());
|
||||||
|
done(false);
|
||||||
|
} else {
|
||||||
|
if (!broadcast) {
|
||||||
|
channel->setStarsPerMessage(starsPerMessage);
|
||||||
|
}
|
||||||
|
done(true);
|
||||||
}
|
}
|
||||||
channel->setStarsPerMessage(starsPerMessage);
|
|
||||||
done();
|
|
||||||
}).send();
|
}).send();
|
||||||
|
|
||||||
api->registerModifyRequest(key, requestId);
|
api->registerModifyRequest(key, requestId);
|
||||||
|
@ -281,6 +295,7 @@ void SaveBoostsUnrestrict(
|
||||||
void ShowEditPermissions(
|
void ShowEditPermissions(
|
||||||
not_null<Window::SessionNavigation*> navigation,
|
not_null<Window::SessionNavigation*> navigation,
|
||||||
not_null<PeerData*> peer) {
|
not_null<PeerData*> peer) {
|
||||||
|
const auto show = navigation->uiShow();
|
||||||
auto createBox = [=](not_null<Ui::GenericBox*> box) {
|
auto createBox = [=](not_null<Ui::GenericBox*> box) {
|
||||||
const auto saving = box->lifetime().make_state<int>(0);
|
const auto saving = box->lifetime().make_state<int>(0);
|
||||||
const auto save = [=](
|
const auto save = [=](
|
||||||
|
@ -299,7 +314,10 @@ void ShowEditPermissions(
|
||||||
channel,
|
channel,
|
||||||
result.boostsUnrestrict,
|
result.boostsUnrestrict,
|
||||||
close);
|
close);
|
||||||
SaveStarsPerMessage(channel, result.starsPerMessage, close);
|
const auto price = result.starsPerMessage;
|
||||||
|
SaveStarsPerMessage(show, channel, price, [=](bool ok) {
|
||||||
|
close();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
auto done = [=](EditPeerPermissionsBoxResult result) {
|
auto done = [=](EditPeerPermissionsBoxResult result) {
|
||||||
|
@ -366,6 +384,7 @@ private:
|
||||||
std::optional<bool> joinToWrite;
|
std::optional<bool> joinToWrite;
|
||||||
std::optional<bool> requestToJoin;
|
std::optional<bool> requestToJoin;
|
||||||
std::optional<ChannelData*> discussionLink;
|
std::optional<ChannelData*> discussionLink;
|
||||||
|
std::optional<int> starsPerDirectMessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] object_ptr<Ui::RpWidget> createPhotoAndTitleEdit();
|
[[nodiscard]] object_ptr<Ui::RpWidget> createPhotoAndTitleEdit();
|
||||||
|
@ -382,8 +401,10 @@ private:
|
||||||
void showEditPeerTypeBox(
|
void showEditPeerTypeBox(
|
||||||
std::optional<rpl::producer<QString>> error = {});
|
std::optional<rpl::producer<QString>> error = {});
|
||||||
void showEditDiscussionLinkBox();
|
void showEditDiscussionLinkBox();
|
||||||
|
void showEditDirectMessagesBox();
|
||||||
void fillPrivacyTypeButton();
|
void fillPrivacyTypeButton();
|
||||||
void fillDiscussionLinkButton();
|
void fillDiscussionLinkButton();
|
||||||
|
void fillDirectMessagesButton();
|
||||||
//void fillInviteLinkButton();
|
//void fillInviteLinkButton();
|
||||||
void fillForumButton();
|
void fillForumButton();
|
||||||
void fillColorIndexButton();
|
void fillColorIndexButton();
|
||||||
|
@ -412,6 +433,7 @@ private:
|
||||||
[[nodiscard]] bool validateUsernamesOrder(Saving &to) const;
|
[[nodiscard]] bool validateUsernamesOrder(Saving &to) const;
|
||||||
[[nodiscard]] bool validateUsername(Saving &to) const;
|
[[nodiscard]] bool validateUsername(Saving &to) const;
|
||||||
[[nodiscard]] bool validateDiscussionLink(Saving &to) const;
|
[[nodiscard]] bool validateDiscussionLink(Saving &to) const;
|
||||||
|
[[nodiscard]] bool validateDirectMessagesPrice(Saving &to) const;
|
||||||
[[nodiscard]] bool validateTitle(Saving &to) const;
|
[[nodiscard]] bool validateTitle(Saving &to) const;
|
||||||
[[nodiscard]] bool validateDescription(Saving &to) const;
|
[[nodiscard]] bool validateDescription(Saving &to) const;
|
||||||
[[nodiscard]] bool validateHistoryVisibility(Saving &to) const;
|
[[nodiscard]] bool validateHistoryVisibility(Saving &to) const;
|
||||||
|
@ -426,6 +448,7 @@ private:
|
||||||
void saveUsernamesOrder();
|
void saveUsernamesOrder();
|
||||||
void saveUsername();
|
void saveUsername();
|
||||||
void saveDiscussionLink();
|
void saveDiscussionLink();
|
||||||
|
void saveDirectMessagesPrice();
|
||||||
void saveTitle();
|
void saveTitle();
|
||||||
void saveDescription();
|
void saveDescription();
|
||||||
void saveHistoryVisibility();
|
void saveHistoryVisibility();
|
||||||
|
@ -454,6 +477,7 @@ private:
|
||||||
std::optional<ChannelData*> _discussionLinkSavedValue;
|
std::optional<ChannelData*> _discussionLinkSavedValue;
|
||||||
ChannelData *_discussionLinkOriginalValue = nullptr;
|
ChannelData *_discussionLinkOriginalValue = nullptr;
|
||||||
bool _channelHasLocationOriginalValue = false;
|
bool _channelHasLocationOriginalValue = false;
|
||||||
|
std::optional<rpl::variable<int>> _starsPerDirectMessageSavedValue;
|
||||||
std::optional<HistoryVisibility> _historyVisibilitySavedValue;
|
std::optional<HistoryVisibility> _historyVisibilitySavedValue;
|
||||||
std::optional<EditPeerTypeData> _typeDataSavedValue;
|
std::optional<EditPeerTypeData> _typeDataSavedValue;
|
||||||
std::optional<bool> _forumSavedValue;
|
std::optional<bool> _forumSavedValue;
|
||||||
|
@ -918,6 +942,20 @@ void Controller::showEditDiscussionLinkBox() {
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Controller::showEditDirectMessagesBox() {
|
||||||
|
Expects(_peer->isBroadcast());
|
||||||
|
Expects(_starsPerDirectMessageSavedValue.has_value());
|
||||||
|
|
||||||
|
const auto stars = _starsPerDirectMessageSavedValue->current();
|
||||||
|
_navigation->parentController()->show(Box(
|
||||||
|
EditDirectMessagesPriceBox,
|
||||||
|
_peer->asChannel(),
|
||||||
|
(stars >= 0) ? stars : std::optional<int>(),
|
||||||
|
[=](std::optional<int> value) {
|
||||||
|
*_starsPerDirectMessageSavedValue = value.value_or(-1);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
void Controller::fillPrivacyTypeButton() {
|
void Controller::fillPrivacyTypeButton() {
|
||||||
Expects(_controls.buttonsLayout != nullptr);
|
Expects(_controls.buttonsLayout != nullptr);
|
||||||
|
|
||||||
|
@ -983,9 +1021,11 @@ void Controller::fillPrivacyTypeButton() {
|
||||||
void Controller::fillDiscussionLinkButton() {
|
void Controller::fillDiscussionLinkButton() {
|
||||||
Expects(_controls.buttonsLayout != nullptr);
|
Expects(_controls.buttonsLayout != nullptr);
|
||||||
|
|
||||||
_discussionLinkSavedValue = _discussionLinkOriginalValue = _peer->isChannel()
|
_discussionLinkSavedValue
|
||||||
? _peer->asChannel()->discussionLink()
|
= _discussionLinkOriginalValue
|
||||||
: nullptr;
|
= (_peer->isChannel()
|
||||||
|
? _peer->asChannel()->discussionLink()
|
||||||
|
: nullptr);
|
||||||
|
|
||||||
const auto isGroup = (_peer->isChat() || _peer->isMegagroup());
|
const auto isGroup = (_peer->isChat() || _peer->isMegagroup());
|
||||||
auto text = !isGroup
|
auto text = !isGroup
|
||||||
|
@ -1019,6 +1059,33 @@ void Controller::fillDiscussionLinkButton() {
|
||||||
{ isGroup ? &st::menuIconChannel : &st::menuIconGroups });
|
{ isGroup ? &st::menuIconChannel : &st::menuIconGroups });
|
||||||
_discussionLinkUpdates.fire_copy(*_discussionLinkSavedValue);
|
_discussionLinkUpdates.fire_copy(*_discussionLinkSavedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Controller::fillDirectMessagesButton() {
|
||||||
|
Expects(_controls.buttonsLayout != nullptr);
|
||||||
|
|
||||||
|
if (!_peer->isBroadcast() || !_peer->asChannel()->canEditInformation()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto monoforumLink = _peer->asChannel()->monoforumLink();
|
||||||
|
_starsPerDirectMessageSavedValue = rpl::variable<int>(
|
||||||
|
monoforumLink ? monoforumLink->starsPerMessage() : -1);
|
||||||
|
|
||||||
|
auto label = _starsPerDirectMessageSavedValue->value(
|
||||||
|
) | rpl::map([](int starsPerMessage) {
|
||||||
|
return (starsPerMessage < 0)
|
||||||
|
? tr::lng_manage_monoforum_off()
|
||||||
|
: !starsPerMessage
|
||||||
|
? tr::lng_manage_monoforum_free()
|
||||||
|
: rpl::single(Lang::FormatCountDecimal(starsPerMessage));
|
||||||
|
}) | rpl::flatten_latest();
|
||||||
|
AddButtonWithText(
|
||||||
|
_controls.buttonsLayout,
|
||||||
|
tr::lng_manage_monoforum(),
|
||||||
|
std::move(label),
|
||||||
|
[=] { showEditDirectMessagesBox(); },
|
||||||
|
{ &st::menuIconChatBubble });
|
||||||
|
}
|
||||||
//
|
//
|
||||||
//void Controller::fillInviteLinkButton() {
|
//void Controller::fillInviteLinkButton() {
|
||||||
// Expects(_controls.buttonsLayout != nullptr);
|
// Expects(_controls.buttonsLayout != nullptr);
|
||||||
|
@ -1359,6 +1426,8 @@ void Controller::fillManageSection() {
|
||||||
const auto canViewOrEditDiscussionLink = isChannel
|
const auto canViewOrEditDiscussionLink = isChannel
|
||||||
&& (channel->discussionLink()
|
&& (channel->discussionLink()
|
||||||
|| (channel->isBroadcast() && channel->canEditInformation()));
|
|| (channel->isBroadcast() && channel->canEditInformation()));
|
||||||
|
const auto canEditDirectMessages = isChannel
|
||||||
|
&& (channel->isBroadcast() && channel->canEditInformation());
|
||||||
|
|
||||||
::AddSkip(_controls.buttonsLayout, 0);
|
::AddSkip(_controls.buttonsLayout, 0);
|
||||||
|
|
||||||
|
@ -1370,6 +1439,9 @@ void Controller::fillManageSection() {
|
||||||
if (canViewOrEditDiscussionLink) {
|
if (canViewOrEditDiscussionLink) {
|
||||||
fillDiscussionLinkButton();
|
fillDiscussionLinkButton();
|
||||||
}
|
}
|
||||||
|
if (canEditDirectMessages) {
|
||||||
|
fillDirectMessagesButton();
|
||||||
|
}
|
||||||
if (canEditPreHistoryHidden) {
|
if (canEditPreHistoryHidden) {
|
||||||
fillHistoryVisibilityButton();
|
fillHistoryVisibilityButton();
|
||||||
}
|
}
|
||||||
|
@ -1973,6 +2045,7 @@ std::optional<Controller::Saving> Controller::validate() const {
|
||||||
if (validateUsernamesOrder(result)
|
if (validateUsernamesOrder(result)
|
||||||
&& validateUsername(result)
|
&& validateUsername(result)
|
||||||
&& validateDiscussionLink(result)
|
&& validateDiscussionLink(result)
|
||||||
|
&& validateDirectMessagesPrice(result)
|
||||||
&& validateTitle(result)
|
&& validateTitle(result)
|
||||||
&& validateDescription(result)
|
&& validateDescription(result)
|
||||||
&& validateHistoryVisibility(result)
|
&& validateHistoryVisibility(result)
|
||||||
|
@ -2022,6 +2095,14 @@ bool Controller::validateDiscussionLink(Saving &to) const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Controller::validateDirectMessagesPrice(Saving &to) const {
|
||||||
|
if (!_starsPerDirectMessageSavedValue) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
to.starsPerDirectMessage = _starsPerDirectMessageSavedValue->current();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Controller::validateTitle(Saving &to) const {
|
bool Controller::validateTitle(Saving &to) const {
|
||||||
if (!_controls.title) {
|
if (!_controls.title) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -2120,6 +2201,7 @@ void Controller::save() {
|
||||||
pushSaveStage([=] { saveUsernamesOrder(); });
|
pushSaveStage([=] { saveUsernamesOrder(); });
|
||||||
pushSaveStage([=] { saveUsername(); });
|
pushSaveStage([=] { saveUsername(); });
|
||||||
pushSaveStage([=] { saveDiscussionLink(); });
|
pushSaveStage([=] { saveDiscussionLink(); });
|
||||||
|
pushSaveStage([=] { saveDirectMessagesPrice(); });
|
||||||
pushSaveStage([=] { saveTitle(); });
|
pushSaveStage([=] { saveTitle(); });
|
||||||
pushSaveStage([=] { saveDescription(); });
|
pushSaveStage([=] { saveDescription(); });
|
||||||
pushSaveStage([=] { saveHistoryVisibility(); });
|
pushSaveStage([=] { saveHistoryVisibility(); });
|
||||||
|
@ -2277,6 +2359,30 @@ void Controller::saveDiscussionLink() {
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Controller::saveDirectMessagesPrice() {
|
||||||
|
const auto channel = _peer->asChannel();
|
||||||
|
if (!channel) {
|
||||||
|
return continueSave();
|
||||||
|
}
|
||||||
|
const auto monoforumLink = channel->monoforumLink();
|
||||||
|
const auto current = monoforumLink ? monoforumLink->starsPerMessage() : -1;
|
||||||
|
const auto desired = _savingData.starsPerDirectMessage
|
||||||
|
? *_savingData.starsPerDirectMessage
|
||||||
|
: current;
|
||||||
|
if (desired == current) {
|
||||||
|
return continueSave();
|
||||||
|
}
|
||||||
|
const auto show = _navigation->uiShow();
|
||||||
|
const auto done = [=](bool ok) {
|
||||||
|
if (ok) {
|
||||||
|
continueSave();
|
||||||
|
} else {
|
||||||
|
cancelSave();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
SaveStarsPerMessage(show, channel, desired, crl::guard(this, done));
|
||||||
|
}
|
||||||
|
|
||||||
void Controller::saveTitle() {
|
void Controller::saveTitle() {
|
||||||
if (!_savingData.title || *_savingData.title == _peer->name()) {
|
if (!_savingData.title || *_savingData.title == _peer->name()) {
|
||||||
return continueSave();
|
return continueSave();
|
||||||
|
|
|
@ -907,6 +907,7 @@ void PinsLimitBox(
|
||||||
limits.dialogsPinnedPremium(),
|
limits.dialogsPinnedPremium(),
|
||||||
PinsCount(session->data().chatsList()));
|
PinsCount(session->data().chatsList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SublistsPinsLimitBox(
|
void SublistsPinsLimitBox(
|
||||||
not_null<Ui::GenericBox*> box,
|
not_null<Ui::GenericBox*> box,
|
||||||
not_null<Main::Session*> session) {
|
not_null<Main::Session*> session) {
|
||||||
|
|
|
@ -871,6 +871,10 @@ historyGiftToChannel: IconButton(defaultIconButton) {
|
||||||
rippleAreaSize: 40px;
|
rippleAreaSize: 40px;
|
||||||
ripple: universalRippleAnimation;
|
ripple: universalRippleAnimation;
|
||||||
}
|
}
|
||||||
|
historyDirectMessage: IconButton(historyGiftToChannel) {
|
||||||
|
icon: icon{{ "menu/chat_bubble", windowActiveTextFg }};
|
||||||
|
iconOver: icon{{ "menu/chat_bubble", windowActiveTextFg }};
|
||||||
|
}
|
||||||
historyUnblock: FlatButton(historyComposeButton) {
|
historyUnblock: FlatButton(historyComposeButton) {
|
||||||
color: attentionButtonFg;
|
color: attentionButtonFg;
|
||||||
overColor: attentionButtonFgOver;
|
overColor: attentionButtonFgOver;
|
||||||
|
|
|
@ -112,12 +112,13 @@ struct PeerUpdate {
|
||||||
StickersSet = (1ULL << 46),
|
StickersSet = (1ULL << 46),
|
||||||
EmojiSet = (1ULL << 47),
|
EmojiSet = (1ULL << 47),
|
||||||
DiscussionLink = (1ULL << 48),
|
DiscussionLink = (1ULL << 48),
|
||||||
ChannelLocation = (1ULL << 49),
|
MonoforumLink = (1ULL << 49),
|
||||||
Slowmode = (1ULL << 50),
|
ChannelLocation = (1ULL << 50),
|
||||||
GroupCall = (1ULL << 51),
|
Slowmode = (1ULL << 51),
|
||||||
|
GroupCall = (1ULL << 52),
|
||||||
|
|
||||||
// For iteration
|
// For iteration
|
||||||
LastUsedBit = (1ULL << 51),
|
LastUsedBit = (1ULL << 52),
|
||||||
};
|
};
|
||||||
using Flags = base::flags<Flag>;
|
using Flags = base::flags<Flag>;
|
||||||
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
||||||
|
|
|
@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_histories.h"
|
#include "data/data_histories.h"
|
||||||
#include "data/data_group_call.h"
|
#include "data/data_group_call.h"
|
||||||
#include "data/data_message_reactions.h"
|
#include "data/data_message_reactions.h"
|
||||||
|
#include "data/data_saved_messages.h"
|
||||||
#include "data/data_wall_paper.h"
|
#include "data/data_wall_paper.h"
|
||||||
#include "data/notify/data_notify_settings.h"
|
#include "data/notify/data_notify_settings.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
|
@ -89,6 +90,29 @@ std::unique_ptr<Data::Forum> MegagroupInfo::takeForumData() {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MegagroupInfo::ensureMonoforum(not_null<ChannelData*> that) {
|
||||||
|
if (!_monoforum) {
|
||||||
|
const auto history = that->owner().history(that);
|
||||||
|
_monoforum = std::make_unique<Data::SavedMessages>(
|
||||||
|
&that->owner(),
|
||||||
|
that);
|
||||||
|
history->monoforumChanged(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Data::SavedMessages *MegagroupInfo::monoforum() const {
|
||||||
|
return _monoforum.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Data::SavedMessages> MegagroupInfo::takeMonoforumData() {
|
||||||
|
if (auto result = base::take(_monoforum)) {
|
||||||
|
const auto history = result->owner().history(result->parentChat());
|
||||||
|
history->monoforumChanged(result.get());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
ChannelData::ChannelData(not_null<Data::Session*> owner, PeerId id)
|
ChannelData::ChannelData(not_null<Data::Session*> owner, PeerId id)
|
||||||
: PeerData(owner, id)
|
: PeerData(owner, id)
|
||||||
, inputChannel(
|
, inputChannel(
|
||||||
|
@ -161,6 +185,12 @@ void ChannelData::setAccessHash(uint64 accessHash) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChannelData::setFlags(ChannelDataFlags which) {
|
void ChannelData::setFlags(ChannelDataFlags which) {
|
||||||
|
if (which & (Flag::Forum | Flag::Monoforum)) {
|
||||||
|
which |= Flag::Megagroup;
|
||||||
|
}
|
||||||
|
if (which & Flag::Monoforum) {
|
||||||
|
which &= ~Flag::Forum;
|
||||||
|
}
|
||||||
const auto diff = flags() ^ which;
|
const auto diff = flags() ^ which;
|
||||||
if ((which & Flag::Megagroup) && !mgInfo) {
|
if ((which & Flag::Megagroup) && !mgInfo) {
|
||||||
mgInfo = std::make_unique<MegagroupInfo>();
|
mgInfo = std::make_unique<MegagroupInfo>();
|
||||||
|
@ -276,8 +306,9 @@ const ChannelLocation *ChannelData::getLocation() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChannelData::setDiscussionLink(ChannelData *linked) {
|
void ChannelData::setDiscussionLink(ChannelData *linked) {
|
||||||
if (_discussionLink != linked) {
|
if (_discussionLink != linked || !_discussionLinkKnown) {
|
||||||
_discussionLink = linked;
|
_discussionLink = linked;
|
||||||
|
_discussionLinkKnown = true;
|
||||||
if (const auto history = owner().historyLoaded(this)) {
|
if (const auto history = owner().historyLoaded(this)) {
|
||||||
history->forceFullResize();
|
history->forceFullResize();
|
||||||
}
|
}
|
||||||
|
@ -286,11 +317,22 @@ void ChannelData::setDiscussionLink(ChannelData *linked) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ChannelData *ChannelData::discussionLink() const {
|
ChannelData *ChannelData::discussionLink() const {
|
||||||
return _discussionLink.value_or(nullptr);
|
return _discussionLink;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChannelData::discussionLinkKnown() const {
|
bool ChannelData::discussionLinkKnown() const {
|
||||||
return _discussionLink.has_value();
|
return _discussionLinkKnown;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelData::setMonoforumLink(ChannelData *link) {
|
||||||
|
if (_monoforumLink != link) {
|
||||||
|
_monoforumLink = link;
|
||||||
|
session().changes().peerUpdated(this, UpdateFlag::MonoforumLink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelData *ChannelData::monoforumLink() const {
|
||||||
|
return _monoforumLink;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChannelData::setMembersCount(int newMembersCount) {
|
void ChannelData::setMembersCount(int newMembersCount) {
|
||||||
|
@ -1240,6 +1282,11 @@ void ApplyChannelUpdate(
|
||||||
} else {
|
} else {
|
||||||
channel->setDiscussionLink(nullptr);
|
channel->setDiscussionLink(nullptr);
|
||||||
}
|
}
|
||||||
|
if (const auto chat = update.vlinked_monoforum_id()) {
|
||||||
|
channel->setMonoforumLink(channel->owner().channelLoaded(chat->v));
|
||||||
|
} else {
|
||||||
|
channel->setMonoforumLink(nullptr);
|
||||||
|
}
|
||||||
if (const auto history = channel->owner().historyLoaded(channel)) {
|
if (const auto history = channel->owner().historyLoaded(channel)) {
|
||||||
if (const auto available = update.vavailable_min_id()) {
|
if (const auto available = update.vavailable_min_id()) {
|
||||||
history->clearUpTill(available->v);
|
history->clearUpTill(available->v);
|
||||||
|
|
|
@ -16,6 +16,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
class ChannelData;
|
class ChannelData;
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
class Forum;
|
||||||
|
class SavedMessages;
|
||||||
|
} // namespace Data
|
||||||
|
|
||||||
struct ChannelLocation {
|
struct ChannelLocation {
|
||||||
QString address;
|
QString address;
|
||||||
Data::LocationPoint point;
|
Data::LocationPoint point;
|
||||||
|
@ -74,6 +79,7 @@ enum class ChannelDataFlag : uint64 {
|
||||||
StargiftsAvailable = (1ULL << 36),
|
StargiftsAvailable = (1ULL << 36),
|
||||||
PaidMessagesAvailable = (1ULL << 37),
|
PaidMessagesAvailable = (1ULL << 37),
|
||||||
AutoTranslation = (1ULL << 38),
|
AutoTranslation = (1ULL << 38),
|
||||||
|
Monoforum = (1ULL << 39),
|
||||||
};
|
};
|
||||||
inline constexpr bool is_flag_type(ChannelDataFlag) { return true; };
|
inline constexpr bool is_flag_type(ChannelDataFlag) { return true; };
|
||||||
using ChannelDataFlags = base::flags<ChannelDataFlag>;
|
using ChannelDataFlags = base::flags<ChannelDataFlag>;
|
||||||
|
@ -118,6 +124,10 @@ public:
|
||||||
[[nodiscard]] Data::Forum *forum() const;
|
[[nodiscard]] Data::Forum *forum() const;
|
||||||
[[nodiscard]] std::unique_ptr<Data::Forum> takeForumData();
|
[[nodiscard]] std::unique_ptr<Data::Forum> takeForumData();
|
||||||
|
|
||||||
|
void ensureMonoforum(not_null<ChannelData*> that);
|
||||||
|
[[nodiscard]] Data::SavedMessages *monoforum() const;
|
||||||
|
[[nodiscard]] std::unique_ptr<Data::SavedMessages> takeMonoforumData();
|
||||||
|
|
||||||
std::deque<not_null<UserData*>> lastParticipants;
|
std::deque<not_null<UserData*>> lastParticipants;
|
||||||
base::flat_map<not_null<UserData*>, Admin> lastAdmins;
|
base::flat_map<not_null<UserData*>, Admin> lastAdmins;
|
||||||
base::flat_map<not_null<UserData*>, Restricted> lastRestricted;
|
base::flat_map<not_null<UserData*>, Restricted> lastRestricted;
|
||||||
|
@ -154,6 +164,7 @@ private:
|
||||||
ChannelLocation _location;
|
ChannelLocation _location;
|
||||||
Data::ChatBotCommands _botCommands;
|
Data::ChatBotCommands _botCommands;
|
||||||
std::unique_ptr<Data::Forum> _forum;
|
std::unique_ptr<Data::Forum> _forum;
|
||||||
|
std::unique_ptr<Data::SavedMessages> _monoforum;
|
||||||
int _starsPerMessage = 0;
|
int _starsPerMessage = 0;
|
||||||
|
|
||||||
friend class ChannelData;
|
friend class ChannelData;
|
||||||
|
@ -301,6 +312,9 @@ public:
|
||||||
[[nodiscard]] bool isForum() const {
|
[[nodiscard]] bool isForum() const {
|
||||||
return flags() & Flag::Forum;
|
return flags() & Flag::Forum;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] bool isMonoforum() const {
|
||||||
|
return flags() & Flag::Monoforum;
|
||||||
|
}
|
||||||
[[nodiscard]] bool hasUsername() const {
|
[[nodiscard]] bool hasUsername() const {
|
||||||
return flags() & Flag::Username;
|
return flags() & Flag::Username;
|
||||||
}
|
}
|
||||||
|
@ -413,6 +427,9 @@ public:
|
||||||
[[nodiscard]] ChannelData *discussionLink() const;
|
[[nodiscard]] ChannelData *discussionLink() const;
|
||||||
[[nodiscard]] bool discussionLinkKnown() const;
|
[[nodiscard]] bool discussionLinkKnown() const;
|
||||||
|
|
||||||
|
void setMonoforumLink(ChannelData *link);
|
||||||
|
[[nodiscard]] ChannelData *monoforumLink() const;
|
||||||
|
|
||||||
void ptsInit(int32 pts) {
|
void ptsInit(int32 pts) {
|
||||||
_ptsWaiter.init(pts);
|
_ptsWaiter.init(pts);
|
||||||
}
|
}
|
||||||
|
@ -510,6 +527,9 @@ public:
|
||||||
[[nodiscard]] Data::Forum *forum() const {
|
[[nodiscard]] Data::Forum *forum() const {
|
||||||
return mgInfo ? mgInfo->forum() : nullptr;
|
return mgInfo ? mgInfo->forum() : nullptr;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] Data::SavedMessages *monoforum() const {
|
||||||
|
return mgInfo ? mgInfo->monoforum() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void processTopics(const MTPVector<MTPForumTopic> &topics);
|
void processTopics(const MTPVector<MTPForumTopic> &topics);
|
||||||
|
|
||||||
|
@ -546,18 +566,11 @@ private:
|
||||||
std::vector<Data::UnavailableReason> &&reasons) override;
|
std::vector<Data::UnavailableReason> &&reasons) override;
|
||||||
|
|
||||||
Flags _flags = ChannelDataFlags(Flag::Forbidden);
|
Flags _flags = ChannelDataFlags(Flag::Forbidden);
|
||||||
int _peerGiftsCount = 0;
|
|
||||||
|
|
||||||
PtsWaiter _ptsWaiter;
|
PtsWaiter _ptsWaiter;
|
||||||
|
|
||||||
Data::UsernamesInfo _username;
|
Data::UsernamesInfo _username;
|
||||||
|
|
||||||
int _membersCount = -1;
|
|
||||||
int _adminsCount = 1;
|
|
||||||
int _restrictedCount = 0;
|
|
||||||
int _kickedCount = 0;
|
|
||||||
int _pendingRequestsCount = 0;
|
|
||||||
int _levelHint = 0;
|
|
||||||
std::vector<UserId> _recentRequesters;
|
std::vector<UserId> _recentRequesters;
|
||||||
MsgId _availableMinId = 0;
|
MsgId _availableMinId = 0;
|
||||||
|
|
||||||
|
@ -570,7 +583,18 @@ private:
|
||||||
std::vector<Data::UnavailableReason> _unavailableReasons;
|
std::vector<Data::UnavailableReason> _unavailableReasons;
|
||||||
std::unique_ptr<InvitePeek> _invitePeek;
|
std::unique_ptr<InvitePeek> _invitePeek;
|
||||||
QString _inviteLink;
|
QString _inviteLink;
|
||||||
std::optional<ChannelData*> _discussionLink;
|
|
||||||
|
ChannelData *_discussionLink = nullptr;
|
||||||
|
ChannelData *_monoforumLink = nullptr;
|
||||||
|
bool _discussionLinkKnown = false;
|
||||||
|
|
||||||
|
int _peerGiftsCount = 0;
|
||||||
|
int _membersCount = -1;
|
||||||
|
int _adminsCount = 1;
|
||||||
|
int _restrictedCount = 0;
|
||||||
|
int _kickedCount = 0;
|
||||||
|
int _pendingRequestsCount = 0;
|
||||||
|
int _levelHint = 0;
|
||||||
|
|
||||||
Data::AllowedReactions _allowedReactions;
|
Data::AllowedReactions _allowedReactions;
|
||||||
|
|
||||||
|
|
|
@ -159,7 +159,8 @@ bool CanSendAnyOf(
|
||||||
using Flag = ChannelDataFlag;
|
using Flag = ChannelDataFlag;
|
||||||
const auto allowed = channel->amIn()
|
const auto allowed = channel->amIn()
|
||||||
|| ((channel->flags() & Flag::HasLink)
|
|| ((channel->flags() & Flag::HasLink)
|
||||||
&& !(channel->flags() & Flag::JoinToWrite));
|
&& !(channel->flags() & Flag::JoinToWrite))
|
||||||
|
|| channel->isMonoforum();
|
||||||
if (!allowed || (forbidInForums && channel->isForum())) {
|
if (!allowed || (forbidInForums && channel->isForum())) {
|
||||||
return false;
|
return false;
|
||||||
} else if (channel->canPostMessages()) {
|
} else if (channel->canPostMessages()) {
|
||||||
|
|
|
@ -1333,6 +1333,13 @@ bool PeerData::isForum() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PeerData::isMonoforum() const {
|
||||||
|
if (const auto channel = asChannel()) {
|
||||||
|
return channel->isMonoforum();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool PeerData::isGigagroup() const {
|
bool PeerData::isGigagroup() const {
|
||||||
if (const auto channel = asChannel()) {
|
if (const auto channel = asChannel()) {
|
||||||
return channel->isGigagroup();
|
return channel->isGigagroup();
|
||||||
|
@ -1416,6 +1423,13 @@ Data::ForumTopic *PeerData::forumTopicFor(MsgId rootId) const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Data::SavedMessages *PeerData::monoforum() const {
|
||||||
|
if (const auto channel = asChannel()) {
|
||||||
|
return channel->monoforum();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
bool PeerData::allowsForwarding() const {
|
bool PeerData::allowsForwarding() const {
|
||||||
if (isUser()) {
|
if (isUser()) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -37,6 +37,7 @@ class Forum;
|
||||||
class ForumTopic;
|
class ForumTopic;
|
||||||
class Session;
|
class Session;
|
||||||
class GroupCall;
|
class GroupCall;
|
||||||
|
class SavedMessages;
|
||||||
struct ReactionId;
|
struct ReactionId;
|
||||||
class WallPaper;
|
class WallPaper;
|
||||||
|
|
||||||
|
@ -232,6 +233,7 @@ public:
|
||||||
[[nodiscard]] bool isMegagroup() const;
|
[[nodiscard]] bool isMegagroup() const;
|
||||||
[[nodiscard]] bool isBroadcast() const;
|
[[nodiscard]] bool isBroadcast() const;
|
||||||
[[nodiscard]] bool isForum() const;
|
[[nodiscard]] bool isForum() const;
|
||||||
|
[[nodiscard]] bool isMonoforum() const;
|
||||||
[[nodiscard]] bool isGigagroup() const;
|
[[nodiscard]] bool isGigagroup() const;
|
||||||
[[nodiscard]] bool isRepliesChat() const;
|
[[nodiscard]] bool isRepliesChat() const;
|
||||||
[[nodiscard]] bool isVerifyCodes() const;
|
[[nodiscard]] bool isVerifyCodes() const;
|
||||||
|
@ -257,6 +259,8 @@ public:
|
||||||
[[nodiscard]] Data::Forum *forum() const;
|
[[nodiscard]] Data::Forum *forum() const;
|
||||||
[[nodiscard]] Data::ForumTopic *forumTopicFor(MsgId rootId) const;
|
[[nodiscard]] Data::ForumTopic *forumTopicFor(MsgId rootId) const;
|
||||||
|
|
||||||
|
[[nodiscard]] Data::SavedMessages *monoforum() const;
|
||||||
|
|
||||||
[[nodiscard]] Data::PeerNotifySettings ¬ify() {
|
[[nodiscard]] Data::PeerNotifySettings ¬ify() {
|
||||||
return _notify;
|
return _notify;
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,6 +269,7 @@ inline auto DefaultRestrictionValue(
|
||||||
| Flag::Left
|
| Flag::Left
|
||||||
| Flag::Forum
|
| Flag::Forum
|
||||||
| Flag::JoinToWrite
|
| Flag::JoinToWrite
|
||||||
|
| Flag::Monoforum
|
||||||
| Flag::HasLink
|
| Flag::HasLink
|
||||||
| Flag::Forbidden
|
| Flag::Forbidden
|
||||||
| Flag::Creator
|
| Flag::Creator
|
||||||
|
@ -292,7 +293,8 @@ inline auto DefaultRestrictionValue(
|
||||||
&& (flags & Flag::Forum);
|
&& (flags & Flag::Forum);
|
||||||
const auto allowed = !(flags & notAmInFlags)
|
const auto allowed = !(flags & notAmInFlags)
|
||||||
|| ((flags & Flag::HasLink)
|
|| ((flags & Flag::HasLink)
|
||||||
&& !(flags & Flag::JoinToWrite));
|
&& !(flags & Flag::JoinToWrite))
|
||||||
|
|| (flags & Flag::Monoforum);
|
||||||
const auto restricted = sendRestriction
|
const auto restricted = sendRestriction
|
||||||
| (defaultSendRestriction && !unrestrictedByBoosts);
|
| (defaultSendRestriction && !unrestrictedByBoosts);
|
||||||
return allowed
|
return allowed
|
||||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_saved_messages.h"
|
#include "data/data_saved_messages.h"
|
||||||
|
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
|
#include "data/data_channel.h"
|
||||||
#include "data/data_peer.h"
|
#include "data/data_peer.h"
|
||||||
#include "data/data_saved_sublist.h"
|
#include "data/data_saved_sublist.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
|
@ -25,12 +26,15 @@ constexpr auto kListFirstPerPage = 20;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
SavedMessages::SavedMessages(not_null<Session*> owner)
|
SavedMessages::SavedMessages(
|
||||||
|
not_null<Session*> owner,
|
||||||
|
ChannelData *parentChat)
|
||||||
: _owner(owner)
|
: _owner(owner)
|
||||||
|
, _parentChat(parentChat)
|
||||||
, _chatsList(
|
, _chatsList(
|
||||||
&owner->session(),
|
&_owner->session(),
|
||||||
FilterId(),
|
FilterId(),
|
||||||
owner->maxPinnedChatsLimitValue(this))
|
_owner->maxPinnedChatsLimitValue(this))
|
||||||
, _loadMore([=] { sendLoadMoreRequests(); }) {
|
, _loadMore([=] { sendLoadMoreRequests(); }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +44,10 @@ bool SavedMessages::supported() const {
|
||||||
return !_unsupported;
|
return !_unsupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChannelData *SavedMessages::parentChat() const {
|
||||||
|
return _parentChat;
|
||||||
|
}
|
||||||
|
|
||||||
Session &SavedMessages::owner() const {
|
Session &SavedMessages::owner() const {
|
||||||
return *_owner;
|
return *_owner;
|
||||||
}
|
}
|
||||||
|
@ -59,7 +67,11 @@ not_null<SavedSublist*> SavedMessages::sublist(not_null<PeerData*> peer) {
|
||||||
}
|
}
|
||||||
return _sublists.emplace(
|
return _sublists.emplace(
|
||||||
peer,
|
peer,
|
||||||
std::make_unique<SavedSublist>(peer)).first->second.get();
|
std::make_unique<SavedSublist>(this, peer)).first->second.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<> SavedMessages::chatsListChanges() const {
|
||||||
|
return _chatsListChanges.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SavedMessages::loadMore() {
|
void SavedMessages::loadMore() {
|
||||||
|
@ -78,10 +90,12 @@ void SavedMessages::sendLoadMore() {
|
||||||
} else if (!_pinnedLoaded) {
|
} else if (!_pinnedLoaded) {
|
||||||
loadPinned();
|
loadPinned();
|
||||||
}
|
}
|
||||||
|
using Flag = MTPmessages_GetSavedDialogs::Flag;
|
||||||
_loadMoreRequestId = _owner->session().api().request(
|
_loadMoreRequestId = _owner->session().api().request(
|
||||||
MTPmessages_GetSavedDialogs(
|
MTPmessages_GetSavedDialogs(
|
||||||
MTP_flags(MTPmessages_GetSavedDialogs::Flag::f_exclude_pinned),
|
MTP_flags(Flag::f_exclude_pinned
|
||||||
MTPInputPeer(), // parent_peer
|
| (_parentChat ? Flag::f_parent_peer : Flag(0))),
|
||||||
|
_parentChat ? _parentChat->input : MTPInputPeer(),
|
||||||
MTP_int(_offsetDate),
|
MTP_int(_offsetDate),
|
||||||
MTP_int(_offsetId),
|
MTP_int(_offsetId),
|
||||||
_offsetPeer ? _offsetPeer->input : MTP_inputPeerEmpty(),
|
_offsetPeer ? _offsetPeer->input : MTP_inputPeerEmpty(),
|
||||||
|
@ -89,6 +103,7 @@ void SavedMessages::sendLoadMore() {
|
||||||
MTP_long(0)) // hash
|
MTP_long(0)) // hash
|
||||||
).done([=](const MTPmessages_SavedDialogs &result) {
|
).done([=](const MTPmessages_SavedDialogs &result) {
|
||||||
apply(result, false);
|
apply(result, false);
|
||||||
|
_chatsListChanges.fire({});
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
if (error.type() == u"SAVED_DIALOGS_UNSUPPORTED"_q) {
|
if (error.type() == u"SAVED_DIALOGS_UNSUPPORTED"_q) {
|
||||||
_unsupported = true;
|
_unsupported = true;
|
||||||
|
@ -99,13 +114,14 @@ void SavedMessages::sendLoadMore() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SavedMessages::loadPinned() {
|
void SavedMessages::loadPinned() {
|
||||||
if (_pinnedRequestId) {
|
if (_pinnedRequestId || parentChat()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_pinnedRequestId = _owner->session().api().request(
|
_pinnedRequestId = _owner->session().api().request(
|
||||||
MTPmessages_GetPinnedSavedDialogs()
|
MTPmessages_GetPinnedSavedDialogs()
|
||||||
).done([=](const MTPmessages_SavedDialogs &result) {
|
).done([=](const MTPmessages_SavedDialogs &result) {
|
||||||
apply(result, true);
|
apply(result, true);
|
||||||
|
_chatsListChanges.fire({});
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
if (error.type() == u"SAVED_DIALOGS_UNSUPPORTED"_q) {
|
if (error.type() == u"SAVED_DIALOGS_UNSUPPORTED"_q) {
|
||||||
_unsupported = true;
|
_unsupported = true;
|
||||||
|
@ -124,10 +140,11 @@ void SavedMessages::sendLoadMore(not_null<SavedSublist*> sublist) {
|
||||||
const auto offsetId = list.empty() ? MsgId(0) : list.back()->id;
|
const auto offsetId = list.empty() ? MsgId(0) : list.back()->id;
|
||||||
const auto offsetDate = list.empty() ? MsgId(0) : list.back()->date();
|
const auto offsetDate = list.empty() ? MsgId(0) : list.back()->date();
|
||||||
const auto limit = offsetId ? kPerPage : kFirstPerPage;
|
const auto limit = offsetId ? kPerPage : kFirstPerPage;
|
||||||
|
using Flag = MTPmessages_GetSavedHistory::Flag;
|
||||||
const auto requestId = _owner->session().api().request(
|
const auto requestId = _owner->session().api().request(
|
||||||
MTPmessages_GetSavedHistory(
|
MTPmessages_GetSavedHistory(
|
||||||
MTP_flags(0),
|
MTP_flags(_parentChat ? Flag::f_parent_peer : Flag(0)),
|
||||||
MTPInputPeer(), // parent_peer
|
_parentChat ? _parentChat->input : MTPInputPeer(),
|
||||||
sublist->peer()->input,
|
sublist->peer()->input,
|
||||||
MTP_int(offsetId),
|
MTP_int(offsetId),
|
||||||
MTP_int(offsetDate),
|
MTP_int(offsetDate),
|
||||||
|
@ -261,6 +278,8 @@ void SavedMessages::sendLoadMoreRequests() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SavedMessages::apply(const MTPDupdatePinnedSavedDialogs &update) {
|
void SavedMessages::apply(const MTPDupdatePinnedSavedDialogs &update) {
|
||||||
|
Expects(!parentChat());
|
||||||
|
|
||||||
const auto list = update.vorder();
|
const auto list = update.vorder();
|
||||||
if (!list) {
|
if (!list) {
|
||||||
loadPinned();
|
loadPinned();
|
||||||
|
@ -286,6 +305,8 @@ void SavedMessages::apply(const MTPDupdatePinnedSavedDialogs &update) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SavedMessages::apply(const MTPDupdateSavedDialogPinned &update) {
|
void SavedMessages::apply(const MTPDupdateSavedDialogPinned &update) {
|
||||||
|
Expects(!parentChat());
|
||||||
|
|
||||||
update.vpeer().match([&](const MTPDdialogPeer &data) {
|
update.vpeer().match([&](const MTPDdialogPeer &data) {
|
||||||
const auto peer = _owner->peer(peerFromMTP(data.vpeer()));
|
const auto peer = _owner->peer(peerFromMTP(data.vpeer()));
|
||||||
const auto i = _sublists.find(peer);
|
const auto i = _sublists.find(peer);
|
||||||
|
@ -300,4 +321,8 @@ void SavedMessages::apply(const MTPDupdateSavedDialogPinned &update) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpl::lifetime &SavedMessages::lifetime() {
|
||||||
|
return _lifetime;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
|
@ -20,10 +20,13 @@ class SavedSublist;
|
||||||
|
|
||||||
class SavedMessages final {
|
class SavedMessages final {
|
||||||
public:
|
public:
|
||||||
explicit SavedMessages(not_null<Session*> owner);
|
explicit SavedMessages(
|
||||||
|
not_null<Session*> owner,
|
||||||
|
ChannelData *parentChat = nullptr);
|
||||||
~SavedMessages();
|
~SavedMessages();
|
||||||
|
|
||||||
[[nodiscard]] bool supported() const;
|
[[nodiscard]] bool supported() const;
|
||||||
|
[[nodiscard]] ChannelData *parentChat() const;
|
||||||
|
|
||||||
[[nodiscard]] Session &owner() const;
|
[[nodiscard]] Session &owner() const;
|
||||||
[[nodiscard]] Main::Session &session() const;
|
[[nodiscard]] Main::Session &session() const;
|
||||||
|
@ -31,12 +34,16 @@ public:
|
||||||
[[nodiscard]] not_null<Dialogs::MainList*> chatsList();
|
[[nodiscard]] not_null<Dialogs::MainList*> chatsList();
|
||||||
[[nodiscard]] not_null<SavedSublist*> sublist(not_null<PeerData*> peer);
|
[[nodiscard]] not_null<SavedSublist*> sublist(not_null<PeerData*> peer);
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::producer<> chatsListChanges() const;
|
||||||
|
|
||||||
void loadMore();
|
void loadMore();
|
||||||
void loadMore(not_null<SavedSublist*> sublist);
|
void loadMore(not_null<SavedSublist*> sublist);
|
||||||
|
|
||||||
void apply(const MTPDupdatePinnedSavedDialogs &update);
|
void apply(const MTPDupdatePinnedSavedDialogs &update);
|
||||||
void apply(const MTPDupdateSavedDialogPinned &update);
|
void apply(const MTPDupdateSavedDialogPinned &update);
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::lifetime &lifetime();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loadPinned();
|
void loadPinned();
|
||||||
void apply(const MTPmessages_SavedDialogs &result, bool pinned);
|
void apply(const MTPmessages_SavedDialogs &result, bool pinned);
|
||||||
|
@ -46,6 +53,7 @@ private:
|
||||||
void sendLoadMoreRequests();
|
void sendLoadMoreRequests();
|
||||||
|
|
||||||
const not_null<Session*> _owner;
|
const not_null<Session*> _owner;
|
||||||
|
ChannelData *_parentChat = nullptr;
|
||||||
|
|
||||||
Dialogs::MainList _chatsList;
|
Dialogs::MainList _chatsList;
|
||||||
base::flat_map<
|
base::flat_map<
|
||||||
|
@ -64,9 +72,13 @@ private:
|
||||||
base::flat_set<not_null<SavedSublist*>> _loadMoreSublistsScheduled;
|
base::flat_set<not_null<SavedSublist*>> _loadMoreSublistsScheduled;
|
||||||
bool _loadMoreScheduled = false;
|
bool _loadMoreScheduled = false;
|
||||||
|
|
||||||
|
rpl::event_stream<> _chatsListChanges;
|
||||||
|
|
||||||
bool _pinnedLoaded = false;
|
bool _pinnedLoaded = false;
|
||||||
bool _unsupported = false;
|
bool _unsupported = false;
|
||||||
|
|
||||||
|
rpl::lifetime _lifetime;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
|
@ -17,13 +17,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
SavedSublist::SavedSublist(not_null<PeerData*> peer)
|
SavedSublist::SavedSublist(
|
||||||
|
not_null<SavedMessages*> parent,
|
||||||
|
not_null<PeerData*> peer)
|
||||||
: Entry(&peer->owner(), Dialogs::Entry::Type::SavedSublist)
|
: Entry(&peer->owner(), Dialogs::Entry::Type::SavedSublist)
|
||||||
|
, _parent(parent)
|
||||||
, _history(peer->owner().history(peer)) {
|
, _history(peer->owner().history(peer)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SavedSublist::~SavedSublist() = default;
|
SavedSublist::~SavedSublist() = default;
|
||||||
|
|
||||||
|
not_null<SavedMessages*> SavedSublist::parent() const {
|
||||||
|
return _parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelData *SavedSublist::parentChat() const {
|
||||||
|
return _parent->parentChat();
|
||||||
|
}
|
||||||
|
|
||||||
not_null<History*> SavedSublist::history() const {
|
not_null<History*> SavedSublist::history() const {
|
||||||
return _history;
|
return _history;
|
||||||
}
|
}
|
||||||
|
@ -101,9 +112,7 @@ void SavedSublist::removeOne(not_null<HistoryItem*> item) {
|
||||||
updateChatListExistence();
|
updateChatListExistence();
|
||||||
} else {
|
} else {
|
||||||
updateChatListEntry();
|
updateChatListEntry();
|
||||||
crl::on_main(this, [=] {
|
crl::on_main(this, [=] { _parent->loadMore(this); });
|
||||||
owner().savedMessages().loadMore(this);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setChatListTimeId(_items.front()->date());
|
setChatListTimeId(_items.front()->date());
|
||||||
|
|
|
@ -16,12 +16,15 @@ class History;
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
class Session;
|
class Session;
|
||||||
|
class SavedMessages;
|
||||||
|
|
||||||
class SavedSublist final : public Dialogs::Entry {
|
class SavedSublist final : public Dialogs::Entry {
|
||||||
public:
|
public:
|
||||||
explicit SavedSublist(not_null<PeerData*> peer);
|
SavedSublist(not_null<SavedMessages*> parent,not_null<PeerData*> peer);
|
||||||
~SavedSublist();
|
~SavedSublist();
|
||||||
|
|
||||||
|
[[nodiscard]] not_null<SavedMessages*> parent() const;
|
||||||
|
[[nodiscard]] ChannelData *parentChat() const;
|
||||||
[[nodiscard]] not_null<History*> history() const;
|
[[nodiscard]] not_null<History*> history() const;
|
||||||
[[nodiscard]] not_null<PeerData*> peer() const;
|
[[nodiscard]] not_null<PeerData*> peer() const;
|
||||||
[[nodiscard]] bool isHiddenAuthor() const;
|
[[nodiscard]] bool isHiddenAuthor() const;
|
||||||
|
@ -72,6 +75,7 @@ private:
|
||||||
void allowChatListMessageResolve();
|
void allowChatListMessageResolve();
|
||||||
void resolveChatListMessageGroup();
|
void resolveChatListMessageGroup();
|
||||||
|
|
||||||
|
const not_null<SavedMessages*> _parent;
|
||||||
const not_null<History*> _history;
|
const not_null<History*> _history;
|
||||||
|
|
||||||
std::vector<not_null<HistoryItem*>> _items;
|
std::vector<not_null<HistoryItem*>> _items;
|
||||||
|
|
|
@ -967,7 +967,8 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
||||||
| ((!minimal && !data.is_stories_hidden_min())
|
| ((!minimal && !data.is_stories_hidden_min())
|
||||||
? Flag::StoriesHidden
|
? Flag::StoriesHidden
|
||||||
: Flag())
|
: Flag())
|
||||||
| Flag::AutoTranslation;
|
| Flag::AutoTranslation
|
||||||
|
| Flag::Monoforum;
|
||||||
const auto storiesState = minimal
|
const auto storiesState = minimal
|
||||||
? std::optional<Data::Stories::PeerSourceState>()
|
? std::optional<Data::Stories::PeerSourceState>()
|
||||||
: data.is_stories_unavailable()
|
: data.is_stories_unavailable()
|
||||||
|
@ -1007,7 +1008,8 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
||||||
&& data.is_stories_hidden())
|
&& data.is_stories_hidden())
|
||||||
? Flag::StoriesHidden
|
? Flag::StoriesHidden
|
||||||
: Flag())
|
: Flag())
|
||||||
| (data.is_autotranslation() ? Flag::AutoTranslation : Flag());
|
| (data.is_autotranslation() ? Flag::AutoTranslation : Flag())
|
||||||
|
| (data.is_monoforum() ? Flag::Monoforum : Flag());
|
||||||
channel->setFlags((channel->flags() & ~flagsMask) | flagsSet);
|
channel->setFlags((channel->flags() & ~flagsMask) | flagsSet);
|
||||||
channel->setBotVerifyDetailsIcon(
|
channel->setBotVerifyDetailsIcon(
|
||||||
data.vbot_verification_icon().value_or_empty());
|
data.vbot_verification_icon().value_or_empty());
|
||||||
|
@ -2310,6 +2312,9 @@ void Session::applyDialog(
|
||||||
|
|
||||||
bool Session::pinnedCanPin(not_null<Dialogs::Entry*> entry) const {
|
bool Session::pinnedCanPin(not_null<Dialogs::Entry*> entry) const {
|
||||||
if ([[maybe_unused]] const auto sublist = entry->asSublist()) {
|
if ([[maybe_unused]] const auto sublist = entry->asSublist()) {
|
||||||
|
if (sublist->parentChat()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const auto saved = &savedMessages();
|
const auto saved = &savedMessages();
|
||||||
return pinnedChatsOrder(saved).size() < pinnedChatsLimit(saved);
|
return pinnedChatsOrder(saved).size() < pinnedChatsLimit(saved);
|
||||||
} else if (const auto topic = entry->asTopic()) {
|
} else if (const auto topic = entry->asTopic()) {
|
||||||
|
@ -2351,6 +2356,9 @@ int Session::pinnedChatsLimit(not_null<Data::Forum*> forum) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
int Session::pinnedChatsLimit(not_null<Data::SavedMessages*> saved) const {
|
int Session::pinnedChatsLimit(not_null<Data::SavedMessages*> saved) const {
|
||||||
|
if (saved->parentChat()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
const auto limits = Data::PremiumLimits(_session);
|
const auto limits = Data::PremiumLimits(_session);
|
||||||
return limits.savedSublistsPinnedCurrent();
|
return limits.savedSublistsPinnedCurrent();
|
||||||
}
|
}
|
||||||
|
@ -2391,6 +2399,9 @@ rpl::producer<int> Session::maxPinnedChatsLimitValue(
|
||||||
|
|
||||||
rpl::producer<int> Session::maxPinnedChatsLimitValue(
|
rpl::producer<int> Session::maxPinnedChatsLimitValue(
|
||||||
not_null<SavedMessages*> saved) const {
|
not_null<SavedMessages*> saved) const {
|
||||||
|
if (saved->parentChat()) {
|
||||||
|
return rpl::single(0);
|
||||||
|
}
|
||||||
// Premium limit from appconfig.
|
// Premium limit from appconfig.
|
||||||
// We always use premium limit in the MainList limit producer,
|
// We always use premium limit in the MainList limit producer,
|
||||||
// because it slices the list to that limit. We don't want to slice
|
// because it slices the list to that limit. We don't want to slice
|
||||||
|
@ -4563,12 +4574,12 @@ not_null<Folder*> Session::processFolder(const MTPDfolder &data) {
|
||||||
|
|
||||||
not_null<Dialogs::MainList*> Session::chatsListFor(
|
not_null<Dialogs::MainList*> Session::chatsListFor(
|
||||||
not_null<Dialogs::Entry*> entry) {
|
not_null<Dialogs::Entry*> entry) {
|
||||||
const auto topic = entry->asTopic();
|
if (const auto topic = entry->asTopic()) {
|
||||||
return topic
|
return topic->forum()->topicsList();
|
||||||
? topic->forum()->topicsList()
|
} else if (const auto sublist = entry->asSublist()) {
|
||||||
: entry->asSublist()
|
return sublist->parent()->chatsList();
|
||||||
? _savedMessages->chatsList()
|
}
|
||||||
: chatsList(entry->folder());
|
return chatsList(entry->folder());
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<Dialogs::MainList*> Session::chatsList(Data::Folder *folder) {
|
not_null<Dialogs::MainList*> Session::chatsList(Data::Folder *folder) {
|
||||||
|
|
|
@ -781,11 +781,14 @@ void InnerWidget::changeOpenedForum(Data::Forum *forum) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::showSavedSublists() {
|
void InnerWidget::showSavedSublists(ChannelData *parentChat) {
|
||||||
|
Expects(!parentChat || parentChat->monoforum());
|
||||||
Expects(!_geometryInited);
|
Expects(!_geometryInited);
|
||||||
Expects(!_savedSublists);
|
Expects(!_savedSublists);
|
||||||
|
|
||||||
_savedSublists = true;
|
_savedSublists = parentChat
|
||||||
|
? parentChat->monoforum()
|
||||||
|
: &session().data().savedMessages();
|
||||||
|
|
||||||
stopReorderPinned();
|
stopReorderPinned();
|
||||||
clearSelection();
|
clearSelection();
|
||||||
|
@ -2115,7 +2118,7 @@ bool InnerWidget::addQuickActionRipple(
|
||||||
const std::vector<Key> &InnerWidget::pinnedChatsOrder() const {
|
const std::vector<Key> &InnerWidget::pinnedChatsOrder() const {
|
||||||
const auto owner = &session().data();
|
const auto owner = &session().data();
|
||||||
return _savedSublists
|
return _savedSublists
|
||||||
? owner->pinnedChatsOrder(&owner->savedMessages())
|
? owner->pinnedChatsOrder(_savedSublists)
|
||||||
: _openedForum
|
: _openedForum
|
||||||
? owner->pinnedChatsOrder(_openedForum)
|
? owner->pinnedChatsOrder(_openedForum)
|
||||||
: _filterId
|
: _filterId
|
||||||
|
@ -2179,6 +2182,9 @@ int InnerWidget::countPinnedIndex(Row *ofRow) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::savePinnedOrder() {
|
void InnerWidget::savePinnedOrder() {
|
||||||
|
if (_savedSublists && _savedSublists->parentChat()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const auto &newOrder = pinnedChatsOrder();
|
const auto &newOrder = pinnedChatsOrder();
|
||||||
if (newOrder.size() != _pinnedOnDragStart.size()) {
|
if (newOrder.size() != _pinnedOnDragStart.size()) {
|
||||||
return; // Something has changed in the set of pinned chats.
|
return; // Something has changed in the set of pinned chats.
|
||||||
|
@ -2316,8 +2322,11 @@ bool InnerWidget::updateReorderPinned(QPoint localPosition) {
|
||||||
const auto delta = [&] {
|
const auto delta = [&] {
|
||||||
if (localPosition.y() < _visibleTop) {
|
if (localPosition.y() < _visibleTop) {
|
||||||
return localPosition.y() - _visibleTop;
|
return localPosition.y() - _visibleTop;
|
||||||
} else if ((_savedSublists || _openedFolder || _openedForum || _filterId)
|
} else if ((localPosition.y() > _visibleBottom)
|
||||||
&& localPosition.y() > _visibleBottom) {
|
&& (_savedSublists
|
||||||
|
|| _openedFolder
|
||||||
|
|| _openedForum
|
||||||
|
|| _filterId)) {
|
||||||
return localPosition.y() - _visibleBottom;
|
return localPosition.y() - _visibleBottom;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2685,8 +2694,8 @@ void InnerWidget::handleChatListEntryRefreshes() {
|
||||||
return false;
|
return false;
|
||||||
} else if (const auto topic = event.key.topic()) {
|
} else if (const auto topic = event.key.topic()) {
|
||||||
return (topic->forum() == _openedForum);
|
return (topic->forum() == _openedForum);
|
||||||
} else if (event.key.sublist()) {
|
} else if (const auto sublist = event.key.sublist()) {
|
||||||
return _savedSublists;
|
return sublist->parent() == _savedSublists;
|
||||||
} else {
|
} else {
|
||||||
return !_openedForum;
|
return !_openedForum;
|
||||||
}
|
}
|
||||||
|
@ -2704,7 +2713,7 @@ void InnerWidget::handleChatListEntryRefreshes() {
|
||||||
&& (key.topic()
|
&& (key.topic()
|
||||||
? (key.topic()->forum() == _openedForum)
|
? (key.topic()->forum() == _openedForum)
|
||||||
: key.sublist()
|
: key.sublist()
|
||||||
? _savedSublists
|
? (key.sublist()->parent() == _savedSublists)
|
||||||
: (entry->folder() == _openedFolder))) {
|
: (entry->folder() == _openedFolder))) {
|
||||||
_dialogMoved.fire({ from, to });
|
_dialogMoved.fire({ from, to });
|
||||||
}
|
}
|
||||||
|
@ -2909,7 +2918,8 @@ void InnerWidget::enterEventHook(QEnterEvent *e) {
|
||||||
Row *InnerWidget::shownRowByKey(Key key) {
|
Row *InnerWidget::shownRowByKey(Key key) {
|
||||||
const auto entry = key.entry();
|
const auto entry = key.entry();
|
||||||
if (_savedSublists) {
|
if (_savedSublists) {
|
||||||
if (!entry->asSublist()) {
|
const auto sublist = entry->asSublist();
|
||||||
|
if (!sublist || sublist->parent() != _savedSublists) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
} else if (_openedForum) {
|
} else if (_openedForum) {
|
||||||
|
@ -2978,7 +2988,7 @@ void InnerWidget::updateSelectedRow(Key key) {
|
||||||
|
|
||||||
void InnerWidget::refreshShownList() {
|
void InnerWidget::refreshShownList() {
|
||||||
const auto list = _savedSublists
|
const auto list = _savedSublists
|
||||||
? session().data().savedMessages().chatsList()->indexed()
|
? _savedSublists->chatsList()->indexed()
|
||||||
: _openedForum
|
: _openedForum
|
||||||
? _openedForum->topicsList()->indexed()
|
? _openedForum->topicsList()->indexed()
|
||||||
: _filterId
|
: _filterId
|
||||||
|
@ -3440,8 +3450,7 @@ void InnerWidget::applySearchState(SearchState state) {
|
||||||
};
|
};
|
||||||
if (_searchState.filterChatsList() && !words.isEmpty()) {
|
if (_searchState.filterChatsList() && !words.isEmpty()) {
|
||||||
if (_savedSublists) {
|
if (_savedSublists) {
|
||||||
const auto owner = &session().data();
|
append(_savedSublists->chatsList()->indexed());
|
||||||
append(owner->savedMessages().chatsList()->indexed());
|
|
||||||
} else if (_openedForum) {
|
} else if (_openedForum) {
|
||||||
append(_openedForum->topicsList()->indexed());
|
append(_openedForum->topicsList()->indexed());
|
||||||
} else {
|
} else {
|
||||||
|
@ -4012,7 +4021,7 @@ void InnerWidget::refreshEmpty() {
|
||||||
const auto state = !_shownList->empty()
|
const auto state = !_shownList->empty()
|
||||||
? EmptyState::None
|
? EmptyState::None
|
||||||
: _savedSublists
|
: _savedSublists
|
||||||
? (data->savedMessages().chatsList()->loaded()
|
? (_savedSublists->chatsList()->loaded()
|
||||||
? EmptyState::EmptySavedSublists
|
? EmptyState::EmptySavedSublists
|
||||||
: EmptyState::Loading)
|
: EmptyState::Loading)
|
||||||
: _openedForum
|
: _openedForum
|
||||||
|
|
|
@ -58,6 +58,7 @@ class ChatFilter;
|
||||||
class Thread;
|
class Thread;
|
||||||
class Folder;
|
class Folder;
|
||||||
class Forum;
|
class Forum;
|
||||||
|
class SavedMessages;
|
||||||
struct ReactionId;
|
struct ReactionId;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
|
@ -140,7 +141,7 @@ public:
|
||||||
|
|
||||||
void changeOpenedFolder(Data::Folder *folder);
|
void changeOpenedFolder(Data::Folder *folder);
|
||||||
void changeOpenedForum(Data::Forum *forum);
|
void changeOpenedForum(Data::Forum *forum);
|
||||||
void showSavedSublists();
|
void showSavedSublists(ChannelData *parentChat);
|
||||||
void selectSkip(int32 direction);
|
void selectSkip(int32 direction);
|
||||||
void selectSkipPage(int32 pixels, int32 direction);
|
void selectSkipPage(int32 pixels, int32 direction);
|
||||||
|
|
||||||
|
@ -668,7 +669,8 @@ private:
|
||||||
float64 _narrowRatio = 0.;
|
float64 _narrowRatio = 0.;
|
||||||
bool _geometryInited = false;
|
bool _geometryInited = false;
|
||||||
|
|
||||||
bool _savedSublists = false;
|
Data::SavedMessages *_savedSublists = nullptr;
|
||||||
|
|
||||||
bool _searchLoading = false;
|
bool _searchLoading = false;
|
||||||
bool _searchWaiting = false;
|
bool _searchWaiting = false;
|
||||||
|
|
||||||
|
|
|
@ -1712,6 +1712,7 @@ ServiceAction ParseServiceAction(
|
||||||
}, [&](const MTPDmessageActionPaidMessagesPrice &data) {
|
}, [&](const MTPDmessageActionPaidMessagesPrice &data) {
|
||||||
result.content = ActionPaidMessagesPrice{
|
result.content = ActionPaidMessagesPrice{
|
||||||
.stars = int(data.vstars().v),
|
.stars = int(data.vstars().v),
|
||||||
|
.broadcastAllowed = data.is_broadcast_messages_allowed(),
|
||||||
};
|
};
|
||||||
}, [&](const MTPDmessageActionConferenceCall &data) {
|
}, [&](const MTPDmessageActionConferenceCall &data) {
|
||||||
auto content = ActionPhoneCall();
|
auto content = ActionPhoneCall();
|
||||||
|
|
|
@ -673,6 +673,7 @@ struct ActionPaidMessagesRefunded {
|
||||||
|
|
||||||
struct ActionPaidMessagesPrice {
|
struct ActionPaidMessagesPrice {
|
||||||
int stars = 0;
|
int stars = 0;
|
||||||
|
bool broadcastAllowed = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ServiceAction {
|
struct ServiceAction {
|
||||||
|
|
|
@ -1383,7 +1383,15 @@ auto HtmlWriter::Wrap::pushMessage(
|
||||||
+ " messages to you");
|
+ " messages to you");
|
||||||
return result;
|
return result;
|
||||||
}, [&](const ActionPaidMessagesPrice &data) {
|
}, [&](const ActionPaidMessagesPrice &data) {
|
||||||
auto result = "Price per messages changed to "
|
if (isChannel) {
|
||||||
|
auto result = !data.broadcastAllowed
|
||||||
|
? "Direct messages were disabled."
|
||||||
|
: ("Price per direct message changed to "
|
||||||
|
+ QString::number(data.stars).toUtf8()
|
||||||
|
+ " Telegram Stars.");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
auto result = "Price per message changed to "
|
||||||
+ QString::number(data.stars).toUtf8()
|
+ QString::number(data.stars).toUtf8()
|
||||||
+ " Telegram Stars.";
|
+ " Telegram Stars.";
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -679,6 +679,7 @@ QByteArray SerializeMessage(
|
||||||
pushActor();
|
pushActor();
|
||||||
pushAction("paid_messages_price_change");
|
pushAction("paid_messages_price_change");
|
||||||
push("price_stars", data.stars);
|
push("price_stars", data.stars);
|
||||||
|
push("is_broadcast_messages_allowed", data.broadcastAllowed);
|
||||||
}, [](v::null_t) {});
|
}, [](v::null_t) {});
|
||||||
|
|
||||||
if (v::is_null(message.action.content)) {
|
if (v::is_null(message.action.content)) {
|
||||||
|
|
|
@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/notify/data_notify_settings.h"
|
#include "data/notify/data_notify_settings.h"
|
||||||
#include "data/stickers/data_stickers.h"
|
#include "data/stickers/data_stickers.h"
|
||||||
#include "data/data_drafts.h"
|
#include "data/data_drafts.h"
|
||||||
|
#include "data/data_saved_messages.h"
|
||||||
#include "data/data_saved_sublist.h"
|
#include "data/data_saved_sublist.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_media_types.h"
|
#include "data/data_media_types.h"
|
||||||
|
@ -3131,6 +3132,42 @@ bool History::isForum() const {
|
||||||
return (_flags & Flag::IsForum);
|
return (_flags & Flag::IsForum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void History::monoforumChanged(Data::SavedMessages *old) {
|
||||||
|
if (inChatList()) {
|
||||||
|
notifyUnreadStateChange(old
|
||||||
|
? AdjustedForumUnreadState(old->chatsList()->unreadState())
|
||||||
|
: computeUnreadState());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto monoforum = peer->monoforum()) {
|
||||||
|
_flags |= Flag::IsMonoforum;
|
||||||
|
|
||||||
|
monoforum->chatsList()->unreadStateChanges(
|
||||||
|
) | rpl::filter([=] {
|
||||||
|
return (_flags & Flag::IsMonoforum) && inChatList();
|
||||||
|
}) | rpl::map(
|
||||||
|
AdjustedForumUnreadState
|
||||||
|
) | rpl::start_with_next([=](const Dialogs::UnreadState &old) {
|
||||||
|
notifyUnreadStateChange(old);
|
||||||
|
}, monoforum->lifetime());
|
||||||
|
|
||||||
|
monoforum->chatsListChanges(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
updateChatListEntry();
|
||||||
|
}, monoforum->lifetime());
|
||||||
|
} else {
|
||||||
|
_flags &= ~Flag::IsMonoforum;
|
||||||
|
}
|
||||||
|
if (cloudDraft(MsgId(0))) {
|
||||||
|
updateChatListSortPosition();
|
||||||
|
}
|
||||||
|
_flags |= Flag::PendingAllItemsResize;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool History::isMonoforum() const {
|
||||||
|
return (_flags & Flag::IsMonoforum);
|
||||||
|
}
|
||||||
|
|
||||||
not_null<History*> History::migrateToOrMe() const {
|
not_null<History*> History::migrateToOrMe() const {
|
||||||
if (const auto to = peer->migrateTo()) {
|
if (const auto to = peer->migrateTo()) {
|
||||||
return owner().history(to);
|
return owner().history(to);
|
||||||
|
|
|
@ -27,12 +27,14 @@ struct LanguageId;
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
struct Draft;
|
struct Draft;
|
||||||
|
class Forum;
|
||||||
class Session;
|
class Session;
|
||||||
class Folder;
|
class Folder;
|
||||||
class ChatFilter;
|
class ChatFilter;
|
||||||
struct SponsoredFrom;
|
struct SponsoredFrom;
|
||||||
class SponsoredMessages;
|
class SponsoredMessages;
|
||||||
class HistoryMessages;
|
class HistoryMessages;
|
||||||
|
class SavedMessages;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
namespace Dialogs {
|
namespace Dialogs {
|
||||||
|
@ -71,6 +73,9 @@ public:
|
||||||
void forumChanged(Data::Forum *old);
|
void forumChanged(Data::Forum *old);
|
||||||
[[nodiscard]] bool isForum() const;
|
[[nodiscard]] bool isForum() const;
|
||||||
|
|
||||||
|
void monoforumChanged(Data::SavedMessages *old);
|
||||||
|
[[nodiscard]] bool isMonoforum() const;
|
||||||
|
|
||||||
[[nodiscard]] not_null<History*> migrateToOrMe() const;
|
[[nodiscard]] not_null<History*> migrateToOrMe() const;
|
||||||
[[nodiscard]] History *migrateFrom() const;
|
[[nodiscard]] History *migrateFrom() const;
|
||||||
[[nodiscard]] MsgRange rangeForDifferenceRequest() const;
|
[[nodiscard]] MsgRange rangeForDifferenceRequest() const;
|
||||||
|
@ -430,9 +435,10 @@ private:
|
||||||
PendingAllItemsResize = (1 << 1),
|
PendingAllItemsResize = (1 << 1),
|
||||||
IsTopPromoted = (1 << 2),
|
IsTopPromoted = (1 << 2),
|
||||||
IsForum = (1 << 3),
|
IsForum = (1 << 3),
|
||||||
FakeUnreadWhileOpened = (1 << 4),
|
IsMonoforum = (1 << 4),
|
||||||
HasPinnedMessages = (1 << 5),
|
FakeUnreadWhileOpened = (1 << 5),
|
||||||
ResolveChatListMessage = (1 << 6),
|
HasPinnedMessages = (1 << 6),
|
||||||
|
ResolveChatListMessage = (1 << 7),
|
||||||
};
|
};
|
||||||
using Flags = base::flags<Flag>;
|
using Flags = base::flags<Flag>;
|
||||||
friend inline constexpr auto is_flag_type(Flag) {
|
friend inline constexpr auto is_flag_type(Flag) {
|
||||||
|
|
|
@ -3563,6 +3563,12 @@ Data::SavedSublist *HistoryItem::savedSublist() const {
|
||||||
that->AddComponents(HistoryMessageSaved::Bit());
|
that->AddComponents(HistoryMessageSaved::Bit());
|
||||||
that->Get<HistoryMessageSaved>()->sublist = sublist;
|
that->Get<HistoryMessageSaved>()->sublist = sublist;
|
||||||
return sublist;
|
return sublist;
|
||||||
|
} else if (const auto monoforum = _history->peer->monoforum()) {
|
||||||
|
const auto sublist = monoforum->sublist(_history->peer);
|
||||||
|
const auto that = const_cast<HistoryItem*>(this);
|
||||||
|
that->AddComponents(HistoryMessageSaved::Bit());
|
||||||
|
that->Get<HistoryMessageSaved>()->sublist = sublist;
|
||||||
|
return sublist;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -3785,7 +3791,9 @@ void HistoryItem::createComponents(CreateConfig &&config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto peer = _history->owner().peer(config.savedSublistPeer);
|
const auto peer = _history->owner().peer(config.savedSublistPeer);
|
||||||
saved->sublist = _history->owner().savedMessages().sublist(peer);
|
saved->sublist = _history->peer->isSelf()
|
||||||
|
? _history->owner().savedMessages().sublist(peer)
|
||||||
|
: _history->peer->monoforum()->sublist(peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const auto reply = Get<HistoryMessageReply>()) {
|
if (const auto reply = Get<HistoryMessageReply>()) {
|
||||||
|
@ -5744,8 +5752,23 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) {
|
||||||
|
|
||||||
auto preparePaidMessagesPrice = [&](const MTPDmessageActionPaidMessagesPrice &action) {
|
auto preparePaidMessagesPrice = [&](const MTPDmessageActionPaidMessagesPrice &action) {
|
||||||
const auto stars = action.vstars().v;
|
const auto stars = action.vstars().v;
|
||||||
|
const auto broadcastAllowed = action.is_broadcast_messages_allowed();
|
||||||
auto result = PreparedServiceText();
|
auto result = PreparedServiceText();
|
||||||
result.text = stars
|
result.text = _history->peer->isBroadcast()
|
||||||
|
? (stars > 0
|
||||||
|
? tr::lng_action_direct_messages_paid(
|
||||||
|
tr::now,
|
||||||
|
lt_count,
|
||||||
|
stars,
|
||||||
|
Ui::Text::WithEntities)
|
||||||
|
: broadcastAllowed
|
||||||
|
? tr::lng_action_direct_messages_enabled(
|
||||||
|
tr::now,
|
||||||
|
Ui::Text::WithEntities)
|
||||||
|
: tr::lng_action_direct_messages_disabled(
|
||||||
|
tr::now,
|
||||||
|
Ui::Text::WithEntities))
|
||||||
|
: stars
|
||||||
? tr::lng_action_message_price_paid(
|
? tr::lng_action_message_price_paid(
|
||||||
tr::now,
|
tr::now,
|
||||||
lt_count,
|
lt_count,
|
||||||
|
|
|
@ -383,6 +383,7 @@ HistoryWidget::HistoryWidget(
|
||||||
_joinChannel->addClickHandler([=] { joinChannel(); });
|
_joinChannel->addClickHandler([=] { joinChannel(); });
|
||||||
_muteUnmute->addClickHandler([=] { toggleMuteUnmute(); });
|
_muteUnmute->addClickHandler([=] { toggleMuteUnmute(); });
|
||||||
setupGiftToChannelButton();
|
setupGiftToChannelButton();
|
||||||
|
setupDirectMessageButton();
|
||||||
_reportMessages->addClickHandler([=] { reportSelectedMessages(); });
|
_reportMessages->addClickHandler([=] { reportSelectedMessages(); });
|
||||||
_field->submits(
|
_field->submits(
|
||||||
) | rpl::start_with_next([=](Qt::KeyboardModifiers modifiers) {
|
) | rpl::start_with_next([=](Qt::KeyboardModifiers modifiers) {
|
||||||
|
@ -1050,15 +1051,23 @@ void HistoryWidget::refreshJoinChannelText() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::refreshGiftToChannelShown() {
|
void HistoryWidget::refreshGiftToChannelShown() {
|
||||||
if (!_giftToChannelIn || !_giftToChannelOut) {
|
if (!_giftToChannel || !_peer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto channel = _peer->asChannel();
|
const auto channel = _peer->asChannel();
|
||||||
const auto shown = channel
|
_giftToChannel->setVisible(channel
|
||||||
&& channel->isBroadcast()
|
&& channel->isBroadcast()
|
||||||
&& channel->stargiftsAvailable();
|
&& channel->stargiftsAvailable());
|
||||||
_giftToChannelIn->setVisible(shown);
|
}
|
||||||
_giftToChannelOut->setVisible(shown);
|
|
||||||
|
void HistoryWidget::refreshDirectMessageShown() {
|
||||||
|
if (!_directMessage || !_peer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto channel = _peer->asChannel();
|
||||||
|
_directMessage->setVisible(channel
|
||||||
|
&& channel->isBroadcast()
|
||||||
|
&& channel->monoforumLink());
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::refreshTopBarActiveChat() {
|
void HistoryWidget::refreshTopBarActiveChat() {
|
||||||
|
@ -2074,22 +2083,63 @@ void HistoryWidget::setupShortcuts() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::setupGiftToChannelButton() {
|
void HistoryWidget::setupGiftToChannelButton() {
|
||||||
const auto setupButton = [=](not_null<Ui::RpWidget*> parent) {
|
_giftToChannel = Ui::CreateChild<Ui::IconButton>(
|
||||||
auto *button = Ui::CreateChild<Ui::IconButton>(
|
_muteUnmute.data(),
|
||||||
parent.get(),
|
st::historyGiftToChannel);
|
||||||
st::historyGiftToChannel);
|
widthValue() | rpl::start_with_next([=](int width) {
|
||||||
parent->widthValue() | rpl::start_with_next([=](int width) {
|
_giftToChannel->moveToRight(0, 0, width);
|
||||||
button->moveToRight(0, 0);
|
}, _giftToChannel->lifetime());
|
||||||
}, button->lifetime());
|
_giftToChannel->setClickedCallback([=] {
|
||||||
button->setClickedCallback([=] {
|
Ui::ShowStarGiftBox(controller(), _peer);
|
||||||
if (_peer) {
|
});
|
||||||
Ui::ShowStarGiftBox(controller(), _peer);
|
rpl::combine(
|
||||||
|
_muteUnmute->shownValue(),
|
||||||
|
_joinChannel->shownValue()
|
||||||
|
) | rpl::start_with_next([=](bool muteUnmute, bool joinChannel) {
|
||||||
|
const auto newParent = (muteUnmute && !joinChannel)
|
||||||
|
? _muteUnmute.data()
|
||||||
|
: (joinChannel && !muteUnmute)
|
||||||
|
? _joinChannel.data()
|
||||||
|
: nullptr;
|
||||||
|
if (newParent) {
|
||||||
|
_giftToChannel->setParent(newParent);
|
||||||
|
_giftToChannel->moveToRight(0, 0);
|
||||||
|
refreshGiftToChannelShown();
|
||||||
|
}
|
||||||
|
}, _giftToChannel->lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryWidget::setupDirectMessageButton() {
|
||||||
|
_directMessage = Ui::CreateChild<Ui::IconButton>(
|
||||||
|
_muteUnmute.data(),
|
||||||
|
st::historyDirectMessage);
|
||||||
|
widthValue() | rpl::start_with_next([=](int width) {
|
||||||
|
_directMessage->moveToRight(0, 0, width);
|
||||||
|
}, _directMessage->lifetime());
|
||||||
|
_directMessage->setClickedCallback([=] {
|
||||||
|
if (const auto channel = _peer ? _peer->asChannel() : nullptr) {
|
||||||
|
if (const auto monoforum = channel->monoforumLink()) {
|
||||||
|
controller()->showPeerHistory(
|
||||||
|
monoforum,
|
||||||
|
Window::SectionShow::Way::Forward);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
return button;
|
});
|
||||||
};
|
rpl::combine(
|
||||||
_giftToChannelIn = setupButton(_muteUnmute);
|
_muteUnmute->shownValue(),
|
||||||
_giftToChannelOut = setupButton(_joinChannel);
|
_joinChannel->shownValue()
|
||||||
|
) | rpl::start_with_next([=](bool muteUnmute, bool joinChannel) {
|
||||||
|
const auto newParent = (muteUnmute && !joinChannel)
|
||||||
|
? _muteUnmute.data()
|
||||||
|
: (joinChannel && !muteUnmute)
|
||||||
|
? _joinChannel.data()
|
||||||
|
: nullptr;
|
||||||
|
if (newParent) {
|
||||||
|
_directMessage->setParent(newParent);
|
||||||
|
_directMessage->moveToLeft(0, 0);
|
||||||
|
refreshDirectMessageShown();
|
||||||
|
}
|
||||||
|
}, _directMessage->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::pushReplyReturn(not_null<HistoryItem*> item) {
|
void HistoryWidget::pushReplyReturn(not_null<HistoryItem*> item) {
|
||||||
|
@ -2456,6 +2506,7 @@ void HistoryWidget::showHistory(
|
||||||
}, _contactStatus->bar().lifetime());
|
}, _contactStatus->bar().lifetime());
|
||||||
|
|
||||||
refreshGiftToChannelShown();
|
refreshGiftToChannelShown();
|
||||||
|
refreshDirectMessageShown();
|
||||||
if (const auto user = _peer->asUser()) {
|
if (const auto user = _peer->asUser()) {
|
||||||
_paysStatus = std::make_unique<PaysStatus>(
|
_paysStatus = std::make_unique<PaysStatus>(
|
||||||
controller(),
|
controller(),
|
||||||
|
@ -5220,7 +5271,10 @@ bool HistoryWidget::isBlocked() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HistoryWidget::isJoinChannel() const {
|
bool HistoryWidget::isJoinChannel() const {
|
||||||
return _peer && _peer->isChannel() && !_peer->asChannel()->amIn();
|
if (const auto channel = _peer ? _peer->asChannel() : nullptr) {
|
||||||
|
return !channel->amIn() && !channel->isMonoforum();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HistoryWidget::isChoosingTheme() const {
|
bool HistoryWidget::isChoosingTheme() const {
|
||||||
|
@ -8639,6 +8693,7 @@ void HistoryWidget::fullInfoUpdated() {
|
||||||
sendBotStartCommand();
|
sendBotStartCommand();
|
||||||
}
|
}
|
||||||
refreshGiftToChannelShown();
|
refreshGiftToChannelShown();
|
||||||
|
refreshDirectMessageShown();
|
||||||
}
|
}
|
||||||
if (updateCmdStartShown()) {
|
if (updateCmdStartShown()) {
|
||||||
refresh = true;
|
refresh = true;
|
||||||
|
|
|
@ -406,6 +406,7 @@ private:
|
||||||
|
|
||||||
void refreshJoinChannelText();
|
void refreshJoinChannelText();
|
||||||
void refreshGiftToChannelShown();
|
void refreshGiftToChannelShown();
|
||||||
|
void refreshDirectMessageShown();
|
||||||
void requestMessageData(MsgId msgId);
|
void requestMessageData(MsgId msgId);
|
||||||
void messageDataReceived(not_null<PeerData*> peer, MsgId msgId);
|
void messageDataReceived(not_null<PeerData*> peer, MsgId msgId);
|
||||||
|
|
||||||
|
@ -535,6 +536,7 @@ private:
|
||||||
|
|
||||||
void setupShortcuts();
|
void setupShortcuts();
|
||||||
void setupGiftToChannelButton();
|
void setupGiftToChannelButton();
|
||||||
|
void setupDirectMessageButton();
|
||||||
|
|
||||||
void handlePeerMigration();
|
void handlePeerMigration();
|
||||||
|
|
||||||
|
@ -797,8 +799,8 @@ private:
|
||||||
object_ptr<Ui::FlatButton> _botStart;
|
object_ptr<Ui::FlatButton> _botStart;
|
||||||
object_ptr<Ui::FlatButton> _joinChannel;
|
object_ptr<Ui::FlatButton> _joinChannel;
|
||||||
object_ptr<Ui::FlatButton> _muteUnmute;
|
object_ptr<Ui::FlatButton> _muteUnmute;
|
||||||
QPointer<Ui::IconButton> _giftToChannelIn;
|
QPointer<Ui::IconButton> _giftToChannel;
|
||||||
QPointer<Ui::IconButton> _giftToChannelOut;
|
QPointer<Ui::IconButton> _directMessage;
|
||||||
object_ptr<Ui::FlatButton> _reportMessages;
|
object_ptr<Ui::FlatButton> _reportMessages;
|
||||||
struct {
|
struct {
|
||||||
object_ptr<Ui::RoundButton> button = { nullptr };
|
object_ptr<Ui::RoundButton> button = { nullptr };
|
||||||
|
|
|
@ -606,7 +606,7 @@ rpl::producer<Data::MessagesSlice> SublistWidget::listSource(
|
||||||
? (*result.fullCount - after - useBefore)
|
? (*result.fullCount - after - useBefore)
|
||||||
: std::optional<int>();
|
: std::optional<int>();
|
||||||
if (!result.fullCount || useBefore < limitBefore) {
|
if (!result.fullCount || useBefore < limitBefore) {
|
||||||
_sublist->owner().savedMessages().loadMore(_sublist);
|
_sublist->parent()->loadMore(_sublist);
|
||||||
}
|
}
|
||||||
consumer.put_next(std::move(result));
|
consumer.put_next(std::move(result));
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_stories_ids.h"
|
#include "data/data_stories_ids.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "history/view/history_view_sublist_section.h"
|
#include "history/view/history_view_sublist_section.h"
|
||||||
|
#include "history/history.h"
|
||||||
#include "info/info_controller.h"
|
#include "info/info_controller.h"
|
||||||
#include "info/info_memento.h"
|
#include "info/info_memento.h"
|
||||||
#include "info/profile/info_profile_values.h"
|
#include "info/profile/info_profile_values.h"
|
||||||
|
@ -32,39 +33,34 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace Info::Media {
|
namespace Info::Media {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
[[nodiscard]] Window::SeparateSharedMediaType ToSeparateType(
|
[[nodiscard]] bool SeparateSupported(Storage::SharedMediaType type) {
|
||||||
Storage::SharedMediaType type) {
|
|
||||||
using Type = Storage::SharedMediaType;
|
using Type = Storage::SharedMediaType;
|
||||||
using SeparatedType = Window::SeparateSharedMediaType;
|
|
||||||
return (type == Type::Photo)
|
return (type == Type::Photo)
|
||||||
? SeparatedType::Photos
|
|| (type == Type::Video)
|
||||||
: (type == Type::Video)
|
|| (type == Type::File)
|
||||||
? SeparatedType::Videos
|
|| (type == Type::MusicFile)
|
||||||
: (type == Type::File)
|
|| (type == Type::Link)
|
||||||
? SeparatedType::Files
|
|| (type == Type::RoundVoiceFile)
|
||||||
: (type == Type::MusicFile)
|
|| (type == Type::GIF);
|
||||||
? SeparatedType::Audio
|
|
||||||
: (type == Type::Link)
|
|
||||||
? SeparatedType::Links
|
|
||||||
: (type == Type::RoundVoiceFile)
|
|
||||||
? SeparatedType::Voices
|
|
||||||
: (type == Type::GIF)
|
|
||||||
? SeparatedType::GIF
|
|
||||||
: SeparatedType::None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] Window::SeparateId SeparateId(
|
[[nodiscard]] Window::SeparateId SeparateId(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
MsgId topicRootId,
|
MsgId topicRootId,
|
||||||
Storage::SharedMediaType type) {
|
Storage::SharedMediaType type) {
|
||||||
if (peer->isSelf()) {
|
if (peer->isSelf() || !SeparateSupported(type)) {
|
||||||
return { nullptr };
|
return { nullptr };
|
||||||
}
|
}
|
||||||
const auto separateType = ToSeparateType(type);
|
const auto topic = topicRootId
|
||||||
if (separateType == Window::SeparateSharedMediaType::None) {
|
? peer->forumTopicFor(topicRootId)
|
||||||
|
: nullptr;
|
||||||
|
if (topicRootId && !topic) {
|
||||||
return { nullptr };
|
return { nullptr };
|
||||||
}
|
}
|
||||||
return { Window::SeparateSharedMedia{ separateType, peer, topicRootId } };
|
const auto thread = topic
|
||||||
|
? (Data::Thread*)topic
|
||||||
|
: peer->owner().history(peer);
|
||||||
|
return { thread, type };
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddContextMenuToButton(
|
void AddContextMenuToButton(
|
||||||
|
|
|
@ -40,6 +40,28 @@ Type TabIndexToType(int index) {
|
||||||
Unexpected("Index in Info::Media::TabIndexToType()");
|
Unexpected("Index in Info::Media::TabIndexToType()");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr::phrase<> SharedMediaTitle(Type type) {
|
||||||
|
switch (type) {
|
||||||
|
case Type::Photo:
|
||||||
|
return tr::lng_media_type_photos;
|
||||||
|
case Type::GIF:
|
||||||
|
return tr::lng_media_type_gifs;
|
||||||
|
case Type::Video:
|
||||||
|
return tr::lng_media_type_videos;
|
||||||
|
case Type::MusicFile:
|
||||||
|
return tr::lng_media_type_songs;
|
||||||
|
case Type::File:
|
||||||
|
return tr::lng_media_type_files;
|
||||||
|
case Type::RoundVoiceFile:
|
||||||
|
return tr::lng_media_type_audios;
|
||||||
|
case Type::Link:
|
||||||
|
return tr::lng_media_type_links;
|
||||||
|
case Type::RoundFile:
|
||||||
|
return tr::lng_media_type_rounds;
|
||||||
|
}
|
||||||
|
Unexpected("Bad media type in Info::TitleValue()");
|
||||||
|
}
|
||||||
|
|
||||||
Memento::Memento(not_null<Controller*> controller)
|
Memento::Memento(not_null<Controller*> controller)
|
||||||
: Memento(
|
: Memento(
|
||||||
(controller->peer()
|
(controller->peer()
|
||||||
|
@ -119,25 +141,7 @@ rpl::producer<QString> Widget::title() {
|
||||||
if (controller()->key().peer()->sharedMediaInfo() && isStackBottom()) {
|
if (controller()->key().peer()->sharedMediaInfo() && isStackBottom()) {
|
||||||
return tr::lng_profile_shared_media();
|
return tr::lng_profile_shared_media();
|
||||||
}
|
}
|
||||||
switch (controller()->section().mediaType()) {
|
return SharedMediaTitle(controller()->section().mediaType())();
|
||||||
case Section::MediaType::Photo:
|
|
||||||
return tr::lng_media_type_photos();
|
|
||||||
case Section::MediaType::GIF:
|
|
||||||
return tr::lng_media_type_gifs();
|
|
||||||
case Section::MediaType::Video:
|
|
||||||
return tr::lng_media_type_videos();
|
|
||||||
case Section::MediaType::MusicFile:
|
|
||||||
return tr::lng_media_type_songs();
|
|
||||||
case Section::MediaType::File:
|
|
||||||
return tr::lng_media_type_files();
|
|
||||||
case Section::MediaType::RoundVoiceFile:
|
|
||||||
return tr::lng_media_type_audios();
|
|
||||||
case Section::MediaType::Link:
|
|
||||||
return tr::lng_media_type_links();
|
|
||||||
case Section::MediaType::RoundFile:
|
|
||||||
return tr::lng_media_type_rounds();
|
|
||||||
}
|
|
||||||
Unexpected("Bad media type in Info::TitleValue()");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::setIsStackBottom(bool isStackBottom) {
|
void Widget::setIsStackBottom(bool isStackBottom) {
|
||||||
|
|
|
@ -11,6 +11,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "storage/storage_shared_media.h"
|
#include "storage/storage_shared_media.h"
|
||||||
#include "data/data_search_controller.h"
|
#include "data/data_search_controller.h"
|
||||||
|
|
||||||
|
namespace tr {
|
||||||
|
template <typename ...Tags>
|
||||||
|
struct phrase;
|
||||||
|
} // namespace tr
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
class ForumTopic;
|
class ForumTopic;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
@ -19,8 +24,9 @@ namespace Info::Media {
|
||||||
|
|
||||||
using Type = Storage::SharedMediaType;
|
using Type = Storage::SharedMediaType;
|
||||||
|
|
||||||
std::optional<int> TypeToTabIndex(Type type);
|
[[nodiscard]] std::optional<int> TypeToTabIndex(Type type);
|
||||||
Type TabIndexToType(int index);
|
[[nodiscard]] Type TabIndexToType(int index);
|
||||||
|
[[nodiscard]] tr::phrase<> SharedMediaTitle(Type type);
|
||||||
|
|
||||||
class InnerWidget;
|
class InnerWidget;
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ SublistsWidget::SublistsWidget(
|
||||||
this,
|
this,
|
||||||
controller->parentController(),
|
controller->parentController(),
|
||||||
rpl::single(Dialogs::InnerWidget::ChildListShown())));
|
rpl::single(Dialogs::InnerWidget::ChildListShown())));
|
||||||
_list->showSavedSublists();
|
_list->showSavedSublists(nullptr);
|
||||||
_list->setNarrowRatio(0.);
|
_list->setNarrowRatio(0.);
|
||||||
|
|
||||||
_list->chosenRow() | rpl::start_with_next([=](Dialogs::ChosenRow row) {
|
_list->chosenRow() | rpl::start_with_next([=](Dialogs::ChosenRow row) {
|
||||||
|
|
|
@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/platform/ui_platform_window.h"
|
#include "ui/platform/ui_platform_window.h"
|
||||||
#include "platform/platform_window_title.h"
|
#include "platform/platform_window_title.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
|
#include "info/media/info_media_widget.h" // SharedMediaTitle.
|
||||||
#include "window/window_separate_id.h"
|
#include "window/window_separate_id.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
#include "window/window_lock_widgets.h"
|
#include "window/window_lock_widgets.h"
|
||||||
|
@ -87,42 +88,24 @@ base::options::toggle OptionDisableTouchbar({
|
||||||
.restartRequired = true,
|
.restartRequired = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
[[nodiscard]] QString TitleFromSeparateId(
|
[[nodiscard]] QString TitleFromSeparateSharedMedia(
|
||||||
const Core::WindowTitleContent &settings,
|
const Core::WindowTitleContent &settings,
|
||||||
const SeparateId &id) {
|
const SeparateId &id) {
|
||||||
if (id.sharedMedia == SeparateSharedMediaType::None
|
if (id.type != SeparateType::SharedMedia) {
|
||||||
|| !id.sharedMediaPeer()) {
|
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
const auto result = (id.sharedMedia == SeparateSharedMediaType::Photos)
|
const auto type = id.sharedMediaType;
|
||||||
? tr::lng_media_type_photos(tr::now)
|
const auto result = Info::Media::SharedMediaTitle(type)(tr::now);
|
||||||
: (id.sharedMedia == SeparateSharedMediaType::Videos)
|
|
||||||
? tr::lng_media_type_videos(tr::now)
|
|
||||||
: (id.sharedMedia == SeparateSharedMediaType::Files)
|
|
||||||
? tr::lng_media_type_files(tr::now)
|
|
||||||
: (id.sharedMedia == SeparateSharedMediaType::Audio)
|
|
||||||
? tr::lng_media_type_songs(tr::now)
|
|
||||||
: (id.sharedMedia == SeparateSharedMediaType::Links)
|
|
||||||
? tr::lng_media_type_links(tr::now)
|
|
||||||
: (id.sharedMedia == SeparateSharedMediaType::GIF)
|
|
||||||
? tr::lng_media_type_gifs(tr::now)
|
|
||||||
: (id.sharedMedia == SeparateSharedMediaType::Voices)
|
|
||||||
? tr::lng_media_type_audios(tr::now)
|
|
||||||
: QString();
|
|
||||||
|
|
||||||
if (settings.hideChatName) {
|
if (settings.hideChatName) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
const auto peer = id.sharedMediaPeer();
|
const auto thread = id.thread;
|
||||||
const auto topicRootId = id.sharedMediaTopicRootId();
|
const auto topic = thread->asTopic();
|
||||||
const auto topic = topicRootId
|
|
||||||
? peer->forumTopicFor(topicRootId)
|
|
||||||
: nullptr;
|
|
||||||
const auto name = topic
|
const auto name = topic
|
||||||
? topic->title()
|
? topic->title()
|
||||||
: peer->isSelf()
|
: thread->peer()->isSelf()
|
||||||
? tr::lng_saved_messages(tr::now)
|
? tr::lng_saved_messages(tr::now)
|
||||||
: peer->name();
|
: thread->peer()->name();
|
||||||
const auto wrapped = st::wrap_rtl(name);
|
const auto wrapped = st::wrap_rtl(name);
|
||||||
return name + u" @ "_q + result;
|
return name + u" @ "_q + result;
|
||||||
}
|
}
|
||||||
|
@ -902,11 +885,11 @@ void MainWindow::updateTitle() {
|
||||||
&& Core::App().domain().accountsAuthedCount() > 1)
|
&& Core::App().domain().accountsAuthedCount() > 1)
|
||||||
? st::wrap_rtl(session->authedName())
|
? st::wrap_rtl(session->authedName())
|
||||||
: QString();
|
: QString();
|
||||||
const auto separateIdTitle = session
|
const auto separateSharedMediaTitle = session
|
||||||
? TitleFromSeparateId(settings, session->windowId())
|
? TitleFromSeparateSharedMedia(settings, session->windowId())
|
||||||
: QString();
|
: QString();
|
||||||
if (!separateIdTitle.isEmpty()) {
|
if (!separateSharedMediaTitle.isEmpty()) {
|
||||||
setTitle(separateIdTitle);
|
setTitle(separateSharedMediaTitle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto key = (session && !settings.hideChatName)
|
const auto key = (session && !settings.hideChatName)
|
||||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "window/window_separate_id.h"
|
#include "window/window_separate_id.h"
|
||||||
|
|
||||||
|
#include "data/data_channel.h"
|
||||||
#include "data/data_folder.h"
|
#include "data/data_folder.h"
|
||||||
#include "data/data_peer.h"
|
#include "data/data_peer.h"
|
||||||
#include "data/data_saved_messages.h"
|
#include "data/data_saved_messages.h"
|
||||||
|
@ -30,10 +31,14 @@ SeparateId::SeparateId(SeparateType type, not_null<Main::Session*> session)
|
||||||
, account(&session->account()) {
|
, account(&session->account()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SeparateId::SeparateId(SeparateType type, not_null<Data::Thread*> thread)
|
SeparateId::SeparateId(
|
||||||
|
SeparateType type,
|
||||||
|
not_null<Data::Thread*> thread,
|
||||||
|
ChannelData *parentChat)
|
||||||
: type(type)
|
: type(type)
|
||||||
, account(&thread->session().account())
|
, account(&thread->session().account())
|
||||||
, thread(thread) {
|
, thread(thread)
|
||||||
|
, parentChat((type == SeparateType::SavedSublist) ? parentChat : nullptr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SeparateId::SeparateId(not_null<Data::Thread*> thread)
|
SeparateId::SeparateId(not_null<Data::Thread*> thread)
|
||||||
|
@ -44,12 +49,13 @@ SeparateId::SeparateId(not_null<PeerData*> peer)
|
||||||
: SeparateId(SeparateType::Chat, peer->owner().history(peer)) {
|
: SeparateId(SeparateType::Chat, peer->owner().history(peer)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SeparateId::SeparateId(SeparateSharedMedia data)
|
SeparateId::SeparateId(
|
||||||
|
not_null<Data::Thread*> thread,
|
||||||
|
Storage::SharedMediaType sharedMediaType)
|
||||||
: type(SeparateType::SharedMedia)
|
: type(SeparateType::SharedMedia)
|
||||||
, sharedMedia(data.type)
|
, sharedMediaType(sharedMediaType)
|
||||||
, account(&data.peer->session().account())
|
, account(&thread->session().account())
|
||||||
, sharedMediaDataPeer(data.peer)
|
, thread(thread) {
|
||||||
, sharedMediaDataTopicRootId(data.topicRootId) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SeparateId::primary() const {
|
bool SeparateId::primary() const {
|
||||||
|
@ -71,9 +77,12 @@ Data::Folder *SeparateId::folder() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
Data::SavedSublist *SeparateId::sublist() const {
|
Data::SavedSublist *SeparateId::sublist() const {
|
||||||
return (type == SeparateType::SavedSublist)
|
const auto monoforum = parentChat ? parentChat->monoforum() : nullptr;
|
||||||
? thread->owner().savedMessages().sublist(thread->peer()).get()
|
return (type != SeparateType::SavedSublist)
|
||||||
: nullptr;
|
? nullptr
|
||||||
|
: monoforum
|
||||||
|
? monoforum->sublist(thread->peer()).get()
|
||||||
|
: thread->owner().savedMessages().sublist(thread->peer()).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SeparateId::hasChatsList() const {
|
bool SeparateId::hasChatsList() const {
|
||||||
|
@ -82,16 +91,4 @@ bool SeparateId::hasChatsList() const {
|
||||||
|| (type == SeparateType::Forum);
|
|| (type == SeparateType::Forum);
|
||||||
}
|
}
|
||||||
|
|
||||||
PeerData *SeparateId::sharedMediaPeer() const {
|
|
||||||
return (type == SeparateType::SharedMedia)
|
|
||||||
? sharedMediaDataPeer
|
|
||||||
: nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
MsgId SeparateId::sharedMediaTopicRootId() const {
|
|
||||||
return (type == SeparateType::SharedMedia)
|
|
||||||
? sharedMediaDataTopicRootId
|
|
||||||
: MsgId();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Window
|
} // namespace Window
|
||||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
class ChannelData;
|
||||||
class PeerData;
|
class PeerData;
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
@ -21,6 +22,10 @@ class Account;
|
||||||
class Session;
|
class Session;
|
||||||
} // namespace Main
|
} // namespace Main
|
||||||
|
|
||||||
|
namespace Storage {
|
||||||
|
enum class SharedMediaType : signed char;
|
||||||
|
} // namespace Storage
|
||||||
|
|
||||||
namespace Window {
|
namespace Window {
|
||||||
|
|
||||||
enum class SeparateType {
|
enum class SeparateType {
|
||||||
|
@ -32,39 +37,30 @@ enum class SeparateType {
|
||||||
SharedMedia,
|
SharedMedia,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class SeparateSharedMediaType {
|
|
||||||
None,
|
|
||||||
Photos,
|
|
||||||
Videos,
|
|
||||||
Files,
|
|
||||||
Audio,
|
|
||||||
Links,
|
|
||||||
Voices,
|
|
||||||
GIF,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SeparateSharedMedia {
|
struct SeparateSharedMedia {
|
||||||
SeparateSharedMediaType type = SeparateSharedMediaType::None;
|
not_null<Data::Thread*> thread;
|
||||||
not_null<PeerData*> peer;
|
Storage::SharedMediaType type = {};
|
||||||
MsgId topicRootId = MsgId();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SeparateId {
|
struct SeparateId {
|
||||||
SeparateId(std::nullptr_t);
|
SeparateId(std::nullptr_t);
|
||||||
SeparateId(not_null<Main::Account*> account);
|
SeparateId(not_null<Main::Account*> account);
|
||||||
SeparateId(SeparateType type, not_null<Main::Session*> session);
|
SeparateId(SeparateType type, not_null<Main::Session*> session);
|
||||||
SeparateId(SeparateType type, not_null<Data::Thread*> thread);
|
SeparateId(
|
||||||
|
SeparateType type,
|
||||||
|
not_null<Data::Thread*> thread,
|
||||||
|
ChannelData *parentChat = nullptr);
|
||||||
SeparateId(not_null<Data::Thread*> thread);
|
SeparateId(not_null<Data::Thread*> thread);
|
||||||
SeparateId(not_null<PeerData*> peer);
|
SeparateId(not_null<PeerData*> peer);
|
||||||
SeparateId(SeparateSharedMedia data);
|
SeparateId(
|
||||||
|
not_null<Data::Thread*> thread,
|
||||||
|
Storage::SharedMediaType sharedMediaType);
|
||||||
|
|
||||||
SeparateType type = SeparateType::Primary;
|
SeparateType type = SeparateType::Primary;
|
||||||
SeparateSharedMediaType sharedMedia = SeparateSharedMediaType::None;
|
Storage::SharedMediaType sharedMediaType = {};
|
||||||
Main::Account *account = nullptr;
|
Main::Account *account = nullptr;
|
||||||
Data::Thread *thread = nullptr; // For types except Main and Archive.
|
Data::Thread *thread = nullptr; // For types except Main and Archive.
|
||||||
PeerData *sharedMediaDataPeer = nullptr;
|
ChannelData *parentChat = nullptr;
|
||||||
MsgId sharedMediaDataTopicRootId = MsgId();
|
|
||||||
|
|
||||||
[[nodiscard]] bool valid() const {
|
[[nodiscard]] bool valid() const {
|
||||||
return account != nullptr;
|
return account != nullptr;
|
||||||
}
|
}
|
||||||
|
@ -77,8 +73,6 @@ struct SeparateId {
|
||||||
[[nodiscard]] Data::Forum *forum() const;
|
[[nodiscard]] Data::Forum *forum() const;
|
||||||
[[nodiscard]] Data::Folder *folder() const;
|
[[nodiscard]] Data::Folder *folder() const;
|
||||||
[[nodiscard]] Data::SavedSublist *sublist() const;
|
[[nodiscard]] Data::SavedSublist *sublist() const;
|
||||||
[[nodiscard]] PeerData *sharedMediaPeer() const;
|
|
||||||
[[nodiscard]] MsgId sharedMediaTopicRootId() const;
|
|
||||||
|
|
||||||
[[nodiscard]] bool hasChatsList() const;
|
[[nodiscard]] bool hasChatsList() const;
|
||||||
|
|
||||||
|
|
|
@ -1321,35 +1321,13 @@ void SessionNavigation::showByInitialId(
|
||||||
showThread(id.thread, msgId, instant);
|
showThread(id.thread, msgId, instant);
|
||||||
break;
|
break;
|
||||||
case SeparateType::SharedMedia: {
|
case SeparateType::SharedMedia: {
|
||||||
Assert(id.sharedMedia != SeparateSharedMediaType::None);
|
|
||||||
clearSectionStack(instant);
|
clearSectionStack(instant);
|
||||||
const auto type = (id.sharedMedia == SeparateSharedMediaType::Photos)
|
const auto type = id.sharedMediaType;
|
||||||
? Storage::SharedMediaType::Photo
|
const auto topic = id.thread->asTopic();
|
||||||
: (id.sharedMedia == SeparateSharedMediaType::Videos)
|
|
||||||
? Storage::SharedMediaType::Video
|
|
||||||
: (id.sharedMedia == SeparateSharedMediaType::Files)
|
|
||||||
? Storage::SharedMediaType::File
|
|
||||||
: (id.sharedMedia == SeparateSharedMediaType::Audio)
|
|
||||||
? Storage::SharedMediaType::MusicFile
|
|
||||||
: (id.sharedMedia == SeparateSharedMediaType::Links)
|
|
||||||
? Storage::SharedMediaType::Link
|
|
||||||
: (id.sharedMedia == SeparateSharedMediaType::Voices)
|
|
||||||
? Storage::SharedMediaType::RoundVoiceFile
|
|
||||||
: (id.sharedMedia == SeparateSharedMediaType::GIF)
|
|
||||||
? Storage::SharedMediaType::GIF
|
|
||||||
: Storage::SharedMediaType::Photo;
|
|
||||||
const auto topicRootId = id.sharedMediaTopicRootId();
|
|
||||||
const auto peer = id.sharedMediaPeer();
|
|
||||||
const auto topic = topicRootId
|
|
||||||
? peer->forumTopicFor(topicRootId)
|
|
||||||
: nullptr;
|
|
||||||
if (topicRootId && !topic) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
showSection(
|
showSection(
|
||||||
topicRootId
|
(topic
|
||||||
? std::make_shared<Info::Memento>(topic, type)
|
? std::make_shared<Info::Memento>(topic, type)
|
||||||
: std::make_shared<Info::Memento>(peer, type),
|
: std::make_shared<Info::Memento>(id.thread->peer(), type)),
|
||||||
instant);
|
instant);
|
||||||
parent->widget()->setMaximumWidth(st::maxWidthSharedMediaWindow);
|
parent->widget()->setMaximumWidth(st::maxWidthSharedMediaWindow);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Add table
Reference in a new issue