Merge tag 'v4.11.7' into dev
# Conflicts: # Telegram/Resources/winrc/Telegram.rc # Telegram/Resources/winrc/Updater.rc # Telegram/SourceFiles/core/version.h # Telegram/lib_ui
Before Width: | Height: | Size: 402 B After Width: | Height: | Size: 759 B |
Before Width: | Height: | Size: 858 B After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.8 KiB |
BIN
Telegram/Resources/icons/chat/input_link_settings.png
Normal file
After Width: | Height: | Size: 829 B |
BIN
Telegram/Resources/icons/chat/input_link_settings@2x.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
Telegram/Resources/icons/chat/input_link_settings@3x.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 593 B |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.8 KiB |
BIN
Telegram/Resources/icons/chat/input_reply_quote.png
Normal file
After Width: | Height: | Size: 676 B |
BIN
Telegram/Resources/icons/chat/input_reply_quote@2x.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/chat/input_reply_quote@3x.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
Telegram/Resources/icons/chat/input_reply_settings.png
Normal file
After Width: | Height: | Size: 711 B |
BIN
Telegram/Resources/icons/chat/input_reply_settings@2x.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/chat/input_reply_settings@3x.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
|
@ -2714,6 +2714,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_forwarding_from_two" = "{user} and {second_user}";
|
"lng_forwarding_from_two" = "{user} and {second_user}";
|
||||||
"lng_inline_switch_choose" = "Choose conversation...";
|
"lng_inline_switch_choose" = "Choose conversation...";
|
||||||
"lng_inline_switch_cant" = "Sorry, no way to write here :(";
|
"lng_inline_switch_cant" = "Sorry, no way to write here :(";
|
||||||
|
"lng_preview_reply_to" = "Reply to {name}";
|
||||||
|
"lng_preview_reply_to_quote" = "Reply to quote by {name}";
|
||||||
|
|
||||||
"lng_reply_in_another_title" = "Reply in...";
|
"lng_reply_in_another_title" = "Reply in...";
|
||||||
"lng_reply_in_another_chat" = "Reply in Another Chat";
|
"lng_reply_in_another_chat" = "Reply in Another Chat";
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||||
ProcessorArchitecture="ARCHITECTURE"
|
ProcessorArchitecture="ARCHITECTURE"
|
||||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||||
Version="4.11.6.0" />
|
Version="4.11.7.0" />
|
||||||
<Properties>
|
<Properties>
|
||||||
<DisplayName>Telegram Desktop</DisplayName>
|
<DisplayName>Telegram Desktop</DisplayName>
|
||||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||||
|
|
|
@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 4,11,6,0
|
FILEVERSION 4,11,7,0
|
||||||
PRODUCTVERSION 4,11,6,0
|
PRODUCTVERSION 4,11,7,0
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -62,10 +62,10 @@ BEGIN
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Radolyn Labs"
|
VALUE "CompanyName", "Radolyn Labs"
|
||||||
VALUE "FileDescription", "AyuGram Desktop"
|
VALUE "FileDescription", "AyuGram Desktop"
|
||||||
VALUE "FileVersion", "4.11.6.0"
|
VALUE "FileVersion", "4.11.7.0"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
|
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
|
||||||
VALUE "ProductName", "AyuGram Desktop"
|
VALUE "ProductName", "AyuGram Desktop"
|
||||||
VALUE "ProductVersion", "4.11.6.0"
|
VALUE "ProductVersion", "4.11.7.0"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
|
@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 4,11,6,0
|
FILEVERSION 4,11,7,0
|
||||||
PRODUCTVERSION 4,11,6,0
|
PRODUCTVERSION 4,11,7,0
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -53,10 +53,10 @@ BEGIN
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Radolyn Labs"
|
VALUE "CompanyName", "Radolyn Labs"
|
||||||
VALUE "FileDescription", "AyuGram Desktop Updater"
|
VALUE "FileDescription", "AyuGram Desktop Updater"
|
||||||
VALUE "FileVersion", "4.11.6.0"
|
VALUE "FileVersion", "4.11.7.0"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
|
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
|
||||||
VALUE "ProductName", "AyuGram Desktop"
|
VALUE "ProductName", "AyuGram Desktop"
|
||||||
VALUE "ProductVersion", "4.11.6.0"
|
VALUE "ProductVersion", "4.11.7.0"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
|
@ -18,6 +18,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace Api {
|
namespace Api {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kCheckRequestsTimer = 10 * crl::time(1000);
|
||||||
|
|
||||||
[[nodiscard]] Data::StatisticalGraph StatisticalGraphFromTL(
|
[[nodiscard]] Data::StatisticalGraph StatisticalGraphFromTL(
|
||||||
const MTPStatsGraph &tl) {
|
const MTPStatsGraph &tl) {
|
||||||
return tl.match([&](const MTPDstatsGraph &d) {
|
return tl.match([&](const MTPDstatsGraph &d) {
|
||||||
|
@ -187,23 +189,73 @@ namespace {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Statistics::Statistics(not_null<ApiWrap*> api)
|
Statistics::Statistics(not_null<ChannelData*> channel)
|
||||||
: _api(&api->instance()) {
|
: StatisticsRequestSender(channel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<rpl::no_value, QString> Statistics::request(
|
StatisticsRequestSender::StatisticsRequestSender(not_null<ChannelData *> channel)
|
||||||
not_null<PeerData*> peer) {
|
: _channel(channel)
|
||||||
|
, _api(&_channel->session().api().instance())
|
||||||
|
, _timer([=] { checkRequests(); }) {
|
||||||
|
}
|
||||||
|
|
||||||
|
StatisticsRequestSender::~StatisticsRequestSender() {
|
||||||
|
for (const auto &[dcId, ids] : _requests) {
|
||||||
|
for (const auto id : ids) {
|
||||||
|
_channel->session().api().unregisterStatsRequest(dcId, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatisticsRequestSender::checkRequests() {
|
||||||
|
for (auto i = begin(_requests); i != end(_requests);) {
|
||||||
|
for (auto j = begin(i->second); j != end(i->second);) {
|
||||||
|
if (_api.pending(*j)) {
|
||||||
|
++j;
|
||||||
|
} else {
|
||||||
|
_channel->session().api().unregisterStatsRequest(
|
||||||
|
i->first,
|
||||||
|
*j);
|
||||||
|
j = i->second.erase(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i->second.empty()) {
|
||||||
|
i = _requests.erase(i);
|
||||||
|
} else {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_requests.empty()) {
|
||||||
|
_timer.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Request, typename, typename>
|
||||||
|
auto StatisticsRequestSender::makeRequest(Request &&request) {
|
||||||
|
const auto id = _api.allocateRequestId();
|
||||||
|
const auto dcId = _channel->owner().statsDcId(_channel);
|
||||||
|
if (dcId) {
|
||||||
|
_channel->session().api().registerStatsRequest(dcId, id);
|
||||||
|
_requests[dcId].emplace(id);
|
||||||
|
if (!_timer.isActive()) {
|
||||||
|
_timer.callEach(kCheckRequestsTimer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::move(_api.request(
|
||||||
|
std::forward<Request>(request)
|
||||||
|
).toDC(
|
||||||
|
dcId ? MTP::ShiftDcId(dcId, MTP::kStatsDcShift) : 0
|
||||||
|
).overrideId(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<rpl::no_value, QString> Statistics::request() {
|
||||||
return [=](auto consumer) {
|
return [=](auto consumer) {
|
||||||
auto lifetime = rpl::lifetime();
|
auto lifetime = rpl::lifetime();
|
||||||
const auto channel = peer->asChannel();
|
|
||||||
if (!channel) {
|
|
||||||
return lifetime;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!channel->isMegagroup()) {
|
if (!channel()->isMegagroup()) {
|
||||||
_api.request(MTPstats_GetBroadcastStats(
|
makeRequest(MTPstats_GetBroadcastStats(
|
||||||
MTP_flags(MTPstats_GetBroadcastStats::Flags(0)),
|
MTP_flags(MTPstats_GetBroadcastStats::Flags(0)),
|
||||||
channel->inputChannel
|
channel()->inputChannel
|
||||||
)).done([=](const MTPstats_BroadcastStats &result) {
|
)).done([=](const MTPstats_BroadcastStats &result) {
|
||||||
_channelStats = ChannelStatisticsFromTL(result.data());
|
_channelStats = ChannelStatisticsFromTL(result.data());
|
||||||
consumer.put_done();
|
consumer.put_done();
|
||||||
|
@ -211,12 +263,13 @@ rpl::producer<rpl::no_value, QString> Statistics::request(
|
||||||
consumer.put_error_copy(error.type());
|
consumer.put_error_copy(error.type());
|
||||||
}).send();
|
}).send();
|
||||||
} else {
|
} else {
|
||||||
_api.request(MTPstats_GetMegagroupStats(
|
makeRequest(MTPstats_GetMegagroupStats(
|
||||||
MTP_flags(MTPstats_GetMegagroupStats::Flags(0)),
|
MTP_flags(MTPstats_GetMegagroupStats::Flags(0)),
|
||||||
channel->inputChannel
|
channel()->inputChannel
|
||||||
)).done([=](const MTPstats_MegagroupStats &result) {
|
)).done([=](const MTPstats_MegagroupStats &result) {
|
||||||
_supergroupStats = SupergroupStatisticsFromTL(result.data());
|
const auto &data = result.data();
|
||||||
peer->owner().processUsers(result.data().vusers());
|
_supergroupStats = SupergroupStatisticsFromTL(data);
|
||||||
|
channel()->owner().processUsers(data.vusers());
|
||||||
consumer.put_done();
|
consumer.put_done();
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
consumer.put_error_copy(error.type());
|
consumer.put_error_copy(error.type());
|
||||||
|
@ -228,18 +281,13 @@ rpl::producer<rpl::no_value, QString> Statistics::request(
|
||||||
}
|
}
|
||||||
|
|
||||||
Statistics::GraphResult Statistics::requestZoom(
|
Statistics::GraphResult Statistics::requestZoom(
|
||||||
not_null<PeerData*> peer,
|
|
||||||
const QString &token,
|
const QString &token,
|
||||||
float64 x) {
|
float64 x) {
|
||||||
return [=](auto consumer) {
|
return [=](auto consumer) {
|
||||||
auto lifetime = rpl::lifetime();
|
auto lifetime = rpl::lifetime();
|
||||||
const auto channel = peer->asChannel();
|
|
||||||
if (!channel) {
|
|
||||||
return lifetime;
|
|
||||||
}
|
|
||||||
const auto wasEmpty = _zoomDeque.empty();
|
const auto wasEmpty = _zoomDeque.empty();
|
||||||
_zoomDeque.push_back([=] {
|
_zoomDeque.push_back([=] {
|
||||||
_api.request(MTPstats_LoadAsyncGraph(
|
makeRequest(MTPstats_LoadAsyncGraph(
|
||||||
MTP_flags(x
|
MTP_flags(x
|
||||||
? MTPstats_LoadAsyncGraph::Flag::f_x
|
? MTPstats_LoadAsyncGraph::Flag::f_x
|
||||||
: MTPstats_LoadAsyncGraph::Flag(0)),
|
: MTPstats_LoadAsyncGraph::Flag(0)),
|
||||||
|
@ -266,32 +314,6 @@ Statistics::GraphResult Statistics::requestZoom(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Statistics::GraphResult Statistics::requestMessage(
|
|
||||||
not_null<PeerData*> peer,
|
|
||||||
MsgId msgId) {
|
|
||||||
return [=](auto consumer) {
|
|
||||||
auto lifetime = rpl::lifetime();
|
|
||||||
const auto channel = peer->asChannel();
|
|
||||||
if (!channel) {
|
|
||||||
return lifetime;
|
|
||||||
}
|
|
||||||
|
|
||||||
_api.request(MTPstats_GetMessageStats(
|
|
||||||
MTP_flags(MTPstats_GetMessageStats::Flags(0)),
|
|
||||||
channel->inputChannel,
|
|
||||||
MTP_int(msgId.bare)
|
|
||||||
)).done([=](const MTPstats_MessageStats &result) {
|
|
||||||
consumer.put_next(
|
|
||||||
StatisticalGraphFromTL(result.data().vviews_graph()));
|
|
||||||
consumer.put_done();
|
|
||||||
}).fail([=](const MTP::Error &error) {
|
|
||||||
consumer.put_error_copy(error.type());
|
|
||||||
}).send();
|
|
||||||
|
|
||||||
return lifetime;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Data::ChannelStatistics Statistics::channelStats() const {
|
Data::ChannelStatistics Statistics::channelStats() const {
|
||||||
return _channelStats;
|
return _channelStats;
|
||||||
}
|
}
|
||||||
|
@ -303,9 +325,8 @@ Data::SupergroupStatistics Statistics::supergroupStats() const {
|
||||||
PublicForwards::PublicForwards(
|
PublicForwards::PublicForwards(
|
||||||
not_null<ChannelData*> channel,
|
not_null<ChannelData*> channel,
|
||||||
FullMsgId fullId)
|
FullMsgId fullId)
|
||||||
: _channel(channel)
|
: StatisticsRequestSender(channel)
|
||||||
, _fullId(fullId)
|
, _fullId(fullId) {
|
||||||
, _api(&channel->session().api().instance()) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PublicForwards::request(
|
void PublicForwards::request(
|
||||||
|
@ -314,19 +335,19 @@ void PublicForwards::request(
|
||||||
if (_requestId) {
|
if (_requestId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto offsetPeer = _channel->owner().peer(token.fullId.peer);
|
const auto offsetPeer = channel()->owner().peer(token.fullId.peer);
|
||||||
const auto tlOffsetPeer = offsetPeer
|
const auto tlOffsetPeer = offsetPeer
|
||||||
? offsetPeer->input
|
? offsetPeer->input
|
||||||
: MTP_inputPeerEmpty();
|
: MTP_inputPeerEmpty();
|
||||||
constexpr auto kLimit = tl::make_int(100);
|
constexpr auto kLimit = tl::make_int(100);
|
||||||
_requestId = _api.request(MTPstats_GetMessagePublicForwards(
|
_requestId = makeRequest(MTPstats_GetMessagePublicForwards(
|
||||||
_channel->inputChannel,
|
channel()->inputChannel,
|
||||||
MTP_int(_fullId.msg),
|
MTP_int(_fullId.msg),
|
||||||
MTP_int(token.rate),
|
MTP_int(token.rate),
|
||||||
tlOffsetPeer,
|
tlOffsetPeer,
|
||||||
MTP_int(token.fullId.msg),
|
MTP_int(token.fullId.msg),
|
||||||
kLimit
|
kLimit
|
||||||
)).done([=, channel = _channel](const MTPmessages_Messages &result) {
|
)).done([=, channel = channel()](const MTPmessages_Messages &result) {
|
||||||
using Messages = QVector<FullMsgId>;
|
using Messages = QVector<FullMsgId>;
|
||||||
_requestId = 0;
|
_requestId = 0;
|
||||||
|
|
||||||
|
@ -402,10 +423,9 @@ void PublicForwards::request(
|
||||||
MessageStatistics::MessageStatistics(
|
MessageStatistics::MessageStatistics(
|
||||||
not_null<ChannelData*> channel,
|
not_null<ChannelData*> channel,
|
||||||
FullMsgId fullId)
|
FullMsgId fullId)
|
||||||
: _publicForwards(channel, fullId)
|
: StatisticsRequestSender(channel)
|
||||||
, _channel(channel)
|
, _publicForwards(channel, fullId)
|
||||||
, _fullId(fullId)
|
, _fullId(fullId) {
|
||||||
, _api(&channel->session().api().instance()) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Data::PublicForwardsSlice MessageStatistics::firstSlice() const {
|
Data::PublicForwardsSlice MessageStatistics::firstSlice() const {
|
||||||
|
@ -413,10 +433,9 @@ Data::PublicForwardsSlice MessageStatistics::firstSlice() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageStatistics::request(Fn<void(Data::MessageStatistics)> done) {
|
void MessageStatistics::request(Fn<void(Data::MessageStatistics)> done) {
|
||||||
if (_channel->isMegagroup()) {
|
if (channel()->isMegagroup()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto requestFirstPublicForwards = [=](
|
const auto requestFirstPublicForwards = [=](
|
||||||
const Data::StatisticalGraph &messageGraph,
|
const Data::StatisticalGraph &messageGraph,
|
||||||
const Data::StatisticsMessageInteractionInfo &info) {
|
const Data::StatisticsMessageInteractionInfo &info) {
|
||||||
|
@ -434,8 +453,8 @@ void MessageStatistics::request(Fn<void(Data::MessageStatistics)> done) {
|
||||||
|
|
||||||
const auto requestPrivateForwards = [=](
|
const auto requestPrivateForwards = [=](
|
||||||
const Data::StatisticalGraph &messageGraph) {
|
const Data::StatisticalGraph &messageGraph) {
|
||||||
_api.request(MTPchannels_GetMessages(
|
api().request(MTPchannels_GetMessages(
|
||||||
_channel->inputChannel,
|
channel()->inputChannel,
|
||||||
MTP_vector<MTPInputMessage>(
|
MTP_vector<MTPInputMessage>(
|
||||||
1,
|
1,
|
||||||
MTP_inputMessageID(MTP_int(_fullId.msg))))
|
MTP_inputMessageID(MTP_int(_fullId.msg))))
|
||||||
|
@ -475,9 +494,9 @@ void MessageStatistics::request(Fn<void(Data::MessageStatistics)> done) {
|
||||||
}).send();
|
}).send();
|
||||||
};
|
};
|
||||||
|
|
||||||
_api.request(MTPstats_GetMessageStats(
|
makeRequest(MTPstats_GetMessageStats(
|
||||||
MTP_flags(MTPstats_GetMessageStats::Flags(0)),
|
MTP_flags(MTPstats_GetMessageStats::Flags(0)),
|
||||||
_channel->inputChannel,
|
channel()->inputChannel,
|
||||||
MTP_int(_fullId.msg.bare)
|
MTP_int(_fullId.msg.bare)
|
||||||
)).done([=](const MTPstats_MessageStats &result) {
|
)).done([=](const MTPstats_MessageStats &result) {
|
||||||
requestPrivateForwards(
|
requestPrivateForwards(
|
||||||
|
@ -485,7 +504,6 @@ void MessageStatistics::request(Fn<void(Data::MessageStatistics)> done) {
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
requestPrivateForwards({});
|
requestPrivateForwards({});
|
||||||
}).send();
|
}).send();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Boosts::Boosts(not_null<PeerData*> peer)
|
Boosts::Boosts(not_null<PeerData*> peer)
|
||||||
|
|
|
@ -7,30 +7,53 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "base/timer.h"
|
||||||
#include "data/data_boosts.h"
|
#include "data/data_boosts.h"
|
||||||
#include "data/data_statistics.h"
|
#include "data/data_statistics.h"
|
||||||
#include "mtproto/sender.h"
|
#include "mtproto/sender.h"
|
||||||
|
|
||||||
class ApiWrap;
|
|
||||||
class ChannelData;
|
class ChannelData;
|
||||||
class PeerData;
|
class PeerData;
|
||||||
|
|
||||||
namespace Api {
|
namespace Api {
|
||||||
|
|
||||||
class Statistics final {
|
class StatisticsRequestSender {
|
||||||
public:
|
protected:
|
||||||
explicit Statistics(not_null<ApiWrap*> api);
|
explicit StatisticsRequestSender(not_null<ChannelData*> channel);
|
||||||
|
~StatisticsRequestSender();
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<rpl::no_value, QString> request(
|
template <
|
||||||
not_null<PeerData*> peer);
|
typename Request,
|
||||||
|
typename = std::enable_if_t<!std::is_reference_v<Request>>,
|
||||||
|
typename = typename Request::Unboxed>
|
||||||
|
[[nodiscard]] auto makeRequest(Request &&request);
|
||||||
|
|
||||||
|
[[nodiscard]] MTP::Sender &api() {
|
||||||
|
return _api;
|
||||||
|
}
|
||||||
|
[[nodiscard]] not_null<ChannelData*> channel() {
|
||||||
|
return _channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void checkRequests();
|
||||||
|
|
||||||
|
const not_null<ChannelData*> _channel;
|
||||||
|
MTP::Sender _api;
|
||||||
|
base::Timer _timer;
|
||||||
|
base::flat_map<MTP::DcId, base::flat_set<mtpRequestId>> _requests;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class Statistics final : public StatisticsRequestSender {
|
||||||
|
public:
|
||||||
|
explicit Statistics(not_null<ChannelData*> channel);
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::producer<rpl::no_value, QString> request();
|
||||||
using GraphResult = rpl::producer<Data::StatisticalGraph, QString>;
|
using GraphResult = rpl::producer<Data::StatisticalGraph, QString>;
|
||||||
[[nodiscard]] GraphResult requestZoom(
|
[[nodiscard]] GraphResult requestZoom(
|
||||||
not_null<PeerData*> peer,
|
|
||||||
const QString &token,
|
const QString &token,
|
||||||
float64 x);
|
float64 x);
|
||||||
[[nodiscard]] GraphResult requestMessage(
|
|
||||||
not_null<PeerData*> peer,
|
|
||||||
MsgId msgId);
|
|
||||||
|
|
||||||
[[nodiscard]] Data::ChannelStatistics channelStats() const;
|
[[nodiscard]] Data::ChannelStatistics channelStats() const;
|
||||||
[[nodiscard]] Data::SupergroupStatistics supergroupStats() const;
|
[[nodiscard]] Data::SupergroupStatistics supergroupStats() const;
|
||||||
|
@ -38,31 +61,27 @@ public:
|
||||||
private:
|
private:
|
||||||
Data::ChannelStatistics _channelStats;
|
Data::ChannelStatistics _channelStats;
|
||||||
Data::SupergroupStatistics _supergroupStats;
|
Data::SupergroupStatistics _supergroupStats;
|
||||||
MTP::Sender _api;
|
|
||||||
|
|
||||||
std::deque<Fn<void()>> _zoomDeque;
|
std::deque<Fn<void()>> _zoomDeque;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PublicForwards final {
|
class PublicForwards final : public StatisticsRequestSender {
|
||||||
public:
|
public:
|
||||||
explicit PublicForwards(not_null<ChannelData*> channel, FullMsgId fullId);
|
PublicForwards(not_null<ChannelData*> channel, FullMsgId fullId);
|
||||||
|
|
||||||
void request(
|
void request(
|
||||||
const Data::PublicForwardsSlice::OffsetToken &token,
|
const Data::PublicForwardsSlice::OffsetToken &token,
|
||||||
Fn<void(Data::PublicForwardsSlice)> done);
|
Fn<void(Data::PublicForwardsSlice)> done);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const not_null<ChannelData*> _channel;
|
|
||||||
const FullMsgId _fullId;
|
const FullMsgId _fullId;
|
||||||
mtpRequestId _requestId = 0;
|
mtpRequestId _requestId = 0;
|
||||||
int _lastTotal = 0;
|
int _lastTotal = 0;
|
||||||
|
|
||||||
MTP::Sender _api;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class MessageStatistics final {
|
class MessageStatistics final : public StatisticsRequestSender {
|
||||||
public:
|
public:
|
||||||
explicit MessageStatistics(
|
explicit MessageStatistics(
|
||||||
not_null<ChannelData*> channel,
|
not_null<ChannelData*> channel,
|
||||||
|
@ -74,13 +93,11 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PublicForwards _publicForwards;
|
PublicForwards _publicForwards;
|
||||||
const not_null<ChannelData*> _channel;
|
|
||||||
const FullMsgId _fullId;
|
const FullMsgId _fullId;
|
||||||
|
|
||||||
Data::PublicForwardsSlice _firstSlice;
|
Data::PublicForwardsSlice _firstSlice;
|
||||||
|
|
||||||
mtpRequestId _requestId = 0;
|
mtpRequestId _requestId = 0;
|
||||||
MTP::Sender _api;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -118,6 +118,7 @@ constexpr auto kStickersByEmojiInvalidateTimeout = crl::time(6 * 1000);
|
||||||
constexpr auto kNotifySettingSaveTimeout = crl::time(1000);
|
constexpr auto kNotifySettingSaveTimeout = crl::time(1000);
|
||||||
constexpr auto kDialogsFirstLoad = 20;
|
constexpr auto kDialogsFirstLoad = 20;
|
||||||
constexpr auto kDialogsPerPage = 500;
|
constexpr auto kDialogsPerPage = 500;
|
||||||
|
constexpr auto kStatsSessionKillTimeout = 10 * crl::time(1000);
|
||||||
|
|
||||||
using PhotoFileLocationId = Data::PhotoFileLocationId;
|
using PhotoFileLocationId = Data::PhotoFileLocationId;
|
||||||
using DocumentFileLocationId = Data::DocumentFileLocationId;
|
using DocumentFileLocationId = Data::DocumentFileLocationId;
|
||||||
|
@ -163,6 +164,7 @@ ApiWrap::ApiWrap(not_null<Main::Session*> session)
|
||||||
, _fileLoader(std::make_unique<TaskQueue>(kFileLoaderQueueStopTimeout))
|
, _fileLoader(std::make_unique<TaskQueue>(kFileLoaderQueueStopTimeout))
|
||||||
, _topPromotionTimer([=] { refreshTopPromotion(); })
|
, _topPromotionTimer([=] { refreshTopPromotion(); })
|
||||||
, _updateNotifyTimer([=] { sendNotifySettingsUpdates(); })
|
, _updateNotifyTimer([=] { sendNotifySettingsUpdates(); })
|
||||||
|
, _statsSessionKillTimer([=] { checkStatsSessions(); })
|
||||||
, _authorizations(std::make_unique<Api::Authorizations>(this))
|
, _authorizations(std::make_unique<Api::Authorizations>(this))
|
||||||
, _attachedStickers(std::make_unique<Api::AttachedStickers>(this))
|
, _attachedStickers(std::make_unique<Api::AttachedStickers>(this))
|
||||||
, _blockedPeers(std::make_unique<Api::BlockedPeers>(this))
|
, _blockedPeers(std::make_unique<Api::BlockedPeers>(this))
|
||||||
|
@ -3614,11 +3616,12 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||||
sendAction(action);
|
sendAction(action);
|
||||||
|
|
||||||
const auto clearCloudDraft = action.clearDraft;
|
const auto clearCloudDraft = action.clearDraft;
|
||||||
|
const auto draftTopicRootId = action.replyTo.topicRootId;
|
||||||
const auto replyTo = action.replyTo.messageId
|
const auto replyTo = action.replyTo.messageId
|
||||||
? peer->owner().message(action.replyTo.messageId)
|
? peer->owner().message(action.replyTo.messageId)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
const auto topicRootId = action.replyTo.topicRootId
|
const auto topicRootId = draftTopicRootId
|
||||||
? action.replyTo.topicRootId
|
? draftTopicRootId
|
||||||
: replyTo
|
: replyTo
|
||||||
? replyTo->topicRootId()
|
? replyTo->topicRootId()
|
||||||
: Data::ForumTopic::kGeneralId;
|
: Data::ForumTopic::kGeneralId;
|
||||||
|
@ -3658,7 +3661,10 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||||
TextUtilities::Trim(sending);
|
TextUtilities::Trim(sending);
|
||||||
|
|
||||||
_session->data().registerMessageRandomId(randomId, newId);
|
_session->data().registerMessageRandomId(randomId, newId);
|
||||||
_session->data().registerMessageSentData(randomId, peer->id, sending.text);
|
_session->data().registerMessageSentData(
|
||||||
|
randomId,
|
||||||
|
peer->id,
|
||||||
|
sending.text);
|
||||||
|
|
||||||
MTPstring msgText(MTP_string(sending.text));
|
MTPstring msgText(MTP_string(sending.text));
|
||||||
auto flags = NewMessageFlags(peer);
|
auto flags = NewMessageFlags(peer);
|
||||||
|
@ -3720,8 +3726,8 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||||
if (clearCloudDraft) {
|
if (clearCloudDraft) {
|
||||||
sendFlags |= MTPmessages_SendMessage::Flag::f_clear_draft;
|
sendFlags |= MTPmessages_SendMessage::Flag::f_clear_draft;
|
||||||
mediaFlags |= MTPmessages_SendMedia::Flag::f_clear_draft;
|
mediaFlags |= MTPmessages_SendMedia::Flag::f_clear_draft;
|
||||||
history->clearCloudDraft(topicRootId);
|
history->clearCloudDraft(draftTopicRootId);
|
||||||
history->startSavingCloudDraft(topicRootId);
|
history->startSavingCloudDraft(draftTopicRootId);
|
||||||
}
|
}
|
||||||
const auto sendAs = action.options.sendAs;
|
const auto sendAs = action.options.sendAs;
|
||||||
const auto messageFromId = sendAs
|
const auto messageFromId = sendAs
|
||||||
|
@ -3758,7 +3764,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||||
const MTP::Response &response) {
|
const MTP::Response &response) {
|
||||||
if (clearCloudDraft) {
|
if (clearCloudDraft) {
|
||||||
history->finishSavingCloudDraft(
|
history->finishSavingCloudDraft(
|
||||||
topicRootId,
|
draftTopicRootId,
|
||||||
UnixtimeFromMsgId(response.outerMsgId));
|
UnixtimeFromMsgId(response.outerMsgId));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -3772,7 +3778,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||||
}
|
}
|
||||||
if (clearCloudDraft) {
|
if (clearCloudDraft) {
|
||||||
history->finishSavingCloudDraft(
|
history->finishSavingCloudDraft(
|
||||||
topicRootId,
|
draftTopicRootId,
|
||||||
UnixtimeFromMsgId(response.outerMsgId));
|
UnixtimeFromMsgId(response.outerMsgId));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -4340,6 +4346,32 @@ void ApiWrap::saveSelfBio(const QString &text) {
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ApiWrap::registerStatsRequest(MTP::DcId dcId, mtpRequestId id) {
|
||||||
|
_statsRequests[dcId].emplace(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApiWrap::unregisterStatsRequest(MTP::DcId dcId, mtpRequestId id) {
|
||||||
|
const auto i = _statsRequests.find(dcId);
|
||||||
|
Assert(i != end(_statsRequests));
|
||||||
|
const auto removed = i->second.remove(id);
|
||||||
|
Assert(removed);
|
||||||
|
if (i->second.empty()) {
|
||||||
|
_statsSessionKillTimer.callOnce(kStatsSessionKillTimeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApiWrap::checkStatsSessions() {
|
||||||
|
for (auto i = begin(_statsRequests); i != end(_statsRequests);) {
|
||||||
|
if (i->second.empty()) {
|
||||||
|
instance().killSession(
|
||||||
|
MTP::ShiftDcId(i->first, MTP::kStatsDcShift));
|
||||||
|
i = _statsRequests.erase(i);
|
||||||
|
} else {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Api::Authorizations &ApiWrap::authorizations() {
|
Api::Authorizations &ApiWrap::authorizations() {
|
||||||
return *_authorizations;
|
return *_authorizations;
|
||||||
}
|
}
|
||||||
|
|
|
@ -369,6 +369,9 @@ public:
|
||||||
|
|
||||||
void saveSelfBio(const QString &text);
|
void saveSelfBio(const QString &text);
|
||||||
|
|
||||||
|
void registerStatsRequest(MTP::DcId dcId, mtpRequestId id);
|
||||||
|
void unregisterStatsRequest(MTP::DcId dcId, mtpRequestId id);
|
||||||
|
|
||||||
[[nodiscard]] Api::Authorizations &authorizations();
|
[[nodiscard]] Api::Authorizations &authorizations();
|
||||||
[[nodiscard]] Api::AttachedStickers &attachedStickers();
|
[[nodiscard]] Api::AttachedStickers &attachedStickers();
|
||||||
[[nodiscard]] Api::BlockedPeers &blockedPeers();
|
[[nodiscard]] Api::BlockedPeers &blockedPeers();
|
||||||
|
@ -547,6 +550,8 @@ private:
|
||||||
not_null<ChannelData*> channel);
|
not_null<ChannelData*> channel);
|
||||||
void migrateFail(not_null<PeerData*> peer, const QString &error);
|
void migrateFail(not_null<PeerData*> peer, const QString &error);
|
||||||
|
|
||||||
|
void checkStatsSessions();
|
||||||
|
|
||||||
const not_null<Main::Session*> _session;
|
const not_null<Main::Session*> _session;
|
||||||
|
|
||||||
base::flat_map<QString, int> _modifyRequests;
|
base::flat_map<QString, int> _modifyRequests;
|
||||||
|
@ -683,6 +688,9 @@ private:
|
||||||
QString requestedText;
|
QString requestedText;
|
||||||
} _bio;
|
} _bio;
|
||||||
|
|
||||||
|
base::flat_map<MTP::DcId, base::flat_set<mtpRequestId>> _statsRequests;
|
||||||
|
base::Timer _statsSessionKillTimer;
|
||||||
|
|
||||||
const std::unique_ptr<Api::Authorizations> _authorizations;
|
const std::unique_ptr<Api::Authorizations> _authorizations;
|
||||||
const std::unique_ptr<Api::AttachedStickers> _attachedStickers;
|
const std::unique_ptr<Api::AttachedStickers> _attachedStickers;
|
||||||
const std::unique_ptr<Api::BlockedPeers> _blockedPeers;
|
const std::unique_ptr<Api::BlockedPeers> _blockedPeers;
|
||||||
|
|
|
@ -827,11 +827,13 @@ historyEmojiStatusInfoLabel: FlatLabel(historyContactStatusLabel) {
|
||||||
}
|
}
|
||||||
historyContactStatusMinSkip: 16px;
|
historyContactStatusMinSkip: 16px;
|
||||||
|
|
||||||
historyReplySkip: 51px;
|
historyReplySkip: 53px;
|
||||||
historyReplyNameFg: windowActiveTextFg;
|
historyReplyNameFg: windowActiveTextFg;
|
||||||
historyReplyHeight: 49px;
|
historyReplyHeight: 49px;
|
||||||
historyReplyIconPosition: point(5px, 5px);
|
historyReplyIconPosition: point(7px, 7px);
|
||||||
historyReplyIcon: icon {{ "chat/input_reply", historyReplyIconFg }};
|
historyReplyIcon: icon {{ "chat/input_reply_settings", historyReplyIconFg }};
|
||||||
|
historyLinkIcon: icon {{ "chat/input_link_settings", historyReplyIconFg }};
|
||||||
|
historyQuoteIcon: icon {{ "chat/input_reply_quote", historyReplyIconFg }};
|
||||||
historyForwardIcon: icon {{ "chat/input_forward", historyReplyIconFg }};
|
historyForwardIcon: icon {{ "chat/input_forward", historyReplyIconFg }};
|
||||||
historyEditIcon: icon {{ "chat/input_edit", historyReplyIconFg }};
|
historyEditIcon: icon {{ "chat/input_edit", historyReplyIconFg }};
|
||||||
historyReplyCancel: IconButton {
|
historyReplyCancel: IconButton {
|
||||||
|
|
|
@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D666}"_cs;
|
||||||
constexpr auto AppNameOld = "AyuGram for Windows"_cs;
|
constexpr auto AppNameOld = "AyuGram for Windows"_cs;
|
||||||
constexpr auto AppName = "AyuGram Desktop"_cs;
|
constexpr auto AppName = "AyuGram Desktop"_cs;
|
||||||
constexpr auto AppFile = "AyuGram"_cs;
|
constexpr auto AppFile = "AyuGram"_cs;
|
||||||
constexpr auto AppVersion = 4011006;
|
constexpr auto AppVersion = 4011007;
|
||||||
constexpr auto AppVersionStr = "4.11.6";
|
constexpr auto AppVersionStr = "4.11.7";
|
||||||
constexpr auto AppBetaVersion = false;
|
constexpr auto AppBetaVersion = false;
|
||||||
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
|
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
|
||||||
|
|
|
@ -1120,6 +1120,10 @@ void ApplyChannelUpdate(
|
||||||
channel,
|
channel,
|
||||||
update.vnotify_settings());
|
update.vnotify_settings());
|
||||||
|
|
||||||
|
if (update.vstats_dc()) {
|
||||||
|
channel->owner().applyStatsDcId(channel, update.vstats_dc()->v);
|
||||||
|
}
|
||||||
|
|
||||||
if (const auto sendAs = update.vdefault_send_as()) {
|
if (const auto sendAs = update.vdefault_send_as()) {
|
||||||
session->sendAsPeers().setChosen(channel, peerFromMTP(*sendAs));
|
session->sendAsPeers().setChosen(channel, peerFromMTP(*sendAs));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -4567,6 +4567,19 @@ uint64 Session::wallpapersHash() const {
|
||||||
return _wallpapersHash;
|
return _wallpapersHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MTP::DcId Session::statsDcId(not_null<ChannelData*> channel) {
|
||||||
|
const auto it = _channelStatsDcIds.find(channel);
|
||||||
|
return (it == end(_channelStatsDcIds)) ? MTP::DcId(0) : it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::applyStatsDcId(
|
||||||
|
not_null<ChannelData*> channel,
|
||||||
|
MTP::DcId dcId) {
|
||||||
|
if (dcId != channel->session().mainDcId()) {
|
||||||
|
_channelStatsDcIds[channel] = dcId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Session::webViewResultSent(WebViewResultSent &&sent) {
|
void Session::webViewResultSent(WebViewResultSent &&sent) {
|
||||||
return _webViewResultSent.fire(std::move(sent));
|
return _webViewResultSent.fire(std::move(sent));
|
||||||
}
|
}
|
||||||
|
|
|
@ -730,6 +730,9 @@ public:
|
||||||
[[nodiscard]] auto peerDecorationsUpdated() const
|
[[nodiscard]] auto peerDecorationsUpdated() const
|
||||||
-> rpl::producer<not_null<PeerData*>>;
|
-> rpl::producer<not_null<PeerData*>>;
|
||||||
|
|
||||||
|
void applyStatsDcId(not_null<ChannelData*>, MTP::DcId);
|
||||||
|
[[nodiscard]] MTP::DcId statsDcId(not_null<ChannelData*>);
|
||||||
|
|
||||||
void clearLocalStorage();
|
void clearLocalStorage();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1014,6 +1017,8 @@ private:
|
||||||
base::flat_map<not_null<UserData*>, TimeId> _watchingForOffline;
|
base::flat_map<not_null<UserData*>, TimeId> _watchingForOffline;
|
||||||
base::Timer _watchForOfflineTimer;
|
base::Timer _watchForOfflineTimer;
|
||||||
|
|
||||||
|
base::flat_map<not_null<ChannelData*>, MTP::DcId> _channelStatsDcIds;
|
||||||
|
|
||||||
rpl::event_stream<WebViewResultSent> _webViewResultSent;
|
rpl::event_stream<WebViewResultSent> _webViewResultSent;
|
||||||
|
|
||||||
rpl::event_stream<not_null<PeerData*>> _peerDecorationsUpdated;
|
rpl::event_stream<not_null<PeerData*>> _peerDecorationsUpdated;
|
||||||
|
|
|
@ -879,7 +879,7 @@ void RowPainter::Paint(
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}();
|
}();
|
||||||
const auto previewOptions = [&]() -> HistoryView::ToPreviewOptions {
|
auto previewOptions = [&]() -> HistoryView::ToPreviewOptions {
|
||||||
if (topic) {
|
if (topic) {
|
||||||
return {};
|
return {};
|
||||||
} else if (const auto searchChat = row->searchInChat()) {
|
} else if (const auto searchChat = row->searchInChat()) {
|
||||||
|
@ -891,6 +891,7 @@ void RowPainter::Paint(
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}();
|
}();
|
||||||
|
previewOptions.ignoreGroup = true;
|
||||||
|
|
||||||
const auto badgesState = context.displayUnreadInfo
|
const auto badgesState = context.displayUnreadInfo
|
||||||
? entry->chatListBadgesState()
|
? entry->chatListBadgesState()
|
||||||
|
|
|
@ -2956,11 +2956,22 @@ FullStoryId HistoryItem::replyToStory() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
FullReplyTo HistoryItem::replyTo() const {
|
FullReplyTo HistoryItem::replyTo() const {
|
||||||
return {
|
auto result = FullReplyTo{
|
||||||
.messageId = replyToFullId(),
|
|
||||||
.storyId = replyToStory(),
|
|
||||||
.topicRootId = topicRootId(),
|
.topicRootId = topicRootId(),
|
||||||
};
|
};
|
||||||
|
if (const auto reply = Get<HistoryMessageReply>()) {
|
||||||
|
const auto &fields = reply->fields();
|
||||||
|
const auto peer = fields.externalPeerId;
|
||||||
|
const auto replyToPeer = peer ? peer : _history->peer->id;
|
||||||
|
if (const auto id = fields.messageId) {
|
||||||
|
result.messageId = { replyToPeer, id };
|
||||||
|
result.quote = fields.quote;
|
||||||
|
}
|
||||||
|
if (const auto id = fields.storyId) {
|
||||||
|
result.storyId = { replyToPeer, id };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryItem::setText(const TextWithEntities &textWithEntities) {
|
void HistoryItem::setText(const TextWithEntities &textWithEntities) {
|
||||||
|
|
|
@ -101,6 +101,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "history/view/history_view_pinned_bar.h"
|
#include "history/view/history_view_pinned_bar.h"
|
||||||
#include "history/view/history_view_group_call_bar.h"
|
#include "history/view/history_view_group_call_bar.h"
|
||||||
#include "history/view/history_view_item_preview.h"
|
#include "history/view/history_view_item_preview.h"
|
||||||
|
#include "history/view/history_view_reply.h"
|
||||||
#include "history/view/history_view_requests_bar.h"
|
#include "history/view/history_view_requests_bar.h"
|
||||||
#include "history/view/history_view_sticker_toast.h"
|
#include "history/view/history_view_sticker_toast.h"
|
||||||
#include "history/view/history_view_translate_bar.h"
|
#include "history/view/history_view_translate_bar.h"
|
||||||
|
@ -4395,11 +4396,10 @@ void HistoryWidget::mouseMoveEvent(QMouseEvent *e) {
|
||||||
|
|
||||||
void HistoryWidget::updateOverStates(QPoint pos) {
|
void HistoryWidget::updateOverStates(QPoint pos) {
|
||||||
const auto isReadyToForward = readyToForward();
|
const auto isReadyToForward = readyToForward();
|
||||||
const auto skip = isReadyToForward ? 0 : st::historyReplySkip;
|
|
||||||
const auto detailsRect = QRect(
|
const auto detailsRect = QRect(
|
||||||
skip,
|
0,
|
||||||
_field->y() - st::historySendPadding - st::historyReplyHeight,
|
_field->y() - st::historySendPadding - st::historyReplyHeight,
|
||||||
width() - skip - _fieldBarCancel->width(),
|
width() - _fieldBarCancel->width(),
|
||||||
st::historyReplyHeight);
|
st::historyReplyHeight);
|
||||||
const auto hasWebPage = !!_previewDrawPreview;
|
const auto hasWebPage = !!_previewDrawPreview;
|
||||||
const auto inDetails = detailsRect.contains(pos)
|
const auto inDetails = detailsRect.contains(pos)
|
||||||
|
@ -4439,10 +4439,6 @@ void HistoryWidget::leaveToChildEvent(QEvent *e, QWidget *child) { // e -- from
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::mouseReleaseEvent(QMouseEvent *e) {
|
void HistoryWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
if (_replyForwardPressed) {
|
|
||||||
_replyForwardPressed = false;
|
|
||||||
update(0, _field->y() - st::historySendPadding - st::historyReplyHeight, width(), st::historyReplyHeight);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::sendBotCommand(const Bot::SendCommandRequest &request) {
|
void HistoryWidget::sendBotCommand(const Bot::SendCommandRequest &request) {
|
||||||
|
@ -6264,20 +6260,7 @@ bool HistoryWidget::cornerButtonsHas(HistoryView::CornerButtonType type) {
|
||||||
|
|
||||||
void HistoryWidget::mousePressEvent(QMouseEvent *e) {
|
void HistoryWidget::mousePressEvent(QMouseEvent *e) {
|
||||||
const auto isReadyToForward = readyToForward();
|
const auto isReadyToForward = readyToForward();
|
||||||
const auto hasSecondLayer = (_editMsgId
|
if (_inPhotoEdit && _photoEditMedia) {
|
||||||
|| _replyTo
|
|
||||||
|| isReadyToForward
|
|
||||||
|| _kbReplyTo);
|
|
||||||
_replyForwardPressed = hasSecondLayer && QRect(
|
|
||||||
0,
|
|
||||||
_field->y() - st::historySendPadding - st::historyReplyHeight,
|
|
||||||
st::historyReplySkip,
|
|
||||||
st::historyReplyHeight).contains(e->pos());
|
|
||||||
if (_replyForwardPressed
|
|
||||||
&& !_fieldBarCancel->isHidden()
|
|
||||||
&& !isReadyToForward) {
|
|
||||||
updateField();
|
|
||||||
} else if (_inPhotoEdit && _photoEditMedia) {
|
|
||||||
EditCaptionBox::StartPhotoEdit(
|
EditCaptionBox::StartPhotoEdit(
|
||||||
controller(),
|
controller(),
|
||||||
_photoEditMedia,
|
_photoEditMedia,
|
||||||
|
@ -7507,7 +7490,6 @@ void HistoryWidget::cancelEdit() {
|
||||||
|
|
||||||
void HistoryWidget::cancelFieldAreaState() {
|
void HistoryWidget::cancelFieldAreaState() {
|
||||||
controller()->hideLayer();
|
controller()->hideLayer();
|
||||||
_replyForwardPressed = false;
|
|
||||||
if (_previewDrawPreview) {
|
if (_previewDrawPreview) {
|
||||||
_preview->apply({ .removed = true });
|
_preview->apply({ .removed = true });
|
||||||
} else if (_editMsgId) {
|
} else if (_editMsgId) {
|
||||||
|
@ -7839,25 +7821,23 @@ void HistoryWidget::updateForwarding() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::updateReplyToName() {
|
void HistoryWidget::updateReplyToName() {
|
||||||
if (_editMsgId) {
|
if (!_history || _editMsgId) {
|
||||||
return;
|
return;
|
||||||
} else if (!_replyEditMsg && (_replyTo || !_kbReplyTo)) {
|
} else if (!_replyEditMsg && (_replyTo || !_kbReplyTo)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto from = [&] {
|
const auto context = Core::MarkedTextContext{
|
||||||
const auto item = _replyEditMsg ? _replyEditMsg : _kbReplyTo;
|
.session = &_history->session(),
|
||||||
if (const auto from = item->displayFrom()) {
|
.customEmojiRepaint = [] {},
|
||||||
return from;
|
.customEmojiLoopLimit = 1,
|
||||||
}
|
};
|
||||||
return item->author().get();
|
const auto to = _replyEditMsg ? _replyEditMsg : _kbReplyTo;
|
||||||
}();
|
const auto replyToQuote = _replyTo && !_replyTo.quote.empty();
|
||||||
_replyToName.setText(
|
_replyToName.setMarkedText(
|
||||||
st::msgNameStyle,
|
st::fwdTextStyle,
|
||||||
from->name(),
|
HistoryView::Reply::ComposePreviewName(_history, to, replyToQuote),
|
||||||
Ui::NameTextOptions());
|
Ui::NameTextOptions(),
|
||||||
_replyToNameVersion = (_replyEditMsg
|
context);
|
||||||
? _replyEditMsg
|
|
||||||
: _kbReplyTo)->author()->nameVersion();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::updateField() {
|
void HistoryWidget::updateField() {
|
||||||
|
@ -7877,12 +7857,6 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
||||||
auto hasForward = readyToForward();
|
auto hasForward = readyToForward();
|
||||||
auto drawMsgText = (_editMsgId || _replyTo) ? _replyEditMsg : _kbReplyTo;
|
auto drawMsgText = (_editMsgId || _replyTo) ? _replyEditMsg : _kbReplyTo;
|
||||||
if (_editMsgId || _replyTo || (!hasForward && _kbReplyTo)) {
|
if (_editMsgId || _replyTo || (!hasForward && _kbReplyTo)) {
|
||||||
if (!_editMsgId
|
|
||||||
&& drawMsgText
|
|
||||||
&& (_replyToNameVersion
|
|
||||||
< drawMsgText->author()->nameVersion())) {
|
|
||||||
updateReplyToName();
|
|
||||||
}
|
|
||||||
backy -= st::historyReplyHeight;
|
backy -= st::historyReplyHeight;
|
||||||
backh += st::historyReplyHeight;
|
backh += st::historyReplyHeight;
|
||||||
} else if (hasForward) {
|
} else if (hasForward) {
|
||||||
|
@ -7892,12 +7866,11 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
||||||
backy -= st::historyReplyHeight;
|
backy -= st::historyReplyHeight;
|
||||||
backh += st::historyReplyHeight;
|
backh += st::historyReplyHeight;
|
||||||
}
|
}
|
||||||
auto drawWebPagePreview = _previewDrawPreview && !_replyForwardPressed;
|
|
||||||
p.setInactive(
|
p.setInactive(
|
||||||
controller()->isGifPausedAtLeastFor(Window::GifPauseReason::Any));
|
controller()->isGifPausedAtLeastFor(Window::GifPauseReason::Any));
|
||||||
p.fillRect(myrtlrect(0, backy, width(), backh), st::historyReplyBg);
|
p.fillRect(myrtlrect(0, backy, width(), backh), st::historyReplyBg);
|
||||||
|
|
||||||
const auto media = (!drawWebPagePreview && drawMsgText)
|
const auto media = (!_previewDrawPreview && drawMsgText)
|
||||||
? drawMsgText->media()
|
? drawMsgText->media()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
const auto hasPreview = media && media->hasReplyPreview();
|
const auto hasPreview = media && media->hasReplyPreview();
|
||||||
|
@ -7911,86 +7884,11 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_editMsgId || _replyTo || (!hasForward && _kbReplyTo)) {
|
if (_previewDrawPreview) {
|
||||||
const auto now = crl::now();
|
st::historyLinkIcon.paint(
|
||||||
const auto paused = p.inactive();
|
p,
|
||||||
const auto pausedSpoiler = paused || On(PowerSaving::kChatSpoiler);
|
st::historyReplyIconPosition + QPoint(0, backy),
|
||||||
auto replyLeft = st::historyReplySkip;
|
width());
|
||||||
(_editMsgId ? st::historyEditIcon : st::historyReplyIcon).paint(p, st::historyReplyIconPosition + QPoint(0, backy), width());
|
|
||||||
if (!drawWebPagePreview) {
|
|
||||||
if (drawMsgText) {
|
|
||||||
if (hasPreview) {
|
|
||||||
if (preview) {
|
|
||||||
const auto overEdit = _photoEditMedia
|
|
||||||
? _inPhotoEditOver.value(_inPhotoEdit ? 1. : 0.)
|
|
||||||
: 0.;
|
|
||||||
auto to = QRect(
|
|
||||||
replyLeft,
|
|
||||||
backy + (st::historyReplyHeight - st::historyReplyPreview) / 2,
|
|
||||||
st::historyReplyPreview,
|
|
||||||
st::historyReplyPreview);
|
|
||||||
p.drawPixmap(to.x(), to.y(), preview->pixSingle(
|
|
||||||
preview->size() / style::DevicePixelRatio(),
|
|
||||||
{
|
|
||||||
.options = Images::Option::RoundSmall,
|
|
||||||
.outer = to.size(),
|
|
||||||
}));
|
|
||||||
if (_replySpoiler) {
|
|
||||||
if (overEdit > 0.) {
|
|
||||||
p.setOpacity(1. - overEdit);
|
|
||||||
}
|
|
||||||
Ui::FillSpoilerRect(
|
|
||||||
p,
|
|
||||||
to,
|
|
||||||
Ui::DefaultImageSpoiler().frame(
|
|
||||||
_replySpoiler->index(now, pausedSpoiler)));
|
|
||||||
}
|
|
||||||
if (overEdit > 0.) {
|
|
||||||
p.setOpacity(overEdit);
|
|
||||||
p.fillRect(to, st::historyEditMediaBg);
|
|
||||||
st::historyEditMedia.paintInCenter(p, to);
|
|
||||||
p.setOpacity(1.);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
replyLeft += st::historyReplyPreview + st::msgReplyBarSkip;
|
|
||||||
}
|
|
||||||
p.setPen(st::historyReplyNameFg);
|
|
||||||
if (_editMsgId) {
|
|
||||||
paintEditHeader(p, rect, replyLeft, backy);
|
|
||||||
} else {
|
|
||||||
_replyToName.drawElided(p, replyLeft, backy + st::msgReplyPadding.top(), width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right());
|
|
||||||
}
|
|
||||||
p.setPen(st::historyComposeAreaFg);
|
|
||||||
_replyEditMsgText.draw(p, {
|
|
||||||
.position = QPoint(
|
|
||||||
replyLeft,
|
|
||||||
backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height),
|
|
||||||
.availableWidth = width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right(),
|
|
||||||
.palette = &st::historyComposeAreaPalette,
|
|
||||||
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
|
||||||
.now = now,
|
|
||||||
.pausedEmoji = paused || On(PowerSaving::kEmojiChat),
|
|
||||||
.pausedSpoiler = pausedSpoiler,
|
|
||||||
.elisionLines = 1,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
p.setFont(st::msgDateFont);
|
|
||||||
p.setPen(st::historyComposeAreaFgService);
|
|
||||||
p.drawText(replyLeft, backy + (st::historyReplyHeight - st::msgDateFont->height) / 2 + st::msgDateFont->ascent, st::msgDateFont->elided(tr::lng_profile_loading(tr::now), width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (hasForward) {
|
|
||||||
st::historyForwardIcon.paint(p, st::historyReplyIconPosition + QPoint(0, backy), width());
|
|
||||||
if (!drawWebPagePreview) {
|
|
||||||
const auto x = st::historyReplySkip;
|
|
||||||
const auto available = width()
|
|
||||||
- x
|
|
||||||
- _fieldBarCancel->width()
|
|
||||||
- st::msgReplyPadding.right();
|
|
||||||
_forwardPanel->paint(p, x, backy, available, width());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (drawWebPagePreview) {
|
|
||||||
const auto textTop = backy + st::msgReplyPadding.top();
|
const auto textTop = backy + st::msgReplyPadding.top();
|
||||||
auto previewLeft = st::historyReplySkip;
|
auto previewLeft = st::historyReplySkip;
|
||||||
|
|
||||||
|
@ -8019,6 +7917,87 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
||||||
previewLeft,
|
previewLeft,
|
||||||
textTop + st::msgServiceNameFont->height,
|
textTop + st::msgServiceNameFont->height,
|
||||||
elidedWidth);
|
elidedWidth);
|
||||||
|
} else if (_editMsgId || _replyTo || (!hasForward && _kbReplyTo)) {
|
||||||
|
const auto now = crl::now();
|
||||||
|
const auto paused = p.inactive();
|
||||||
|
const auto pausedSpoiler = paused || On(PowerSaving::kChatSpoiler);
|
||||||
|
auto replyLeft = st::historyReplySkip;
|
||||||
|
(_editMsgId
|
||||||
|
? st::historyEditIcon
|
||||||
|
: (_replyTo && !_replyTo.quote.empty())
|
||||||
|
? st::historyQuoteIcon
|
||||||
|
: st::historyReplyIcon).paint(
|
||||||
|
p,
|
||||||
|
st::historyReplyIconPosition + QPoint(0, backy),
|
||||||
|
width());
|
||||||
|
if (drawMsgText) {
|
||||||
|
if (hasPreview) {
|
||||||
|
if (preview) {
|
||||||
|
const auto overEdit = _photoEditMedia
|
||||||
|
? _inPhotoEditOver.value(_inPhotoEdit ? 1. : 0.)
|
||||||
|
: 0.;
|
||||||
|
auto to = QRect(
|
||||||
|
replyLeft,
|
||||||
|
backy + (st::historyReplyHeight - st::historyReplyPreview) / 2,
|
||||||
|
st::historyReplyPreview,
|
||||||
|
st::historyReplyPreview);
|
||||||
|
p.drawPixmap(to.x(), to.y(), preview->pixSingle(
|
||||||
|
preview->size() / style::DevicePixelRatio(),
|
||||||
|
{
|
||||||
|
.options = Images::Option::RoundSmall,
|
||||||
|
.outer = to.size(),
|
||||||
|
}));
|
||||||
|
if (_replySpoiler) {
|
||||||
|
if (overEdit > 0.) {
|
||||||
|
p.setOpacity(1. - overEdit);
|
||||||
|
}
|
||||||
|
Ui::FillSpoilerRect(
|
||||||
|
p,
|
||||||
|
to,
|
||||||
|
Ui::DefaultImageSpoiler().frame(
|
||||||
|
_replySpoiler->index(now, pausedSpoiler)));
|
||||||
|
}
|
||||||
|
if (overEdit > 0.) {
|
||||||
|
p.setOpacity(overEdit);
|
||||||
|
p.fillRect(to, st::historyEditMediaBg);
|
||||||
|
st::historyEditMedia.paintInCenter(p, to);
|
||||||
|
p.setOpacity(1.);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
replyLeft += st::historyReplyPreview + st::msgReplyBarSkip;
|
||||||
|
}
|
||||||
|
p.setPen(st::historyReplyNameFg);
|
||||||
|
if (_editMsgId) {
|
||||||
|
paintEditHeader(p, rect, replyLeft, backy);
|
||||||
|
} else {
|
||||||
|
_replyToName.drawElided(p, replyLeft, backy + st::msgReplyPadding.top(), width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right());
|
||||||
|
}
|
||||||
|
p.setPen(st::historyComposeAreaFg);
|
||||||
|
_replyEditMsgText.draw(p, {
|
||||||
|
.position = QPoint(
|
||||||
|
replyLeft,
|
||||||
|
backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height),
|
||||||
|
.availableWidth = width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right(),
|
||||||
|
.palette = &st::historyComposeAreaPalette,
|
||||||
|
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
||||||
|
.now = now,
|
||||||
|
.pausedEmoji = paused || On(PowerSaving::kEmojiChat),
|
||||||
|
.pausedSpoiler = pausedSpoiler,
|
||||||
|
.elisionLines = 1,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
p.setFont(st::msgDateFont);
|
||||||
|
p.setPen(st::historyComposeAreaFgService);
|
||||||
|
p.drawText(replyLeft, backy + (st::historyReplyHeight - st::msgDateFont->height) / 2 + st::msgDateFont->ascent, st::msgDateFont->elided(tr::lng_profile_loading(tr::now), width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right()));
|
||||||
|
}
|
||||||
|
} else if (hasForward) {
|
||||||
|
st::historyForwardIcon.paint(p, st::historyReplyIconPosition + QPoint(0, backy), width());
|
||||||
|
const auto x = st::historyReplySkip;
|
||||||
|
const auto available = width()
|
||||||
|
- x
|
||||||
|
- _fieldBarCancel->width()
|
||||||
|
- st::msgReplyPadding.right();
|
||||||
|
_forwardPanel->paint(p, x, backy, available, width());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -647,7 +647,6 @@ private:
|
||||||
MTP::Sender _api;
|
MTP::Sender _api;
|
||||||
FullReplyTo _replyTo;
|
FullReplyTo _replyTo;
|
||||||
Ui::Text::String _replyToName;
|
Ui::Text::String _replyToName;
|
||||||
int _replyToNameVersion = 0;
|
|
||||||
|
|
||||||
FullReplyTo _processingReplyTo;
|
FullReplyTo _processingReplyTo;
|
||||||
HistoryItem *_processingReplyItem = nullptr;
|
HistoryItem *_processingReplyItem = nullptr;
|
||||||
|
@ -688,8 +687,6 @@ private:
|
||||||
Ui::Text::String _previewTitle;
|
Ui::Text::String _previewTitle;
|
||||||
Ui::Text::String _previewDescription;
|
Ui::Text::String _previewDescription;
|
||||||
|
|
||||||
bool _replyForwardPressed = false;
|
|
||||||
|
|
||||||
PeerData *_peer = nullptr;
|
PeerData *_peer = nullptr;
|
||||||
|
|
||||||
bool _canSendMessages = false;
|
bool _canSendMessages = false;
|
||||||
|
|
|
@ -51,6 +51,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "history/view/controls/history_view_voice_record_bar.h"
|
#include "history/view/controls/history_view_voice_record_bar.h"
|
||||||
#include "history/view/controls/history_view_ttl_button.h"
|
#include "history/view/controls/history_view_ttl_button.h"
|
||||||
#include "history/view/controls/history_view_webpage_processor.h"
|
#include "history/view/controls/history_view_webpage_processor.h"
|
||||||
|
#include "history/view/history_view_reply.h"
|
||||||
#include "history/view/history_view_webpage_preview.h"
|
#include "history/view/history_view_webpage_preview.h"
|
||||||
#include "inline_bots/bot_attach_web_view.h"
|
#include "inline_bots/bot_attach_web_view.h"
|
||||||
#include "inline_bots/inline_results_widget.h"
|
#include "inline_bots/inline_results_widget.h"
|
||||||
|
@ -192,7 +193,6 @@ private:
|
||||||
Ui::Text::String _shownMessageText;
|
Ui::Text::String _shownMessageText;
|
||||||
std::unique_ptr<Ui::SpoilerAnimation> _shownPreviewSpoiler;
|
std::unique_ptr<Ui::SpoilerAnimation> _shownPreviewSpoiler;
|
||||||
Ui::Animations::Simple _inPhotoEditOver;
|
Ui::Animations::Simple _inPhotoEditOver;
|
||||||
int _shownMessageNameVersion = -1;
|
|
||||||
bool _shownMessageHasPreview : 1 = false;
|
bool _shownMessageHasPreview : 1 = false;
|
||||||
bool _inPhotoEdit : 1 = false;
|
bool _inPhotoEdit : 1 = false;
|
||||||
bool _photoEditAllowed : 1 = false;
|
bool _photoEditAllowed : 1 = false;
|
||||||
|
@ -245,7 +245,6 @@ void FieldHeader::init() {
|
||||||
updateVisible();
|
updateVisible();
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
const auto leftIconPressed = lifetime().make_state<bool>(false);
|
|
||||||
paintRequest(
|
paintRequest(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
|
@ -253,21 +252,29 @@ void FieldHeader::init() {
|
||||||
p.fillRect(rect(), st::historyComposeAreaBg);
|
p.fillRect(rect(), st::historyComposeAreaBg);
|
||||||
|
|
||||||
const auto position = st::historyReplyIconPosition;
|
const auto position = st::historyReplyIconPosition;
|
||||||
if (isEditingMessage()) {
|
if (_preview.parsed) {
|
||||||
|
st::historyLinkIcon.paint(p, position, width());
|
||||||
|
} else if (isEditingMessage()) {
|
||||||
st::historyEditIcon.paint(p, position, width());
|
st::historyEditIcon.paint(p, position, width());
|
||||||
} else if (readyToForward()) {
|
} else if (readyToForward()) {
|
||||||
st::historyForwardIcon.paint(p, position, width());
|
st::historyForwardIcon.paint(p, position, width());
|
||||||
} else if (replyingToMessage()) {
|
} else if (const auto reply = replyingToMessage()) {
|
||||||
st::historyReplyIcon.paint(p, position, width());
|
if (!reply.quote.empty()) {
|
||||||
|
st::historyQuoteIcon.paint(p, position, width());
|
||||||
|
} else {
|
||||||
|
st::historyReplyIcon.paint(p, position, width());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(_preview.parsed && !*leftIconPressed)
|
if (_preview.parsed) {
|
||||||
? paintWebPage(
|
paintWebPage(
|
||||||
p,
|
p,
|
||||||
_history ? _history->peer : _data->session().user())
|
_history ? _history->peer : _data->session().user());
|
||||||
: (isEditingMessage() || !readyToForward())
|
} else if (isEditingMessage() || !readyToForward()) {
|
||||||
? paintEditOrReplyToMessage(p)
|
paintEditOrReplyToMessage(p);
|
||||||
: paintForwardInfo(p);
|
} else {
|
||||||
|
paintForwardInfo(p);
|
||||||
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
_editMsgId.value(
|
_editMsgId.value(
|
||||||
|
@ -359,13 +366,9 @@ void FieldHeader::init() {
|
||||||
updateOver(inPreviewRect, inPhotoEdit);
|
updateOver(inPreviewRect, inPhotoEdit);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto isLeftIcon = (pos.x() < st::historyReplySkip);
|
|
||||||
const auto isLeftButton = (e->button() == Qt::LeftButton);
|
const auto isLeftButton = (e->button() == Qt::LeftButton);
|
||||||
if (type == QEvent::MouseButtonPress) {
|
if (type == QEvent::MouseButtonPress) {
|
||||||
if (isLeftButton && isLeftIcon && !inPreviewRect) {
|
if (isLeftButton && inPhotoEdit) {
|
||||||
*leftIconPressed = true;
|
|
||||||
update();
|
|
||||||
} else if (isLeftButton && inPhotoEdit) {
|
|
||||||
_editPhotoRequests.fire({});
|
_editPhotoRequests.fire({});
|
||||||
} else if (isLeftButton && inPreviewRect) {
|
} else if (isLeftButton && inPreviewRect) {
|
||||||
const auto reply = replyingToMessage();
|
const auto reply = replyingToMessage();
|
||||||
|
@ -384,11 +387,6 @@ void FieldHeader::init() {
|
||||||
_editOptionsRequests.fire({});
|
_editOptionsRequests.fire({});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (type == QEvent::MouseButtonRelease) {
|
|
||||||
if (isLeftButton && *leftIconPressed) {
|
|
||||||
*leftIconPressed = false;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
@ -431,9 +429,21 @@ void FieldHeader::setShownMessage(HistoryItem *item) {
|
||||||
st::msgNameStyle,
|
st::msgNameStyle,
|
||||||
tr::lng_edit_message(tr::now),
|
tr::lng_edit_message(tr::now),
|
||||||
Ui::NameTextOptions());
|
Ui::NameTextOptions());
|
||||||
|
} else if (item) {
|
||||||
|
const auto context = Core::MarkedTextContext{
|
||||||
|
.session = &_history->session(),
|
||||||
|
.customEmojiRepaint = [] {},
|
||||||
|
.customEmojiLoopLimit = 1,
|
||||||
|
};
|
||||||
|
const auto replyTo = _replyTo.current();
|
||||||
|
const auto quote = replyTo && !replyTo.quote.empty();
|
||||||
|
_shownMessageName.setMarkedText(
|
||||||
|
st::fwdTextStyle,
|
||||||
|
HistoryView::Reply::ComposePreviewName(_history, item, quote),
|
||||||
|
Ui::NameTextOptions(),
|
||||||
|
context);
|
||||||
} else {
|
} else {
|
||||||
_shownMessageName.clear();
|
_shownMessageName.clear();
|
||||||
_shownMessageNameVersion = -1;
|
|
||||||
}
|
}
|
||||||
updateVisible();
|
updateVisible();
|
||||||
update();
|
update();
|
||||||
|
@ -545,19 +555,6 @@ void FieldHeader::paintEditOrReplyToMessage(Painter &p) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isEditingMessage()) {
|
|
||||||
const auto user = _shownMessage->displayFrom()
|
|
||||||
? _shownMessage->displayFrom()
|
|
||||||
: _shownMessage->author().get();
|
|
||||||
if (_shownMessageNameVersion < user->nameVersion()) {
|
|
||||||
_shownMessageName.setText(
|
|
||||||
st::msgNameStyle,
|
|
||||||
user->name(),
|
|
||||||
Ui::NameTextOptions());
|
|
||||||
_shownMessageNameVersion = user->nameVersion();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto media = _shownMessage->media();
|
const auto media = _shownMessage->media();
|
||||||
_shownMessageHasPreview = media && media->hasReplyPreview();
|
_shownMessageHasPreview = media && media->hasReplyPreview();
|
||||||
const auto preview = _shownMessageHasPreview
|
const auto preview = _shownMessageHasPreview
|
||||||
|
@ -691,13 +688,11 @@ FullReplyTo FieldHeader::getDraftReply() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FieldHeader::updateControlsGeometry(QSize size) {
|
void FieldHeader::updateControlsGeometry(QSize size) {
|
||||||
const auto isReadyToForward = readyToForward();
|
|
||||||
const auto skip = isReadyToForward ? 0 : st::historyReplySkip;
|
|
||||||
_cancel->moveToRight(0, 0);
|
_cancel->moveToRight(0, 0);
|
||||||
_clickableRect = QRect(
|
_clickableRect = QRect(
|
||||||
skip,
|
|
||||||
0,
|
0,
|
||||||
width() - skip - _cancel->width(),
|
0,
|
||||||
|
width() - _cancel->width(),
|
||||||
height());
|
height());
|
||||||
_shownMessagePreviewRect = QRect(
|
_shownMessagePreviewRect = QRect(
|
||||||
st::historyReplySkip,
|
st::historyReplySkip,
|
||||||
|
|
|
@ -642,6 +642,8 @@ void DraftOptionsBox(
|
||||||
if (const auto current = state->quote.current()) {
|
if (const auto current = state->quote.current()) {
|
||||||
result.messageId = current.item->fullId();
|
result.messageId = current.item->fullId();
|
||||||
result.quote = current.text;
|
result.quote = current.text;
|
||||||
|
} else {
|
||||||
|
result.quote = {};
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1676,21 +1676,27 @@ TextSelection Element::FindSelectionFromQuote(
|
||||||
}
|
}
|
||||||
offset = i + 1;
|
offset = i + 1;
|
||||||
}
|
}
|
||||||
//for (const auto &modification : text.modifications()) {
|
for (const auto &modification : text.modifications()) {
|
||||||
// if (modification.position >= selection.to) {
|
if (modification.position >= result.to) {
|
||||||
// break;
|
break;
|
||||||
// } else if (modification.position <= selection.from) {
|
}
|
||||||
// modified.from += modification.skipped;
|
if (modification.added) {
|
||||||
// if (modification.added
|
++result.to;
|
||||||
// && modification.position < selection.from) {
|
}
|
||||||
// --modified.from;
|
const auto shiftTo = std::min(
|
||||||
// }
|
int(modification.skipped),
|
||||||
// }
|
result.to - modification.position);
|
||||||
// modified.to += modification.skipped;
|
result.to -= shiftTo;
|
||||||
// if (modification.added && modified.to > modified.from) {
|
if (modification.position <= result.from) {
|
||||||
// --modified.to;
|
if (modification.added) {
|
||||||
// }
|
++result.from;
|
||||||
//}
|
}
|
||||||
|
const auto shiftFrom = std::min(
|
||||||
|
int(modification.skipped),
|
||||||
|
result.from - modification.position);
|
||||||
|
result.from -= shiftFrom;
|
||||||
|
}
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -398,10 +398,11 @@ void Reply::updateName(
|
||||||
viaBotUsername = bot->username();
|
viaBotUsername = bot->username();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const auto history = view->history();
|
||||||
const auto &fields = data->fields();
|
const auto &fields = data->fields();
|
||||||
const auto sender = resolvedSender.value_or(this->sender(view, data));
|
const auto sender = resolvedSender.value_or(this->sender(view, data));
|
||||||
const auto externalPeer = fields.externalPeerId
|
const auto externalPeer = fields.externalPeerId
|
||||||
? view->history()->owner().peer(fields.externalPeerId).get()
|
? history->owner().peer(fields.externalPeerId).get()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
const auto displayAsExternal = data->displayAsExternal(view->data());
|
const auto displayAsExternal = data->displayAsExternal(view->data());
|
||||||
const auto groupNameAdded = displayAsExternal
|
const auto groupNameAdded = displayAsExternal
|
||||||
|
@ -419,38 +420,20 @@ void Reply::updateName(
|
||||||
+ st::historyReplyPreviewMargin.right()
|
+ st::historyReplyPreviewMargin.right()
|
||||||
- st::historyReplyPadding.left())
|
- st::historyReplyPadding.left())
|
||||||
: 0;
|
: 0;
|
||||||
const auto peerIcon = [](PeerData *peer) {
|
|
||||||
using namespace std;
|
|
||||||
return !peer
|
|
||||||
? pair(&st::historyReplyUser, st::historyReplyUserPadding)
|
|
||||||
: peer->isBroadcast()
|
|
||||||
? pair(&st::historyReplyChannel, st::historyReplyChannelPadding)
|
|
||||||
: (peer->isChannel() || peer->isChat())
|
|
||||||
? pair(&st::historyReplyGroup, st::historyReplyGroupPadding)
|
|
||||||
: pair(&st::historyReplyUser, st::historyReplyUserPadding);
|
|
||||||
};
|
|
||||||
const auto peerEmoji = [&](PeerData *peer) {
|
|
||||||
const auto owner = &view->history()->owner();
|
|
||||||
const auto icon = peerIcon(peer);
|
|
||||||
return Ui::Text::SingleCustomEmoji(
|
|
||||||
owner->customEmojiManager().registerInternalEmoji(
|
|
||||||
*icon.first,
|
|
||||||
icon.second));
|
|
||||||
};
|
|
||||||
auto nameFull = TextWithEntities();
|
auto nameFull = TextWithEntities();
|
||||||
if (displayAsExternal && !groupNameAdded && !fields.storyId) {
|
if (displayAsExternal && !groupNameAdded && !fields.storyId) {
|
||||||
nameFull.append(peerEmoji(sender));
|
nameFull.append(PeerEmoji(history, sender));
|
||||||
}
|
}
|
||||||
nameFull.append(name);
|
nameFull.append(name);
|
||||||
if (groupNameAdded) {
|
if (groupNameAdded) {
|
||||||
nameFull.append(' ').append(peerEmoji(externalPeer));
|
nameFull.append(' ').append(PeerEmoji(history, externalPeer));
|
||||||
nameFull.append(externalPeer->name());
|
nameFull.append(externalPeer->name());
|
||||||
}
|
}
|
||||||
if (!viaBotUsername.isEmpty()) {
|
if (!viaBotUsername.isEmpty()) {
|
||||||
nameFull.append(u" @"_q).append(viaBotUsername);
|
nameFull.append(u" @"_q).append(viaBotUsername);
|
||||||
}
|
}
|
||||||
const auto context = Core::MarkedTextContext{
|
const auto context = Core::MarkedTextContext{
|
||||||
.session = &view->history()->session(),
|
.session = &history->session(),
|
||||||
.customEmojiRepaint = [] {},
|
.customEmojiRepaint = [] {},
|
||||||
.customEmojiLoopLimit = 1,
|
.customEmojiLoopLimit = 1,
|
||||||
};
|
};
|
||||||
|
@ -819,6 +802,61 @@ void Reply::stopLastRipple() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextWithEntities Reply::PeerEmoji(
|
||||||
|
not_null<History*> history,
|
||||||
|
PeerData *peer) {
|
||||||
|
using namespace std;
|
||||||
|
const auto icon = !peer
|
||||||
|
? pair(&st::historyReplyUser, st::historyReplyUserPadding)
|
||||||
|
: peer->isBroadcast()
|
||||||
|
? pair(&st::historyReplyChannel, st::historyReplyChannelPadding)
|
||||||
|
: (peer->isChannel() || peer->isChat())
|
||||||
|
? pair(&st::historyReplyGroup, st::historyReplyGroupPadding)
|
||||||
|
: pair(&st::historyReplyUser, st::historyReplyUserPadding);
|
||||||
|
const auto owner = &history->owner();
|
||||||
|
return Ui::Text::SingleCustomEmoji(
|
||||||
|
owner->customEmojiManager().registerInternalEmoji(
|
||||||
|
*icon.first,
|
||||||
|
icon.second));
|
||||||
|
}
|
||||||
|
|
||||||
|
TextWithEntities Reply::ComposePreviewName(
|
||||||
|
not_null<History*> history,
|
||||||
|
not_null<HistoryItem*> to,
|
||||||
|
bool quote) {
|
||||||
|
const auto sender = [&] {
|
||||||
|
if (const auto from = to->displayFrom()) {
|
||||||
|
return not_null(from);
|
||||||
|
}
|
||||||
|
return to->author();
|
||||||
|
}();
|
||||||
|
const auto toPeer = to->history()->peer;
|
||||||
|
const auto displayAsExternal = (to->history() != history);
|
||||||
|
const auto groupNameAdded = displayAsExternal
|
||||||
|
&& (toPeer != sender)
|
||||||
|
&& (toPeer->isChat() || toPeer->isMegagroup());
|
||||||
|
const auto shorten = groupNameAdded || quote;
|
||||||
|
|
||||||
|
auto nameFull = TextWithEntities();
|
||||||
|
using namespace HistoryView;
|
||||||
|
if (displayAsExternal && !groupNameAdded) {
|
||||||
|
nameFull.append(Reply::PeerEmoji(history, sender));
|
||||||
|
}
|
||||||
|
nameFull.append(shorten ? sender->shortName() : sender->name());
|
||||||
|
if (groupNameAdded) {
|
||||||
|
nameFull.append(' ').append(Reply::PeerEmoji(history, toPeer));
|
||||||
|
nameFull.append(toPeer->name());
|
||||||
|
}
|
||||||
|
return (quote
|
||||||
|
? tr::lng_preview_reply_to_quote
|
||||||
|
: tr::lng_preview_reply_to)(
|
||||||
|
tr::now,
|
||||||
|
lt_name,
|
||||||
|
nameFull,
|
||||||
|
Ui::Text::WithEntities);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void Reply::unloadPersistentAnimation() {
|
void Reply::unloadPersistentAnimation() {
|
||||||
_text.unloadPersistentAnimation();
|
_text.unloadPersistentAnimation();
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,14 @@ public:
|
||||||
return _link;
|
return _link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static TextWithEntities PeerEmoji(
|
||||||
|
not_null<History*> history,
|
||||||
|
PeerData *peer);
|
||||||
|
[[nodiscard]] static TextWithEntities ComposePreviewName(
|
||||||
|
not_null<History*> history,
|
||||||
|
not_null<HistoryItem*> to,
|
||||||
|
bool quote);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] Ui::Text::GeometryDescriptor textGeometry(
|
[[nodiscard]] Ui::Text::GeometryDescriptor textGeometry(
|
||||||
int available,
|
int available,
|
||||||
|
|
|
@ -91,7 +91,6 @@ void ProcessZoom(
|
||||||
widget->zoomRequests(
|
widget->zoomRequests(
|
||||||
) | rpl::start_with_next([=](float64 x) {
|
) | rpl::start_with_next([=](float64 x) {
|
||||||
d.api->requestZoom(
|
d.api->requestZoom(
|
||||||
d.peer,
|
|
||||||
zoomToken,
|
zoomToken,
|
||||||
x
|
x
|
||||||
) | rpl::start_with_next_error_done([=](
|
) | rpl::start_with_next_error_done([=](
|
||||||
|
@ -144,7 +143,6 @@ void FillStatistic(
|
||||||
m);
|
m);
|
||||||
|
|
||||||
descriptor.api->requestZoom(
|
descriptor.api->requestZoom(
|
||||||
descriptor.peer,
|
|
||||||
graphData.zoomToken,
|
graphData.zoomToken,
|
||||||
0
|
0
|
||||||
) | rpl::start_with_next_error_done([=, graphPtr = &graphData](
|
) | rpl::start_with_next_error_done([=, graphPtr = &graphData](
|
||||||
|
@ -524,7 +522,7 @@ void InnerWidget::load() {
|
||||||
|
|
||||||
const auto descriptor = Descriptor{
|
const auto descriptor = Descriptor{
|
||||||
_peer,
|
_peer,
|
||||||
lifetime().make_state<Api::Statistics>(&_peer->session().api()),
|
lifetime().make_state<Api::Statistics>(_peer->asChannel()),
|
||||||
_controller->uiShow()->toastParent(),
|
_controller->uiShow()->toastParent(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -543,7 +541,6 @@ void InnerWidget::load() {
|
||||||
) | rpl::take(1) | rpl::start_with_next([=] {
|
) | rpl::take(1) | rpl::start_with_next([=] {
|
||||||
if (!_contextId) {
|
if (!_contextId) {
|
||||||
descriptor.api->request(
|
descriptor.api->request(
|
||||||
descriptor.peer
|
|
||||||
) | rpl::start_with_done([=] {
|
) | rpl::start_with_done([=] {
|
||||||
_state.stats = Data::AnyStatistics{
|
_state.stats = Data::AnyStatistics{
|
||||||
descriptor.api->channelStats(),
|
descriptor.api->channelStats(),
|
||||||
|
@ -575,7 +572,7 @@ void InnerWidget::fill() {
|
||||||
const auto inner = this;
|
const auto inner = this;
|
||||||
const auto descriptor = Descriptor{
|
const auto descriptor = Descriptor{
|
||||||
_peer,
|
_peer,
|
||||||
lifetime().make_state<Api::Statistics>(&_peer->session().api()),
|
lifetime().make_state<Api::Statistics>(_peer->asChannel()),
|
||||||
_controller->uiShow()->toastParent(),
|
_controller->uiShow()->toastParent(),
|
||||||
};
|
};
|
||||||
if (_state.stats.message) {
|
if (_state.stats.message) {
|
||||||
|
@ -705,8 +702,9 @@ void InnerWidget::fillRecentPosts() {
|
||||||
container,
|
container,
|
||||||
tr::lng_stories_show_more())));
|
tr::lng_stories_show_more())));
|
||||||
|
|
||||||
constexpr auto kPerPage = int(10);
|
constexpr auto kFirstPage = int(10);
|
||||||
const auto max = stats.recentMessageInteractions.size();
|
constexpr auto kPerPage = int(30);
|
||||||
|
const auto max = int(stats.recentMessageInteractions.size());
|
||||||
if (_state.recentPostsExpanded) {
|
if (_state.recentPostsExpanded) {
|
||||||
_state.recentPostsExpanded = std::max(
|
_state.recentPostsExpanded = std::max(
|
||||||
_state.recentPostsExpanded - kPerPage,
|
_state.recentPostsExpanded - kPerPage,
|
||||||
|
@ -715,8 +713,10 @@ void InnerWidget::fillRecentPosts() {
|
||||||
const auto showMore = [=] {
|
const auto showMore = [=] {
|
||||||
const auto from = _state.recentPostsExpanded;
|
const auto from = _state.recentPostsExpanded;
|
||||||
_state.recentPostsExpanded = std::min(
|
_state.recentPostsExpanded = std::min(
|
||||||
int(max),
|
max,
|
||||||
_state.recentPostsExpanded + kPerPage);
|
_state.recentPostsExpanded
|
||||||
|
? (_state.recentPostsExpanded + kPerPage)
|
||||||
|
: kFirstPage);
|
||||||
if (_state.recentPostsExpanded == max) {
|
if (_state.recentPostsExpanded == max) {
|
||||||
buttonWrap->toggle(false, anim::type::instant);
|
buttonWrap->toggle(false, anim::type::instant);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ constexpr auto kUpdaterDcShift = 0x03;
|
||||||
constexpr auto kExportDcShift = 0x04;
|
constexpr auto kExportDcShift = 0x04;
|
||||||
constexpr auto kExportMediaDcShift = 0x05;
|
constexpr auto kExportMediaDcShift = 0x05;
|
||||||
constexpr auto kGroupCallStreamDcShift = 0x06;
|
constexpr auto kGroupCallStreamDcShift = 0x06;
|
||||||
|
constexpr auto kStatsDcShift = 0x07;
|
||||||
constexpr auto kMaxMediaDcCount = 0x10;
|
constexpr auto kMaxMediaDcCount = 0x10;
|
||||||
constexpr auto kBaseDownloadDcShift = 0x10;
|
constexpr auto kBaseDownloadDcShift = 0x10;
|
||||||
constexpr auto kBaseUploadDcShift = 0x20;
|
constexpr auto kBaseUploadDcShift = 0x20;
|
||||||
|
|
|
@ -150,8 +150,11 @@ public:
|
||||||
ResponseHandler &&callbacks = {},
|
ResponseHandler &&callbacks = {},
|
||||||
ShiftedDcId shiftedDcId = 0,
|
ShiftedDcId shiftedDcId = 0,
|
||||||
crl::time msCanWait = 0,
|
crl::time msCanWait = 0,
|
||||||
mtpRequestId afterRequestId = 0) {
|
mtpRequestId afterRequestId = 0,
|
||||||
const auto requestId = details::GetNextRequestId();
|
mtpRequestId overrideRequestId = 0) {
|
||||||
|
const auto requestId = overrideRequestId
|
||||||
|
? overrideRequestId
|
||||||
|
: details::GetNextRequestId();
|
||||||
sendSerialized(
|
sendSerialized(
|
||||||
requestId,
|
requestId,
|
||||||
details::SerializedRequest::Serialize(request),
|
details::SerializedRequest::Serialize(request),
|
||||||
|
@ -169,13 +172,15 @@ public:
|
||||||
FailHandler &&onFail = nullptr,
|
FailHandler &&onFail = nullptr,
|
||||||
ShiftedDcId shiftedDcId = 0,
|
ShiftedDcId shiftedDcId = 0,
|
||||||
crl::time msCanWait = 0,
|
crl::time msCanWait = 0,
|
||||||
mtpRequestId afterRequestId = 0) {
|
mtpRequestId afterRequestId = 0,
|
||||||
|
mtpRequestId overrideRequestId = 0) {
|
||||||
return send(
|
return send(
|
||||||
request,
|
request,
|
||||||
ResponseHandler{ std::move(onDone), std::move(onFail) },
|
ResponseHandler{ std::move(onDone), std::move(onFail) },
|
||||||
shiftedDcId,
|
shiftedDcId,
|
||||||
msCanWait,
|
msCanWait,
|
||||||
afterRequestId);
|
afterRequestId,
|
||||||
|
overrideRequestId);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Request>
|
template <typename Request>
|
||||||
|
|
|
@ -130,6 +130,9 @@ class Sender {
|
||||||
void setToDC(ShiftedDcId dcId) noexcept {
|
void setToDC(ShiftedDcId dcId) noexcept {
|
||||||
_dcId = dcId;
|
_dcId = dcId;
|
||||||
}
|
}
|
||||||
|
void setOverrideRequestId(mtpRequestId id) noexcept {
|
||||||
|
_overrideRequestId = id;
|
||||||
|
}
|
||||||
void setCanWait(crl::time ms) noexcept {
|
void setCanWait(crl::time ms) noexcept {
|
||||||
_canWait = ms;
|
_canWait = ms;
|
||||||
}
|
}
|
||||||
|
@ -147,16 +150,16 @@ class Sender {
|
||||||
_afterRequestId = requestId;
|
_afterRequestId = requestId;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShiftedDcId takeDcId() const noexcept {
|
[[nodiscard]] ShiftedDcId takeDcId() const noexcept {
|
||||||
return _dcId;
|
return _dcId;
|
||||||
}
|
}
|
||||||
crl::time takeCanWait() const noexcept {
|
[[nodiscard]] crl::time takeCanWait() const noexcept {
|
||||||
return _canWait;
|
return _canWait;
|
||||||
}
|
}
|
||||||
DoneHandler takeOnDone() noexcept {
|
[[nodiscard]] DoneHandler takeOnDone() noexcept {
|
||||||
return std::move(_done);
|
return std::move(_done);
|
||||||
}
|
}
|
||||||
FailHandler takeOnFail() {
|
[[nodiscard]] FailHandler takeOnFail() {
|
||||||
return v::match(_fail, [&](auto &value) {
|
return v::match(_fail, [&](auto &value) {
|
||||||
return MakeFailHandler(
|
return MakeFailHandler(
|
||||||
_sender,
|
_sender,
|
||||||
|
@ -164,11 +167,14 @@ class Sender {
|
||||||
_failSkipPolicy);
|
_failSkipPolicy);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
mtpRequestId takeAfter() const noexcept {
|
[[nodiscard]] mtpRequestId takeAfter() const noexcept {
|
||||||
return _afterRequestId;
|
return _afterRequestId;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] mtpRequestId takeOverrideRequestId() const noexcept {
|
||||||
|
return _overrideRequestId;
|
||||||
|
}
|
||||||
|
|
||||||
not_null<Sender*> sender() const noexcept {
|
[[nodiscard]] not_null<Sender*> sender() const noexcept {
|
||||||
return _sender;
|
return _sender;
|
||||||
}
|
}
|
||||||
void registerRequest(mtpRequestId requestId) {
|
void registerRequest(mtpRequestId requestId) {
|
||||||
|
@ -187,6 +193,7 @@ class Sender {
|
||||||
FailFullHandler> _fail;
|
FailFullHandler> _fail;
|
||||||
FailSkipPolicy _failSkipPolicy = FailSkipPolicy::Simple;
|
FailSkipPolicy _failSkipPolicy = FailSkipPolicy::Simple;
|
||||||
mtpRequestId _afterRequestId = 0;
|
mtpRequestId _afterRequestId = 0;
|
||||||
|
mtpRequestId _overrideRequestId = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -207,9 +214,10 @@ public:
|
||||||
: RequestBuilder(sender)
|
: RequestBuilder(sender)
|
||||||
, _request(std::move(request)) {
|
, _request(std::move(request)) {
|
||||||
}
|
}
|
||||||
SpecificRequestBuilder(SpecificRequestBuilder &&other) = default;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
SpecificRequestBuilder(SpecificRequestBuilder &&other) = default;
|
||||||
|
|
||||||
[[nodiscard]] SpecificRequestBuilder &toDC(ShiftedDcId dcId) noexcept {
|
[[nodiscard]] SpecificRequestBuilder &toDC(ShiftedDcId dcId) noexcept {
|
||||||
setToDC(dcId);
|
setToDC(dcId);
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -218,6 +226,10 @@ public:
|
||||||
setCanWait(ms);
|
setCanWait(ms);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] SpecificRequestBuilder &overrideId(mtpRequestId id) noexcept {
|
||||||
|
setOverrideRequestId(id);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
using Result = typename Request::ResponseType;
|
using Result = typename Request::ResponseType;
|
||||||
[[nodiscard]] SpecificRequestBuilder &done(
|
[[nodiscard]] SpecificRequestBuilder &done(
|
||||||
|
@ -295,7 +307,8 @@ public:
|
||||||
takeOnFail(),
|
takeOnFail(),
|
||||||
takeDcId(),
|
takeDcId(),
|
||||||
takeCanWait(),
|
takeCanWait(),
|
||||||
takeAfter());
|
takeAfter(),
|
||||||
|
takeOverrideRequestId());
|
||||||
registerRequest(id);
|
registerRequest(id);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
@ -347,6 +360,13 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] mtpRequestId allocateRequestId() noexcept {
|
||||||
|
return details::GetNextRequestId();
|
||||||
|
}
|
||||||
|
[[nodiscard]] bool pending(mtpRequestId requestId) noexcept {
|
||||||
|
return _requests.contains(requestId);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class RequestWrap {
|
class RequestWrap {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -40,7 +40,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include <QtWidgets/QLineEdit>
|
#include <QtWidgets/QLineEdit>
|
||||||
#include <QtWidgets/QTextEdit>
|
#include <QtWidgets/QTextEdit>
|
||||||
#include <QtGui/QClipboard>
|
#include <QtGui/QClipboard>
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
|
||||||
#include <qpa/qwindowsysteminterface.h>
|
#include <qpa/qwindowsysteminterface.h>
|
||||||
|
#endif // Qt < 6.6.0
|
||||||
|
|
||||||
#include <Cocoa/Cocoa.h>
|
#include <Cocoa/Cocoa.h>
|
||||||
#include <CoreFoundation/CFURL.h>
|
#include <CoreFoundation/CFURL.h>
|
||||||
|
@ -52,7 +55,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
- (id) init:(MainWindow::Private*)window;
|
- (id) init:(MainWindow::Private*)window;
|
||||||
- (void) activeSpaceDidChange:(NSNotification *)aNotification;
|
- (void) activeSpaceDidChange:(NSNotification *)aNotification;
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
|
||||||
- (void) darkModeChanged:(NSNotification *)aNotification;
|
- (void) darkModeChanged:(NSNotification *)aNotification;
|
||||||
|
#endif // Qt < 6.6.0
|
||||||
- (void) screenIsLocked:(NSNotification *)aNotification;
|
- (void) screenIsLocked:(NSNotification *)aNotification;
|
||||||
- (void) screenIsUnlocked:(NSNotification *)aNotification;
|
- (void) screenIsUnlocked:(NSNotification *)aNotification;
|
||||||
|
|
||||||
|
@ -113,6 +118,7 @@ private:
|
||||||
- (void) activeSpaceDidChange:(NSNotification *)aNotification {
|
- (void) activeSpaceDidChange:(NSNotification *)aNotification {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
|
||||||
- (void) darkModeChanged:(NSNotification *)aNotification {
|
- (void) darkModeChanged:(NSNotification *)aNotification {
|
||||||
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
|
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
|
||||||
|
@ -122,6 +128,7 @@ private:
|
||||||
#endif // Qt < 6.5.0
|
#endif // Qt < 6.5.0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
#endif // Qt < 6.6.0
|
||||||
|
|
||||||
- (void) screenIsLocked:(NSNotification *)aNotification {
|
- (void) screenIsLocked:(NSNotification *)aNotification {
|
||||||
Core::App().setScreenIsLocked(true);
|
Core::App().setScreenIsLocked(true);
|
||||||
|
@ -156,10 +163,12 @@ void ForceDisabled(QAction *action, bool disabled) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
|
||||||
QString strNotificationAboutThemeChange() {
|
QString strNotificationAboutThemeChange() {
|
||||||
const uint32 letters[] = { 0x75E86256, 0xD03E11B1, 0x4D92201D, 0xA2144987, 0x99D5B34F, 0x037589C3, 0x38ED2A7C, 0xD2371ABC, 0xDC98BB02, 0x27964E1B, 0x01748AED, 0xE06679F8, 0x761C9580, 0x4F2595BF, 0x6B5FCBF4, 0xE4D9C24E, 0xBA2F6AB5, 0xE6E3FA71, 0xF2CFC255, 0x56A50C19, 0x43AE1239, 0x77CA4254, 0x7D189A89, 0xEA7663EE, 0x84CEB554, 0xA0ADF236, 0x886512D4, 0x7D3FBDAF, 0x85C4BE4F, 0x12C8255E, 0x9AD8BD41, 0xAC154683, 0xB117598B, 0xDFD9F947, 0x63F06C7B, 0x6340DCD6, 0x3AAE6B3E, 0x26CB125A };
|
const uint32 letters[] = { 0x75E86256, 0xD03E11B1, 0x4D92201D, 0xA2144987, 0x99D5B34F, 0x037589C3, 0x38ED2A7C, 0xD2371ABC, 0xDC98BB02, 0x27964E1B, 0x01748AED, 0xE06679F8, 0x761C9580, 0x4F2595BF, 0x6B5FCBF4, 0xE4D9C24E, 0xBA2F6AB5, 0xE6E3FA71, 0xF2CFC255, 0x56A50C19, 0x43AE1239, 0x77CA4254, 0x7D189A89, 0xEA7663EE, 0x84CEB554, 0xA0ADF236, 0x886512D4, 0x7D3FBDAF, 0x85C4BE4F, 0x12C8255E, 0x9AD8BD41, 0xAC154683, 0xB117598B, 0xDFD9F947, 0x63F06C7B, 0x6340DCD6, 0x3AAE6B3E, 0x26CB125A };
|
||||||
return Platform::MakeFromLetters(letters);
|
return Platform::MakeFromLetters(letters);
|
||||||
}
|
}
|
||||||
|
#endif // Qt < 6.6.0
|
||||||
|
|
||||||
QString strNotificationAboutScreenLocked() {
|
QString strNotificationAboutScreenLocked() {
|
||||||
const uint32 letters[] = { 0x34B47F28, 0x47E95179, 0x73D05C42, 0xB4E2A933, 0x924F22D1, 0x4265D8EA, 0x9E4D2CC2, 0x02E8157B, 0x35BF7525, 0x75901A41, 0xB0400FCC, 0xE801169D, 0x4E04B589, 0xC1CEF054, 0xAB2A7EB0, 0x5C67C4F6, 0xA4E2B954, 0xB35E12D2, 0xD598B22B, 0x4E3B8AAB, 0xBEA5E439, 0xFDA8AA3C, 0x1632DBA8, 0x88FE8965 };
|
const uint32 letters[] = { 0x34B47F28, 0x47E95179, 0x73D05C42, 0xB4E2A933, 0x924F22D1, 0x4265D8EA, 0x9E4D2CC2, 0x02E8157B, 0x35BF7525, 0x75901A41, 0xB0400FCC, 0xE801169D, 0x4E04B589, 0xC1CEF054, 0xAB2A7EB0, 0x5C67C4F6, 0xA4E2B954, 0xB35E12D2, 0xD598B22B, 0x4E3B8AAB, 0xBEA5E439, 0xFDA8AA3C, 0x1632DBA8, 0x88FE8965 };
|
||||||
|
@ -181,7 +190,9 @@ MainWindow::Private::Private(not_null<MainWindow*> window)
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
|
||||||
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:_observer selector:@selector(activeSpaceDidChange:) name:NSWorkspaceActiveSpaceDidChangeNotification object:nil];
|
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:_observer selector:@selector(activeSpaceDidChange:) name:NSWorkspaceActiveSpaceDidChangeNotification object:nil];
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
|
||||||
[[NSDistributedNotificationCenter defaultCenter] addObserver:_observer selector:@selector(darkModeChanged:) name:Q2NSString(strNotificationAboutThemeChange()) object:nil];
|
[[NSDistributedNotificationCenter defaultCenter] addObserver:_observer selector:@selector(darkModeChanged:) name:Q2NSString(strNotificationAboutThemeChange()) object:nil];
|
||||||
|
#endif // Qt < 6.6.0
|
||||||
[[NSDistributedNotificationCenter defaultCenter] addObserver:_observer selector:@selector(screenIsLocked:) name:Q2NSString(strNotificationAboutScreenLocked()) object:nil];
|
[[NSDistributedNotificationCenter defaultCenter] addObserver:_observer selector:@selector(screenIsLocked:) name:Q2NSString(strNotificationAboutScreenLocked()) object:nil];
|
||||||
[[NSDistributedNotificationCenter defaultCenter] addObserver:_observer selector:@selector(screenIsUnlocked:) name:Q2NSString(strNotificationAboutScreenUnlocked()) object:nil];
|
[[NSDistributedNotificationCenter defaultCenter] addObserver:_observer selector:@selector(screenIsUnlocked:) name:Q2NSString(strNotificationAboutScreenUnlocked()) object:nil];
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#if __has_include(<QtCore/QOperatingSystemVersion>)
|
#if __has_include(<QtCore/QOperatingSystemVersion>)
|
||||||
#include <QtCore/QOperatingSystemVersion>
|
#include <QtCore/QOperatingSystemVersion>
|
||||||
#endif // __has_include(<QtCore/QOperatingSystemVersion>)
|
#endif // __has_include(<QtCore/QOperatingSystemVersion>)
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
|
||||||
#include <qpa/qwindowsysteminterface.h>
|
#include <qpa/qwindowsysteminterface.h>
|
||||||
|
#endif // Qt < 6.6.0
|
||||||
#include <Cocoa/Cocoa.h>
|
#include <Cocoa/Cocoa.h>
|
||||||
#include <CoreFoundation/CFURL.h>
|
#include <CoreFoundation/CFURL.h>
|
||||||
#include <IOKit/IOKitLib.h>
|
#include <IOKit/IOKitLib.h>
|
||||||
|
@ -201,11 +203,11 @@ ApplicationDelegate *_sharedDelegate = nil;
|
||||||
"-receiveWakeNote: received, scheduling detach from audio device"));
|
"-receiveWakeNote: received, scheduling detach from audio device"));
|
||||||
Media::Audio::ScheduleDetachFromDeviceSafe();
|
Media::Audio::ScheduleDetachFromDeviceSafe();
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
|
#if QT_VERSION < QT_VERSION_CHECK(6, 5, 0)
|
||||||
QWindowSystemInterface::handleThemeChange();
|
|
||||||
#else // Qt >= 6.5.0
|
|
||||||
Core::App().settings().setSystemDarkMode(Platform::IsDarkMode());
|
Core::App().settings().setSystemDarkMode(Platform::IsDarkMode());
|
||||||
#endif // Qt < 6.5.0
|
#elif QT_VERSION < QT_VERSION_CHECK(6, 6, 0) // Qt < 6.5.0
|
||||||
|
QWindowSystemInterface::handleThemeChange();
|
||||||
|
#endif // Qt < 6.6.0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "base/platform/win/base_windows_winrt.h"
|
||||||
#include "platform/platform_integration.h"
|
#include "platform/platform_integration.h"
|
||||||
|
|
||||||
#include <QAbstractNativeEventFilter>
|
#include <QAbstractNativeEventFilter>
|
||||||
|
|
||||||
#include <winrt/base.h>
|
|
||||||
#include <ShlObj.h>
|
#include <ShlObj.h>
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
|
|
|
@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "base/platform/win/base_windows_h.h"
|
#include "base/platform/win/base_windows_h.h"
|
||||||
|
|
||||||
|
#include <wtypes.h>
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
namespace AppUserModelId {
|
namespace AppUserModelId {
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "base/platform/win/base_windows_h.h"
|
#include "base/platform/win/base_windows_h.h"
|
||||||
|
|
||||||
|
#include <shellapi.h>
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
#include <dwmapi.h>
|
#include <dwmapi.h>
|
||||||
#include <RestartManager.h>
|
#include <RestartManager.h>
|
||||||
|
|
|
@ -163,7 +163,7 @@ void LinearChartView::paintSelectedXIndex(
|
||||||
+ c.rect.topLeft();
|
+ c.rect.topLeft();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!linePainted) {
|
if (!linePainted && lineAlpha) {
|
||||||
[[maybe_unused]] const auto o = ScopedPainterOpacity(
|
[[maybe_unused]] const auto o = ScopedPainterOpacity(
|
||||||
p,
|
p,
|
||||||
p.opacity() * progress * kRulerLineAlpha);
|
p.opacity() * progress * kRulerLineAlpha);
|
||||||
|
|
|
@ -98,11 +98,7 @@ namespace {
|
||||||
auto hq = PainterHighQualityEnabler(p);
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
const auto radius = std::min(badge->width(), badge->height()) / 2;
|
const auto radius = std::min(badge->width(), badge->height()) / 2;
|
||||||
p.setPen(Qt::NoPen);
|
p.setPen(Qt::NoPen);
|
||||||
auto brush = QLinearGradient(
|
p.setBrush(st::premiumButtonBg2);
|
||||||
QPointF(badge->width(), badge->height()),
|
|
||||||
QPointF());
|
|
||||||
brush.setStops(Ui::Premium::ButtonGradientStops());
|
|
||||||
p.setBrush(brush);
|
|
||||||
p.drawRoundedRect(badge->rect(), radius, radius);
|
p.drawRoundedRect(badge->rect(), radius, radius);
|
||||||
}, badge->lifetime());
|
}, badge->lifetime());
|
||||||
|
|
||||||
|
|
2
Telegram/ThirdParty/libtgvoip
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit c2e718049cf11bbbe7b6d78b78b2d21f0e0affa0
|
Subproject commit e286ab66141a2f986803177e4cbb7b14002664cb
|
|
@ -1,7 +1,7 @@
|
||||||
AppVersion 4011006
|
AppVersion 4011007
|
||||||
AppVersionStrMajor 4.11
|
AppVersionStrMajor 4.11
|
||||||
AppVersionStrSmall 4.11.6
|
AppVersionStrSmall 4.11.7
|
||||||
AppVersionStr 4.11.6
|
AppVersionStr 4.11.7
|
||||||
BetaChannel 0
|
BetaChannel 0
|
||||||
AlphaVersion 0
|
AlphaVersion 0
|
||||||
AppVersionOriginal 4.11.6
|
AppVersionOriginal 4.11.7
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit bb5e7fafd7aca5808217baeeb9ee3af8c3be6b1b
|
Subproject commit fe4f0a72d2041a860c67a81a70f2e4b6f845d9fb
|
|
@ -1 +1 @@
|
||||||
Subproject commit f5fe3afcf5bc5edf07a78ad18b9e8d33c3fbfdb2
|
Subproject commit aab27269ff8aad5dfaf7372db10bff700fdb5fe9
|
|
@ -1,3 +1,11 @@
|
||||||
|
4.11.7 (13.11.23)
|
||||||
|
|
||||||
|
- Fix sending media files with quote replies.
|
||||||
|
- Fix quoted text highlighting in some cases.
|
||||||
|
- Fix loading statistics for some channels.
|
||||||
|
- Fix Ctrl+Shift+. shortcut on X11.
|
||||||
|
- Fix a crash in statistics.
|
||||||
|
|
||||||
4.11.6 (09.11.23)
|
4.11.6 (09.11.23)
|
||||||
|
|
||||||
- Support multiple boosts and reassignment.
|
- Support multiple boosts and reassignment.
|
||||||
|
|
2
cmake
|
@ -1 +1 @@
|
||||||
Subproject commit 78098ede77a09e41da6233d765d02b43a60e7138
|
Subproject commit c373a0a0141bbe146a9507f02b8515183748eb51
|