Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf0ad9e7ca | ||
|
|
fc7dcd0360 | ||
|
|
14416a68db | ||
|
|
ee1a80abd7 | ||
|
|
d392d9cb1f | ||
|
|
65c7a9a554 | ||
|
|
1c98399c6f | ||
|
|
263ac2eb71 | ||
|
|
75d8e8ba7d | ||
|
|
0fbd7d1a3b | ||
|
|
8f0ba749d1 | ||
|
|
fc8ea688a3 | ||
|
|
2d651050ad | ||
|
|
a94c42411b | ||
|
|
57f769f358 | ||
|
|
ce39eb2da9 | ||
|
|
f7bc84fdd6 | ||
|
|
28f75525b2 | ||
|
|
03c1f15961 | ||
|
|
2f92830f6a | ||
|
|
73af96e9c3 | ||
|
|
1e63a6a1a7 | ||
|
|
0df699a054 | ||
|
|
0e771312f4 | ||
|
|
db15a58dde | ||
|
|
d81c40f4c8 | ||
|
|
e2624416af | ||
|
|
e72b4c6192 | ||
|
|
654fefaa72 | ||
|
|
7f6c163449 | ||
|
|
5738998310 | ||
|
|
45d2baa2c4 | ||
|
|
9033d49d76 | ||
|
|
1b754d14ae | ||
|
|
d1c1b687c7 | ||
|
|
8b44dcf8d0 | ||
|
|
984094a7ff | ||
|
|
55285f327a | ||
|
|
b85ad05f8a | ||
|
|
3c1663adeb | ||
|
|
66e9c5ef16 | ||
|
|
7027c0db0b | ||
|
|
6812f1e5ec | ||
|
|
b963a68dd6 | ||
|
|
1c720af9bc | ||
|
|
69f469a0f9 | ||
|
|
fbc284af49 | ||
|
|
ff51bf81f3 | ||
|
|
29c61635de | ||
|
|
1b9232e28d | ||
|
|
b84c876ba2 | ||
|
|
5fe1988d0a | ||
|
|
77330aa6a7 | ||
|
|
03e60ed329 |
@@ -230,7 +230,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
"lng_limits_increase" = "Increase Limit";
|
||||
|
||||
"lng_sticker_premium_title" = "With Effects";
|
||||
"lng_sticker_premium_text" = "This pack contains premium stickers like this one.";
|
||||
"lng_sticker_premium_view" = "View";
|
||||
"lng_reaction_premium_info" = "Click on the reaction to preview the animation.";
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="3.7.6.0" />
|
||||
Version="4.0.2.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||
|
||||
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,7,6,0
|
||||
PRODUCTVERSION 3,7,6,0
|
||||
FILEVERSION 4,0,2,0
|
||||
PRODUCTVERSION 4,0,2,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -62,10 +62,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "3.7.6.0"
|
||||
VALUE "FileVersion", "4.0.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2022"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "3.7.6.0"
|
||||
VALUE "ProductVersion", "4.0.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,7,6,0
|
||||
PRODUCTVERSION 3,7,6,0
|
||||
FILEVERSION 4,0,2,0
|
||||
PRODUCTVERSION 4,0,2,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -53,10 +53,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop Updater"
|
||||
VALUE "FileVersion", "3.7.6.0"
|
||||
VALUE "FileVersion", "4.0.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2022"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "3.7.6.0"
|
||||
VALUE "ProductVersion", "4.0.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -74,6 +74,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/sticker_set_box.h"
|
||||
#include "boxes/premium_limits_box.h"
|
||||
#include "window/notifications_manager.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/window_lock_widgets.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "inline_bots/inline_bot_result.h"
|
||||
@@ -117,6 +118,26 @@ using UpdatedFileReferences = Data::UpdatedFileReferences;
|
||||
return TimeId(msgId >> 32);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::shared_ptr<Window::Show> ShowForPeer(
|
||||
not_null<PeerData*> peer) {
|
||||
const auto separate = Core::App().separateWindowForPeer(peer);
|
||||
const auto window = separate ? separate : Core::App().primaryWindow();
|
||||
return std::make_shared<Window::Show>(window);
|
||||
}
|
||||
|
||||
void ShowChannelsLimitBox(not_null<PeerData*> peer) {
|
||||
const auto primary = Core::App().primaryWindow();
|
||||
if (!primary) {
|
||||
return;
|
||||
}
|
||||
primary->invokeForSessionController(
|
||||
&peer->session().account(),
|
||||
peer,
|
||||
[&](not_null<Window::SessionController*> controller) {
|
||||
controller->show(Box(ChannelsLimitBox, &peer->session()));
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ApiWrap::ApiWrap(not_null<Main::Session*> session)
|
||||
@@ -417,19 +438,25 @@ void ApiWrap::sendMessageFail(
|
||||
not_null<PeerData*> peer,
|
||||
uint64 randomId,
|
||||
FullMsgId itemId) {
|
||||
const auto show = ShowForPeer(peer);
|
||||
|
||||
if (error.type() == qstr("PEER_FLOOD")) {
|
||||
Ui::show(Ui::MakeInformBox(
|
||||
PeerFloodErrorText(&session(), PeerFloodType::Send)));
|
||||
show->showBox(
|
||||
Ui::MakeInformBox(
|
||||
PeerFloodErrorText(&session(), PeerFloodType::Send)),
|
||||
Ui::LayerOption::CloseOther);
|
||||
} else if (error.type() == qstr("USER_BANNED_IN_CHANNEL")) {
|
||||
const auto link = Ui::Text::Link(
|
||||
tr::lng_cant_more_info(tr::now),
|
||||
session().createInternalLinkFull(qsl("spambot")));
|
||||
Ui::show(Ui::MakeInformBox(
|
||||
tr::lng_error_public_groups_denied(
|
||||
tr::now,
|
||||
lt_more_info,
|
||||
link,
|
||||
Ui::Text::WithEntities)));
|
||||
show->showBox(
|
||||
Ui::MakeInformBox(
|
||||
tr::lng_error_public_groups_denied(
|
||||
tr::now,
|
||||
lt_more_info,
|
||||
link,
|
||||
Ui::Text::WithEntities)),
|
||||
Ui::LayerOption::CloseOther);
|
||||
} else if (error.type().startsWith(qstr("SLOWMODE_WAIT_"))) {
|
||||
const auto chop = qstr("SLOWMODE_WAIT_").size();
|
||||
const auto left = base::StringViewMid(error.type(), chop).toInt();
|
||||
@@ -447,13 +474,21 @@ void ApiWrap::sendMessageFail(
|
||||
Assert(peer->isUser());
|
||||
if (const auto item = scheduled.lookupItem(peer->id, itemId.msg)) {
|
||||
scheduled.removeSending(item);
|
||||
Ui::show(Ui::MakeInformBox(tr::lng_cant_do_this()));
|
||||
show->showBox(
|
||||
Ui::MakeInformBox(tr::lng_cant_do_this()),
|
||||
Ui::LayerOption::CloseOther);
|
||||
}
|
||||
} else if (error.type() == qstr("CHAT_FORWARDS_RESTRICTED")) {
|
||||
Ui::ShowMultilineToast({ .text = { peer->isBroadcast()
|
||||
? tr::lng_error_noforwards_channel(tr::now)
|
||||
: tr::lng_error_noforwards_group(tr::now)
|
||||
}, .duration = kJoinErrorDuration });
|
||||
if (show->valid()) {
|
||||
Ui::ShowMultilineToast({
|
||||
.parentOverride = show->toastParent(),
|
||||
.text = { peer->isBroadcast()
|
||||
? tr::lng_error_noforwards_channel(tr::now)
|
||||
: tr::lng_error_noforwards_group(tr::now)
|
||||
},
|
||||
.duration = kJoinErrorDuration
|
||||
});
|
||||
}
|
||||
} else if (error.type() == qstr("PREMIUM_ACCOUNT_REQUIRED")) {
|
||||
Settings::ShowPremium(&session(), "premium_stickers");
|
||||
}
|
||||
@@ -1214,7 +1249,7 @@ void ApiWrap::migrateDone(
|
||||
|
||||
void ApiWrap::migrateFail(not_null<PeerData*> peer, const QString &error) {
|
||||
if (error == u"CHANNELS_TOO_MUCH"_q) {
|
||||
Ui::show(Box(ChannelsLimitBox, _session));
|
||||
ShowChannelsLimitBox(peer);
|
||||
}
|
||||
if (auto handlers = _migrateCallbacks.take(peer)) {
|
||||
for (auto &handler : *handlers) {
|
||||
@@ -1635,37 +1670,40 @@ void ApiWrap::joinChannel(not_null<ChannelData*> channel) {
|
||||
channel,
|
||||
Data::PeerUpdate::Flag::ChannelAmIn);
|
||||
} else if (!_channelAmInRequests.contains(channel)) {
|
||||
auto requestId = request(MTPchannels_JoinChannel(
|
||||
const auto requestId = request(MTPchannels_JoinChannel(
|
||||
channel->inputChannel
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
_channelAmInRequests.remove(channel);
|
||||
applyUpdates(result);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
const auto &type = error.type();
|
||||
if (type == qstr("CHANNEL_PRIVATE")
|
||||
|
||||
const auto show = ShowForPeer(channel);
|
||||
if (type == u"CHANNEL_PRIVATE"_q
|
||||
&& channel->invitePeekExpires()) {
|
||||
channel->privateErrorReceived();
|
||||
} else if (type == qstr("CHANNELS_TOO_MUCH")) {
|
||||
Ui::show(Box(ChannelsLimitBox, _session));
|
||||
} else if (type == u"CHANNELS_TOO_MUCH"_q) {
|
||||
ShowChannelsLimitBox(channel);
|
||||
} else {
|
||||
const auto text = [&] {
|
||||
if (type == qstr("INVITE_REQUEST_SENT")) {
|
||||
if (type == u"INVITE_REQUEST_SENT"_q) {
|
||||
return channel->isMegagroup()
|
||||
? tr::lng_group_request_sent(tr::now)
|
||||
: tr::lng_group_request_sent_channel(tr::now);
|
||||
} else if (type == qstr("CHANNEL_PRIVATE")
|
||||
|| type == qstr("CHANNEL_PUBLIC_GROUP_NA")
|
||||
|| type == qstr("USER_BANNED_IN_CHANNEL")) {
|
||||
} else if (type == u"CHANNEL_PRIVATE"_q
|
||||
|| type == u"CHANNEL_PUBLIC_GROUP_NA"_q
|
||||
|| type == u"USER_BANNED_IN_CHANNEL"_q) {
|
||||
return channel->isMegagroup()
|
||||
? tr::lng_group_not_accessible(tr::now)
|
||||
: tr::lng_channel_not_accessible(tr::now);
|
||||
} else if (type == qstr("USERS_TOO_MUCH")) {
|
||||
} else if (type == u"USERS_TOO_MUCH"_q) {
|
||||
return tr::lng_group_full(tr::now);
|
||||
}
|
||||
return QString();
|
||||
}();
|
||||
if (!text.isEmpty()) {
|
||||
if (!text.isEmpty() && show->valid()) {
|
||||
Ui::ShowMultilineToast({
|
||||
.parentOverride = show->toastParent(),
|
||||
.text = { text },
|
||||
.duration = kJoinErrorDuration,
|
||||
});
|
||||
|
||||
@@ -365,6 +365,8 @@ void AddContactBox::save() {
|
||||
firstName = lastName;
|
||||
lastName = QString();
|
||||
}
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
const auto session = _session;
|
||||
_sentName = firstName;
|
||||
_contactId = base::RandomValue<uint64>();
|
||||
_addRequest = _session->api().request(MTPcontacts_ImportContacts(
|
||||
@@ -375,18 +377,20 @@ void AddContactBox::save() {
|
||||
MTP_string(phone),
|
||||
MTP_string(firstName),
|
||||
MTP_string(lastName)))
|
||||
)).done(crl::guard(this, [=](
|
||||
)).done(crl::guard(weak, [=](
|
||||
const MTPcontacts_ImportedContacts &result) {
|
||||
const auto &data = result.match([](
|
||||
const auto &data) -> const MTPDcontacts_importedContacts& {
|
||||
return data;
|
||||
});
|
||||
_session->data().processUsers(data.vusers());
|
||||
|
||||
session->data().processUsers(data.vusers());
|
||||
if (!weak) {
|
||||
return;
|
||||
}
|
||||
const auto extractUser = [&](const MTPImportedContact &data) {
|
||||
return data.match([&](const MTPDimportedContact &data) {
|
||||
return (data.vclient_id().v == _contactId)
|
||||
? _session->data().userLoaded(data.vuser_id())
|
||||
? session->data().userLoaded(data.vuser_id())
|
||||
: nullptr;
|
||||
});
|
||||
};
|
||||
@@ -398,7 +402,9 @@ void AddContactBox::save() {
|
||||
if (user->isContact() || user->session().supportMode()) {
|
||||
Ui::showPeerHistory(user, ShowAtTheEndMsgId);
|
||||
}
|
||||
getDelegate()->hideLayer();
|
||||
if (weak) { // showPeerHistory could close the box.
|
||||
getDelegate()->hideLayer();
|
||||
}
|
||||
} else if (isBoxShown()) {
|
||||
hideChildren();
|
||||
_retrying = true;
|
||||
|
||||
@@ -38,7 +38,7 @@ not_null<int64*> AddSizeLimitSlider(
|
||||
using namespace Settings;
|
||||
using Pair = base::flat_map<Type, int64>::value_type;
|
||||
|
||||
const auto limits = Ui::CreateChild<rpl::event_stream<int>>(
|
||||
const auto limits = Ui::CreateChild<rpl::event_stream<int64>>(
|
||||
container.get());
|
||||
const auto currentLimit = ranges::max_element(
|
||||
values,
|
||||
@@ -51,7 +51,7 @@ not_null<int64*> AddSizeLimitSlider(
|
||||
tr::lng_media_size_limit(),
|
||||
limits->events_starting_with_copy(
|
||||
startLimit
|
||||
) | rpl::map([](int value) {
|
||||
) | rpl::map([](int64 value) {
|
||||
return tr::lng_media_size_up_to(
|
||||
tr::now,
|
||||
lt_size,
|
||||
@@ -67,7 +67,7 @@ not_null<int64*> AddSizeLimitSlider(
|
||||
Export::View::kSizeValueCount,
|
||||
Export::View::SizeLimitByIndex,
|
||||
*result,
|
||||
[=](int value) {
|
||||
[=](int64 value) {
|
||||
*result = value;
|
||||
limits->fire_copy(value);
|
||||
});
|
||||
|
||||
@@ -337,8 +337,6 @@ auto DeleteMessagesBox::revokeText(not_null<PeerData*> peer) const
|
||||
lt_user,
|
||||
{ user->firstName },
|
||||
Ui::Text::RichLangValue);
|
||||
} else if (_wipeHistoryJustClear) {
|
||||
return std::nullopt;
|
||||
} else {
|
||||
result.checkbox.text = tr::lng_delete_for_everyone_check(tr::now);
|
||||
}
|
||||
|
||||
@@ -654,9 +654,13 @@ void PeerListRow::invalidatePixmapsCache() {
|
||||
}
|
||||
|
||||
int PeerListRow::nameIconWidth() const {
|
||||
return (special() || !_peer->isVerified())
|
||||
return special()
|
||||
? 0
|
||||
: st::dialogsVerifiedIcon.width();
|
||||
: _peer->isVerified()
|
||||
? st::dialogsVerifiedIcon.width()
|
||||
: (_peer->isPremium() && !_peer->isSelf())
|
||||
? st::dialogsPremiumIcon.width()
|
||||
: 0;
|
||||
}
|
||||
|
||||
void PeerListRow::paintNameIcon(
|
||||
@@ -665,7 +669,11 @@ void PeerListRow::paintNameIcon(
|
||||
int y,
|
||||
int outerWidth,
|
||||
bool selected) {
|
||||
st::dialogsVerifiedIcon.paint(p, x, y, outerWidth);
|
||||
if (_peer->isVerified()) {
|
||||
st::dialogsVerifiedIcon.paint(p, x, y, outerWidth);
|
||||
} else if (_peer->isPremium() && !_peer->isSelf()) {
|
||||
st::dialogsPremiumIcon.paint(p, x, y, outerWidth);
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListRow::paintStatusText(
|
||||
|
||||
@@ -1941,7 +1941,7 @@ auto ParticipantsBoxController::computeType(
|
||||
? Badge::Fake
|
||||
: user->isVerified()
|
||||
? Badge::Verified
|
||||
: (user->isPremium() && participant->session().premiumPossible())
|
||||
: (user->isPremium() && participant->session().premiumBadgesShown())
|
||||
? Badge::Premium
|
||||
: Badge::None;
|
||||
return result;
|
||||
|
||||
@@ -608,7 +608,7 @@ void Controller::refreshHistoryVisibility() {
|
||||
const auto withUsername = _typeDataSavedValue
|
||||
&& (_typeDataSavedValue->privacy == Privacy::HasUsername);
|
||||
_controls.historyVisibilityWrap->toggle(
|
||||
(withUsername
|
||||
(!withUsername
|
||||
&& !_channelHasLocationOriginalValue
|
||||
&& (!_linkedChatSavedValue || !*_linkedChatSavedValue)),
|
||||
anim::type::instant);
|
||||
|
||||
@@ -1722,12 +1722,12 @@ void DoubledLimitsPreviewBox(
|
||||
});
|
||||
}
|
||||
{
|
||||
const auto premium = limits.captionLengthPremium();
|
||||
const auto premium = limits.aboutLengthPremium();
|
||||
entries.push_back(Ui::Premium::ListEntry{
|
||||
tr::lng_premium_double_limits_subtitle_bio(),
|
||||
tr::lng_premium_double_limits_about_bio(
|
||||
Ui::Text::RichLangValue),
|
||||
limits.captionLengthDefault(),
|
||||
limits.aboutLengthDefault(),
|
||||
premium,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3482,6 +3482,7 @@ void GroupCall::destroyController() {
|
||||
DEBUG_LOG(("Call Info: Destroying call controller.."));
|
||||
invalidate_weak_ptrs(&_instanceGuard);
|
||||
|
||||
_instance->stop();
|
||||
crl::async([
|
||||
instance = base::take(_instance),
|
||||
done = _delegate->groupCallAddAsyncWaiter()
|
||||
@@ -3497,6 +3498,8 @@ void GroupCall::destroyScreencast() {
|
||||
if (_screenInstance) {
|
||||
DEBUG_LOG(("Call Info: Destroying call screen controller.."));
|
||||
invalidate_weak_ptrs(&_screenInstanceGuard);
|
||||
|
||||
_screenInstance->stop();
|
||||
crl::async([
|
||||
instance = base::take(_screenInstance),
|
||||
done = _delegate->groupCallAddAsyncWaiter()
|
||||
|
||||
@@ -574,6 +574,7 @@ void ChooseSourceProcess::setupSourcesGeometry() {
|
||||
|
||||
void ChooseSourceProcess::setupGeometryWithParent(
|
||||
not_null<QWidget*> parent) {
|
||||
_window->createWinId();
|
||||
const auto parentScreen = [&] {
|
||||
if (!::Platform::IsWayland()) {
|
||||
if (const auto screen = QGuiApplication::screenAt(
|
||||
@@ -585,7 +586,7 @@ void ChooseSourceProcess::setupGeometryWithParent(
|
||||
}();
|
||||
const auto myScreen = _window->screen();
|
||||
if (parentScreen && myScreen != parentScreen) {
|
||||
_window->setScreen(parentScreen);
|
||||
_window->windowHandle()->setScreen(parentScreen);
|
||||
}
|
||||
_window->move(
|
||||
parent->x() + (parent->width() - _window->width()) / 2,
|
||||
|
||||
@@ -470,7 +470,7 @@ AutocompleteQuery ParseMentionHashtagBotCommandQuery(
|
||||
}
|
||||
return result;
|
||||
} else if (text[i - 1] == '/') {
|
||||
if (i < 2) {
|
||||
if (i < 2 && !fragmentPosition) {
|
||||
result.fromStart = (i == 1) && (fragmentPosition == 0);
|
||||
result.query = text.mid(i - 1, position - fragmentPosition - i + 1);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/history_item.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_session.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/window_session_controller.h"
|
||||
|
||||
namespace {
|
||||
@@ -118,16 +119,21 @@ void HiddenUrlClickHandler::Open(QString url, QVariant context) {
|
||||
? QString::fromUtf8(parsedUrl.toEncoded())
|
||||
: ShowEncoded(displayed);
|
||||
const auto my = context.value<ClickHandlerContext>();
|
||||
if (const auto controller = my.sessionWindow.get()) {
|
||||
controller->show(
|
||||
Ui::MakeConfirmBox({
|
||||
.text = (tr::lng_open_this_link(tr::now)
|
||||
+ qsl("\n\n")
|
||||
+ displayUrl),
|
||||
.confirmed = [=](Fn<void()> hide) { hide(); open(); },
|
||||
.confirmText = tr::lng_open_link(),
|
||||
}),
|
||||
Ui::LayerOption::KeepOther);
|
||||
const auto controller = my.sessionWindow.get();
|
||||
const auto use = controller
|
||||
? &controller->window()
|
||||
: Core::App().activeWindow();
|
||||
auto box = Ui::MakeConfirmBox({
|
||||
.text = (tr::lng_open_this_link(tr::now)
|
||||
+ qsl("\n\n")
|
||||
+ displayUrl),
|
||||
.confirmed = [=](Fn<void()> hide) { hide(); open(); },
|
||||
.confirmText = tr::lng_open_link(),
|
||||
});
|
||||
if (my.show) {
|
||||
my.show->showBox(std::move(box));
|
||||
} else if (use) {
|
||||
use->show(std::move(box), Ui::LayerOption::KeepOther);
|
||||
}
|
||||
} else {
|
||||
open();
|
||||
@@ -182,9 +188,15 @@ void MentionClickHandler::onClick(ClickContext context) const {
|
||||
const auto button = context.button;
|
||||
if (button == Qt::LeftButton || button == Qt::MiddleButton) {
|
||||
const auto my = context.other.value<ClickHandlerContext>();
|
||||
if (const auto controller = my.sessionWindow.get()) {
|
||||
const auto controller = my.sessionWindow.get();
|
||||
const auto use = controller
|
||||
? controller
|
||||
: Core::App().activeWindow()
|
||||
? Core::App().activeWindow()->sessionController()
|
||||
: nullptr;
|
||||
if (use) {
|
||||
using Info = Window::SessionNavigation::PeerByLinkInfo;
|
||||
controller->showPeerByLink(Info{
|
||||
use->showPeerByLink(Info{
|
||||
.usernameOrId = _tag.mid(1),
|
||||
.resolveType = Window::ResolveType::Mention,
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#pragma once
|
||||
|
||||
#include "ui/basic_click_handlers.h"
|
||||
#include "data/data_msg_id.h"
|
||||
|
||||
constexpr auto kPeerLinkPeerIdProperty = 0x01;
|
||||
constexpr auto kPhotoLinkMediaProperty = 0x02;
|
||||
@@ -15,6 +16,10 @@ constexpr auto kDocumentLinkMediaProperty = 0x03;
|
||||
constexpr auto kSendReactionEmojiProperty = 0x04;
|
||||
constexpr auto kReactionsCountEmojiProperty = 0x05;
|
||||
|
||||
namespace Ui {
|
||||
class Show;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
@@ -35,6 +40,7 @@ struct ClickHandlerContext {
|
||||
// Is filled from sections.
|
||||
Fn<HistoryView::ElementDelegate*()> elementDelegate;
|
||||
base::weak_ptr<Window::SessionController> sessionWindow;
|
||||
std::shared_ptr<Ui::Show> show;
|
||||
bool skipBotAutoLogin = false;
|
||||
bool botStartAutoSubmit = false;
|
||||
// Is filled from peer info.
|
||||
|
||||
@@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs;
|
||||
constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs;
|
||||
constexpr auto AppName = "Telegram Desktop"_cs;
|
||||
constexpr auto AppFile = "Telegram"_cs;
|
||||
constexpr auto AppVersion = 3007006;
|
||||
constexpr auto AppVersionStr = "3.7.6";
|
||||
constexpr auto AppBetaVersion = true;
|
||||
constexpr auto AppVersion = 4000002;
|
||||
constexpr auto AppVersionStr = "4.0.2";
|
||||
constexpr auto AppBetaVersion = false;
|
||||
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
|
||||
|
||||
@@ -641,8 +641,9 @@ void Histories::deleteAllMessages(
|
||||
// }
|
||||
}).send();
|
||||
} else if (channel) {
|
||||
using Flag = MTPchannels_DeleteHistory::Flag;
|
||||
return session().api().request(MTPchannels_DeleteHistory(
|
||||
MTP_flags(0),
|
||||
MTP_flags(revoke ? Flag::f_for_everyone : Flag(0)),
|
||||
channel->inputChannel,
|
||||
MTP_int(deleteTillId)
|
||||
)).done(finish).fail(finish).send();
|
||||
|
||||
@@ -148,7 +148,7 @@ enum LocationType {
|
||||
SecureFileLocation = 0xcbc7ee28, // mtpc_inputSecureFileLocation
|
||||
};
|
||||
|
||||
enum FileStatus : char {
|
||||
enum FileStatus : signed char {
|
||||
FileDownloadFailed = -2,
|
||||
FileUploadFailed = -1,
|
||||
FileReady = 1,
|
||||
|
||||
@@ -263,17 +263,27 @@ Widget::Widget(
|
||||
const auto showAtMsgId = controller->uniqueChatsInSearchResults()
|
||||
? ShowAtUnreadMsgId
|
||||
: row.message.fullId.msg;
|
||||
if (row.newWindow) {
|
||||
if (row.newWindow && controller->canShowSeparateWindow(peer)) {
|
||||
const auto active = controller->activeChatCurrent();
|
||||
if (const auto history = active.history()) {
|
||||
if (history->peer == peer) {
|
||||
const auto fromActive = active.history()
|
||||
? (active.history()->peer == peer)
|
||||
: false;
|
||||
const auto toSeparate = [=] {
|
||||
Core::App().ensureSeparateWindowForPeer(
|
||||
peer,
|
||||
showAtMsgId);
|
||||
};
|
||||
if (fromActive) {
|
||||
controller->window().preventOrInvoke([=] {
|
||||
controller->content()->ui_showPeerHistory(
|
||||
0,
|
||||
Window::SectionShow::Way::ClearStack,
|
||||
0);
|
||||
}
|
||||
toSeparate();
|
||||
});
|
||||
} else {
|
||||
toSeparate();
|
||||
}
|
||||
Core::App().ensureSeparateWindowForPeer(peer, showAtMsgId);
|
||||
} else {
|
||||
controller->content()->choosePeer(peer->id, showAtMsgId);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Export {
|
||||
namespace View {
|
||||
namespace {
|
||||
|
||||
constexpr auto kMegabyte = 1024 * 1024;
|
||||
constexpr auto kMegabyte = int64(1024) * 1024;
|
||||
|
||||
[[nodiscard]] PeerId ReadPeerId(
|
||||
not_null<Main::Session*> session,
|
||||
|
||||
@@ -133,10 +133,13 @@ void activateBotCommand(
|
||||
skipConfirmation = true;
|
||||
}
|
||||
}
|
||||
const auto context = QVariant::fromValue(ClickHandlerContext{
|
||||
.sessionWindow = sessionController.get(),
|
||||
});
|
||||
if (skipConfirmation) {
|
||||
UrlClickHandler::Open(url);
|
||||
UrlClickHandler::Open(url, context);
|
||||
} else {
|
||||
HiddenUrlClickHandler::Open(url);
|
||||
HiddenUrlClickHandler::Open(url, context);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
||||
@@ -1218,6 +1218,9 @@ HistoryInner::VideoUserpic *HistoryInner::validateVideoUserpic(
|
||||
return i->second.get();
|
||||
}
|
||||
const auto repaint = [=] {
|
||||
if (hasPendingResizedItems()) {
|
||||
return;
|
||||
}
|
||||
enumerateUserpics([&](not_null<Element*> view, int userpicTop) {
|
||||
// stop the enumeration if the userpic is below the painted rect
|
||||
if (userpicTop >= _visibleAreaBottom) {
|
||||
|
||||
@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "mainwidget.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_domain.h" // Core::App().domain().activate().
|
||||
#include "menu/menu_ttl_validator.h"
|
||||
#include "apiwrap.h"
|
||||
#include "history/history.h"
|
||||
#include "history/view/media/history_view_invoice.h"
|
||||
@@ -1362,7 +1363,11 @@ void HistoryService::createFromMtp(const MTPDmessage &message) {
|
||||
|
||||
void HistoryService::createFromMtp(const MTPDmessageService &message) {
|
||||
const auto type = message.vaction().type();
|
||||
if (type == mtpc_messageActionGameScore) {
|
||||
if (type == mtpc_messageActionSetChatTheme) {
|
||||
setupChatThemeChange();
|
||||
} else if (type == mtpc_messageActionSetMessagesTTL) {
|
||||
setupTTLChange();
|
||||
} else if (type == mtpc_messageActionGameScore) {
|
||||
const auto &data = message.vaction().c_messageActionGameScore();
|
||||
UpdateComponents(HistoryServiceGameScore::Bit());
|
||||
Get<HistoryServiceGameScore>()->score = data.vscore().v;
|
||||
@@ -1525,6 +1530,42 @@ void HistoryService::clearDependency() {
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryService::setupChatThemeChange() {
|
||||
if (const auto user = history()->peer->asUser()) {
|
||||
auto link = std::make_shared<LambdaClickHandler>([=](
|
||||
ClickContext context) {
|
||||
const auto my = context.other.value<ClickHandlerContext>();
|
||||
if (const auto controller = my.sessionWindow.get()) {
|
||||
controller->toggleChooseChatTheme(user);
|
||||
}
|
||||
});
|
||||
|
||||
UpdateComponents(HistoryServiceChatThemeChange::Bit());
|
||||
Get<HistoryServiceChatThemeChange>()->link = std::move(link);
|
||||
} else {
|
||||
RemoveComponents(HistoryServiceChatThemeChange::Bit());
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryService::setupTTLChange() {
|
||||
const auto peer = history()->peer;
|
||||
auto link = std::make_shared<LambdaClickHandler>([=](
|
||||
ClickContext context) {
|
||||
const auto my = context.other.value<ClickHandlerContext>();
|
||||
if (const auto controller = my.sessionWindow.get()) {
|
||||
const auto validator = TTLMenu::TTLValidator(
|
||||
std::make_shared<Window::Show>(controller),
|
||||
peer);
|
||||
if (validator.can()) {
|
||||
validator.showBox();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
UpdateComponents(HistoryServiceTTLChange::Bit());
|
||||
Get<HistoryServiceTTLChange>()->link = std::move(link);
|
||||
}
|
||||
|
||||
void HistoryService::dependencyItemRemoved(HistoryItem *dependency) {
|
||||
clearDependency();
|
||||
updateDependentText();
|
||||
|
||||
@@ -59,6 +59,16 @@ struct HistoryServiceOngoingCall
|
||||
rpl::lifetime lifetime;
|
||||
};
|
||||
|
||||
struct HistoryServiceChatThemeChange
|
||||
: public RuntimeComponent<HistoryServiceChatThemeChange, HistoryItem> {
|
||||
ClickHandlerPtr link;
|
||||
};
|
||||
|
||||
struct HistoryServiceTTLChange
|
||||
: public RuntimeComponent<HistoryServiceTTLChange, HistoryItem> {
|
||||
ClickHandlerPtr link;
|
||||
};
|
||||
|
||||
namespace HistoryView {
|
||||
class ServiceMessagePainter;
|
||||
} // namespace HistoryView
|
||||
@@ -155,6 +165,8 @@ private:
|
||||
void updateDependentText();
|
||||
void updateText(PreparedText &&text);
|
||||
void clearDependency();
|
||||
void setupChatThemeChange();
|
||||
void setupTTLChange();
|
||||
|
||||
void createFromMtp(const MTPDmessage &message);
|
||||
void createFromMtp(const MTPDmessageService &message);
|
||||
|
||||
@@ -737,8 +737,10 @@ HistoryWidget::HistoryWidget(
|
||||
if (flags & PeerUpdateFlag::UnavailableReason) {
|
||||
const auto unavailable = _peer->computeUnavailableReason();
|
||||
if (!unavailable.isEmpty()) {
|
||||
controller->showBackFromStack();
|
||||
controller->show(Ui::MakeInformBox(unavailable));
|
||||
closeCurrent();
|
||||
if (const auto primary = Core::App().primaryWindow()) {
|
||||
primary->show(Ui::MakeInformBox(unavailable));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1595,6 +1597,12 @@ void HistoryWidget::fieldChanged() {
|
||||
updateSendButtonType();
|
||||
if (!HasSendText(_field)) {
|
||||
_previewState = Data::PreviewState::Allowed;
|
||||
_fieldIsEmpty = true;
|
||||
} else if (_fieldIsEmpty) {
|
||||
_fieldIsEmpty = false;
|
||||
if (_kbShown) {
|
||||
toggleKeyboard();
|
||||
}
|
||||
}
|
||||
if (updateCmdStartShown()) {
|
||||
updateControlsVisibility();
|
||||
@@ -2932,7 +2940,7 @@ void HistoryWidget::unreadCountUpdated() {
|
||||
if (_history->chatListUnreadMark()) {
|
||||
crl::on_main(this, [=, history = _history] {
|
||||
if (history == _history) {
|
||||
controller()->showBackFromStack();
|
||||
closeCurrent();
|
||||
_cancelRequests.fire({});
|
||||
}
|
||||
});
|
||||
@@ -2942,6 +2950,14 @@ void HistoryWidget::unreadCountUpdated() {
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::closeCurrent() {
|
||||
if (controller()->isPrimary()) {
|
||||
controller()->showBackFromStack();
|
||||
} else {
|
||||
controller()->window().close();
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::messagesFailed(const MTP::Error &error, int requestId) {
|
||||
if (error.type() == qstr("CHANNEL_PRIVATE")
|
||||
&& _peer->isChannel()
|
||||
@@ -2951,13 +2967,15 @@ void HistoryWidget::messagesFailed(const MTP::Error &error, int requestId) {
|
||||
|| error.type() == qstr("CHANNEL_PUBLIC_GROUP_NA")
|
||||
|| error.type() == qstr("USER_BANNED_IN_CHANNEL")) {
|
||||
auto was = _peer;
|
||||
controller()->showBackFromStack();
|
||||
Ui::ShowMultilineToast({
|
||||
.parentOverride = Window::Show(controller()).toastParent(),
|
||||
.text = { (was && was->isMegagroup())
|
||||
? tr::lng_group_not_accessible(tr::now)
|
||||
: tr::lng_channel_not_accessible(tr::now) },
|
||||
});
|
||||
closeCurrent();
|
||||
if (const auto primary = Core::App().primaryWindow()) {
|
||||
Ui::ShowMultilineToast({
|
||||
.parentOverride = Window::Show(primary).toastParent(),
|
||||
.text = { (was && was->isMegagroup())
|
||||
? tr::lng_group_not_accessible(tr::now)
|
||||
: tr::lng_channel_not_accessible(tr::now) },
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2972,7 +2990,7 @@ void HistoryWidget::messagesFailed(const MTP::Error &error, int requestId) {
|
||||
_preloadDownRequest = 0;
|
||||
} else if (_firstLoadRequest == requestId) {
|
||||
_firstLoadRequest = 0;
|
||||
controller()->showBackFromStack();
|
||||
closeCurrent();
|
||||
} else if (_delayedShowAtRequest == requestId) {
|
||||
_delayedShowAtRequest = 0;
|
||||
}
|
||||
|
||||
@@ -390,6 +390,7 @@ private:
|
||||
void handleHistoryChange(not_null<const History*> history);
|
||||
void showAboutTopPromotion();
|
||||
void unreadCountUpdated();
|
||||
void closeCurrent();
|
||||
|
||||
[[nodiscard]] int computeMaxFieldHeight() const;
|
||||
void toggleMuteUnmute();
|
||||
@@ -742,6 +743,7 @@ private:
|
||||
bool _inClickable = false;
|
||||
|
||||
bool _kbShown = false;
|
||||
bool _fieldIsEmpty = true;
|
||||
HistoryItem *_kbReplyTo = nullptr;
|
||||
object_ptr<Ui::ScrollArea> _kbScroll;
|
||||
const not_null<BotKeyboard*> _keyboard;
|
||||
|
||||
@@ -408,6 +408,7 @@ void ListenWrap::initPlayButton() {
|
||||
using State = TrackState;
|
||||
|
||||
_mediaView->setBytes(_data->bytes);
|
||||
_document->size = _data->bytes.size();
|
||||
_document->type = VoiceDocument;
|
||||
|
||||
const auto &play = _playPauseSt.playOuter;
|
||||
@@ -1415,7 +1416,6 @@ void VoiceRecordBar::hideFast() {
|
||||
hide();
|
||||
_lock->hide();
|
||||
_level->hide();
|
||||
stopRecording(StopType::Cancel);
|
||||
}
|
||||
|
||||
void VoiceRecordBar::stopRecording(StopType type) {
|
||||
@@ -1542,7 +1542,10 @@ void VoiceRecordBar::hideAnimated() {
|
||||
return;
|
||||
}
|
||||
_lockShowing = false;
|
||||
visibilityAnimate(false, [=] { hideFast(); });
|
||||
visibilityAnimate(false, [=] {
|
||||
hideFast();
|
||||
stopRecording(StopType::Cancel);
|
||||
});
|
||||
}
|
||||
|
||||
void VoiceRecordBar::finishAnimating() {
|
||||
@@ -1676,6 +1679,7 @@ void VoiceRecordBar::showDiscardBox(
|
||||
auto sure = [=, callback = std::move(callback)](Fn<void()> &&close) {
|
||||
if (animated == anim::type::instant) {
|
||||
hideFast();
|
||||
stopRecording(StopType::Cancel);
|
||||
} else {
|
||||
hideAnimated();
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/text/text_options.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "mainwidget.h"
|
||||
#include "menu/menu_ttl_validator.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "styles/style_chat.h"
|
||||
|
||||
@@ -613,6 +614,12 @@ TextState Service::textState(QPoint point, StateRequest request) const {
|
||||
if (PeerHasThisCall(peer, call->id).value_or(false)) {
|
||||
result.link = call->link;
|
||||
}
|
||||
} else if (const auto theme = item->Get<HistoryServiceChatThemeChange>()) {
|
||||
result.link = theme->link;
|
||||
} else if (const auto ttl = item->Get<HistoryServiceTTLChange>()) {
|
||||
if (TTLMenu::TTLValidator(nullptr, history()->peer).can()) {
|
||||
result.link = ttl->link;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (media) {
|
||||
|
||||
@@ -12,12 +12,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "data/data_session.h"
|
||||
#include "main/main_session.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "boxes/sticker_set_box.h"
|
||||
#include "lottie/lottie_single_player.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "apiwrap.h"
|
||||
#include "styles/style_chat.h"
|
||||
|
||||
namespace HistoryView {
|
||||
@@ -36,7 +38,9 @@ StickerToast::StickerToast(
|
||||
, _destroy(std::move(destroy)) {
|
||||
}
|
||||
|
||||
StickerToast::~StickerToast() = default;
|
||||
StickerToast::~StickerToast() {
|
||||
cancelRequest();
|
||||
}
|
||||
|
||||
void StickerToast::showFor(not_null<DocumentData*> document) {
|
||||
const auto sticker = document->sticker();
|
||||
@@ -49,11 +53,76 @@ void StickerToast::showFor(not_null<DocumentData*> document) {
|
||||
return;
|
||||
}
|
||||
strong->hideAnimated();
|
||||
} else if (_setRequestId) {
|
||||
if (_for == document) {
|
||||
return;
|
||||
}
|
||||
cancelRequest();
|
||||
}
|
||||
_for = document;
|
||||
|
||||
const auto title = lookupTitle();
|
||||
if (!title.isEmpty()) {
|
||||
showWithTitle(title);
|
||||
} else {
|
||||
requestSet();
|
||||
}
|
||||
}
|
||||
|
||||
QString StickerToast::lookupTitle() const {
|
||||
Expects(_for != nullptr);
|
||||
|
||||
const auto sticker = _for->sticker();
|
||||
if (!sticker) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto id = sticker->set.id;
|
||||
if (!id) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto &sets = _for->owner().stickers().sets();
|
||||
const auto i = sets.find(id);
|
||||
if (i == end(sets)) {
|
||||
return {};
|
||||
}
|
||||
return i->second->title;
|
||||
}
|
||||
|
||||
void StickerToast::requestSet() {
|
||||
Expects(_for != nullptr);
|
||||
|
||||
if (const auto sticker = _for->sticker()) {
|
||||
const auto api = &_controller->session().api();
|
||||
_setRequestId = api->request(MTPmessages_GetStickerSet(
|
||||
Data::InputStickerSet(sticker->set),
|
||||
MTP_int(0) // hash
|
||||
)).done([=](const MTPmessages_StickerSet &result) {
|
||||
_setRequestId = 0;
|
||||
result.match([&](const MTPDmessages_stickerSet &data) {
|
||||
data.vset().match([&](const MTPDstickerSet &data) {
|
||||
const auto owner = &_controller->session().data();
|
||||
showWithTitle(owner->stickers().getSetTitle(data));
|
||||
});
|
||||
}, [&](const MTPDmessages_stickerSetNotModified &) {
|
||||
LOG(("API Error: Got messages.stickerSetNotModified."));
|
||||
});
|
||||
}).fail([=] {
|
||||
_setRequestId = 0;
|
||||
}).send();
|
||||
}
|
||||
}
|
||||
|
||||
void StickerToast::cancelRequest() {
|
||||
_controller->session().api().request(base::take(_setRequestId)).cancel();
|
||||
}
|
||||
|
||||
void StickerToast::showWithTitle(const QString &title) {
|
||||
Expects(_for != nullptr);
|
||||
|
||||
const auto text = Ui::Text::Bold(
|
||||
tr::lng_sticker_premium_title(tr::now)
|
||||
title
|
||||
).append('\n').append(
|
||||
tr::lng_sticker_premium_text(tr::now)
|
||||
);
|
||||
@@ -98,8 +167,8 @@ void StickerToast::showFor(not_null<DocumentData*> document) {
|
||||
preview->resize(size, size);
|
||||
preview->show();
|
||||
|
||||
const auto bytes = document->createMediaView()->bytes();
|
||||
const auto filepath = document->filepath();
|
||||
const auto bytes = _for->createMediaView()->bytes();
|
||||
const auto filepath = _for->filepath();
|
||||
const auto player = preview->lifetime().make_state<Lottie::SinglePlayer>(
|
||||
Lottie::ReadContent(bytes, filepath),
|
||||
Lottie::FrameRequest{ QSize(size, size) },
|
||||
@@ -122,7 +191,7 @@ void StickerToast::showFor(not_null<DocumentData*> document) {
|
||||
|
||||
button->setClickedCallback([=, weak = _weak] {
|
||||
_controller->show(
|
||||
Box<StickerSetBox>(_controller, document->sticker()->set),
|
||||
Box<StickerSetBox>(_controller, _for->sticker()->set),
|
||||
Ui::LayerOption::KeepOther);
|
||||
if (const auto strong = weak.get()) {
|
||||
strong->hideAnimated();
|
||||
|
||||
@@ -34,6 +34,11 @@ public:
|
||||
void showFor(not_null<DocumentData*> document);
|
||||
|
||||
private:
|
||||
void requestSet();
|
||||
void cancelRequest();
|
||||
void showWithTitle(const QString &title);
|
||||
[[nodiscard]] QString lookupTitle() const;
|
||||
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
const not_null<QWidget*> _parent;
|
||||
style::Toast _st;
|
||||
@@ -41,6 +46,8 @@ private:
|
||||
DocumentData *_for = nullptr;
|
||||
Fn<void()> _destroy;
|
||||
|
||||
mtpRequestId _setRequestId = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace HistoryView
|
||||
|
||||
@@ -513,9 +513,10 @@ void TopBarWidget::paintTopBar(Painter &p) {
|
||||
const auto peer = history->peer;
|
||||
const auto &text = peer->topBarNameText();
|
||||
const auto badgeStyle = Ui::PeerBadgeStyle{
|
||||
nullptr, // verified
|
||||
&st::dialogsPremiumIcon, // premium
|
||||
&st::attentionButtonFg };
|
||||
&st::dialogsVerifiedIcon,
|
||||
&st::dialogsPremiumIcon,
|
||||
&st::attentionButtonFg,
|
||||
};
|
||||
const auto badgeWidth = Ui::DrawPeerBadgeGetWidth(
|
||||
peer,
|
||||
p,
|
||||
|
||||
@@ -177,7 +177,8 @@ void Cover::initViewers(rpl::producer<QString> title) {
|
||||
BadgeValue(
|
||||
_peer
|
||||
) | rpl::start_with_next([=](Badge badge) {
|
||||
if (badge == Badge::Premium && !_peer->session().premiumPossible()) {
|
||||
if (badge == Badge::Premium
|
||||
&& !_peer->session().premiumBadgesShown()) {
|
||||
badge = Badge::None;
|
||||
}
|
||||
setBadge(badge);
|
||||
|
||||
@@ -479,14 +479,14 @@ rpl::producer<Badge> BadgeValueFromFlags(Peer peer) {
|
||||
Flag::Verified | Flag::Scam | Flag::Fake),
|
||||
Data::PeerPremiumValue(peer)
|
||||
) | rpl::map([=](base::flags<Flag> value, bool premium) {
|
||||
return (value & Flag::Verified)
|
||||
? Badge::Verified
|
||||
: premium
|
||||
? Badge::Premium
|
||||
: (value & Flag::Scam)
|
||||
return (value & Flag::Scam)
|
||||
? Badge::Scam
|
||||
: (value & Flag::Fake)
|
||||
? Badge::Fake
|
||||
: (value & Flag::Verified)
|
||||
? Badge::Verified
|
||||
: premium
|
||||
? Badge::Premium
|
||||
: Badge::None;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -236,6 +236,10 @@ bool Session::premiumPossible() const {
|
||||
return premium() || _premiumPossible.current();
|
||||
}
|
||||
|
||||
bool Session::premiumBadgesShown() const {
|
||||
return supportMode() || premiumPossible();
|
||||
}
|
||||
|
||||
rpl::producer<bool> Session::premiumPossibleValue() const {
|
||||
using namespace rpl::mappers;
|
||||
|
||||
|
||||
@@ -83,6 +83,7 @@ public:
|
||||
[[nodiscard]] bool premium() const;
|
||||
[[nodiscard]] bool premiumPossible() const;
|
||||
[[nodiscard]] rpl::producer<bool> premiumPossibleValue() const;
|
||||
[[nodiscard]] bool premiumBadgesShown() const;
|
||||
|
||||
[[nodiscard]] uint64 uniqueId() const; // userId() with TestDC shift.
|
||||
[[nodiscard]] UserId userId() const;
|
||||
|
||||
@@ -1314,6 +1314,7 @@ void MainWidget::ui_showPeerHistory(
|
||||
}
|
||||
const auto unavailable = peer->computeUnavailableReason();
|
||||
if (!unavailable.isEmpty()) {
|
||||
Assert(isPrimary());
|
||||
if (params.activation != anim::activation::background) {
|
||||
controller()->show(Ui::MakeInformBox(unavailable));
|
||||
}
|
||||
|
||||
@@ -280,6 +280,7 @@ void MainWindow::setupMain(MsgId singlePeerShowAtMsgId) {
|
||||
clearWidgets();
|
||||
_main = std::move(created);
|
||||
if (const auto peer = singlePeer()) {
|
||||
updateControlsGeometry();
|
||||
_main->controller()->showPeerHistory(
|
||||
peer,
|
||||
Window::SectionShow::Way::ClearStack,
|
||||
|
||||
@@ -501,7 +501,7 @@ void OverlayWidget::moveToScreen(bool inMove) {
|
||||
DEBUG_LOG(("Viewer Pos: Currently on screen %1, moving to screen %2")
|
||||
.arg(screenList.indexOf(myScreen))
|
||||
.arg(screenList.indexOf(activeWindowScreen)));
|
||||
_widget->setScreen(activeWindowScreen);
|
||||
window()->setScreen(activeWindowScreen);
|
||||
DEBUG_LOG(("Viewer Pos: New actual screen: %1")
|
||||
.arg(screenList.indexOf(_widget->screen())));
|
||||
}
|
||||
|
||||
@@ -475,7 +475,7 @@ void PipPanel::setPositionDefault() {
|
||||
const auto parentScreen = widgetScreen(_parent);
|
||||
const auto myScreen = widgetScreen(widget());
|
||||
if (parentScreen && myScreen && myScreen != parentScreen) {
|
||||
widget()->setScreen(parentScreen);
|
||||
widget()->windowHandle()->setScreen(parentScreen);
|
||||
}
|
||||
auto position = Position();
|
||||
position.snapped = RectPart::Top | RectPart::Left;
|
||||
|
||||
@@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "core/local_url_handlers.h" // TryConvertUrlToLocal.
|
||||
#include "core/file_utilities.h" // File::OpenUrl.
|
||||
#include "core/core_cloud_password.h" // Core::CloudPasswordState
|
||||
#include "core/click_handler_types.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_cloud_password.h"
|
||||
@@ -808,6 +809,12 @@ void CheckoutProcess::panelShowBox(object_ptr<Ui::BoxContent> box) {
|
||||
_panel->showBox(std::move(box));
|
||||
}
|
||||
|
||||
QVariant CheckoutProcess::panelClickHandlerContext() {
|
||||
return QVariant::fromValue(ClickHandlerContext{
|
||||
.show = _panel->uiShow(),
|
||||
});
|
||||
}
|
||||
|
||||
void CheckoutProcess::performInitialSilentValidation() {
|
||||
const auto &invoice = _form->invoice();
|
||||
const auto &saved = _form->information();
|
||||
|
||||
@@ -147,6 +147,7 @@ private:
|
||||
Ui::UncheckedCardDetails data,
|
||||
bool saveInformation) override;
|
||||
void panelShowBox(object_ptr<Ui::BoxContent> box) override;
|
||||
QVariant panelClickHandlerContext() override;
|
||||
|
||||
QString panelWebviewDataPath() override;
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/effects/radial_animation.h"
|
||||
#include "ui/click_handler.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "webview/webview_embed.h"
|
||||
#include "webview/webview_interface.h"
|
||||
@@ -679,6 +680,17 @@ void Panel::requestTermsAcceptance(
|
||||
st::boxRowPadding.right(),
|
||||
st::defaultBoxCheckbox.margin.bottom(),
|
||||
});
|
||||
row->setAllowTextLines(5);
|
||||
row->setClickHandlerFilter([=](
|
||||
const ClickHandlerPtr &link,
|
||||
Qt::MouseButton button) {
|
||||
ActivateClickHandler(_widget.get(), link, ClickContext{
|
||||
.button = button,
|
||||
.other = _delegate->panelClickHandlerContext(),
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
(*update) = [=] { row->update(); };
|
||||
|
||||
struct State {
|
||||
@@ -830,6 +842,10 @@ void Panel::showCriticalError(const TextWithEntities &text) {
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Show> Panel::uiShow() {
|
||||
return _widget->uiShow();
|
||||
}
|
||||
|
||||
void Panel::showWebviewError(
|
||||
const QString &text,
|
||||
const Webview::Available &information) {
|
||||
|
||||
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/object_ptr.h"
|
||||
|
||||
namespace Ui {
|
||||
class Show;
|
||||
class RpWidget;
|
||||
class SeparatePanel;
|
||||
class BoxContent;
|
||||
@@ -85,6 +86,7 @@ public:
|
||||
void showBox(object_ptr<Ui::BoxContent> box);
|
||||
void showToast(const TextWithEntities &text);
|
||||
void showCriticalError(const TextWithEntities &text);
|
||||
[[nodiscard]] std::shared_ptr<Show> uiShow();
|
||||
|
||||
[[nodiscard]] rpl::lifetime &lifetime();
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ public:
|
||||
Ui::UncheckedCardDetails data,
|
||||
bool saveInformation) = 0;
|
||||
virtual void panelShowBox(object_ptr<BoxContent> box) = 0;
|
||||
virtual QVariant panelClickHandlerContext() = 0;
|
||||
|
||||
virtual QString panelWebviewDataPath() = 0;
|
||||
};
|
||||
|
||||
@@ -419,6 +419,10 @@ rpl::producer<> Tray::iconClicks() const {
|
||||
return _iconClicks.events();
|
||||
}
|
||||
|
||||
bool Tray::hasIcon() const {
|
||||
return _icon;
|
||||
}
|
||||
|
||||
rpl::lifetime &Tray::lifetime() {
|
||||
return _lifetime;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ public:
|
||||
[[nodiscard]] rpl::producer<> hideToTrayRequests() const;
|
||||
[[nodiscard]] rpl::producer<> iconClicks() const;
|
||||
|
||||
[[nodiscard]] bool hasIcon() const;
|
||||
|
||||
void createIcon();
|
||||
void destroyIcon();
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ public:
|
||||
[[nodiscard]] rpl::producer<> hideToTrayRequests() const;
|
||||
[[nodiscard]] rpl::producer<> iconClicks() const;
|
||||
|
||||
[[nodiscard]] bool hasIcon() const;
|
||||
|
||||
void createIcon();
|
||||
void destroyIcon();
|
||||
|
||||
|
||||
@@ -413,6 +413,10 @@ rpl::producer<> Tray::iconClicks() const {
|
||||
return rpl::never<>();
|
||||
}
|
||||
|
||||
bool Tray::hasIcon() const {
|
||||
return _nativeIcon != nullptr;
|
||||
}
|
||||
|
||||
rpl::lifetime &Tray::lifetime() {
|
||||
return _lifetime;
|
||||
}
|
||||
|
||||
@@ -12,35 +12,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "core/sandbox.h"
|
||||
#include "base/platform/win/base_windows_winrt.h"
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QAbstractNativeEventFilter>
|
||||
|
||||
namespace Platform {
|
||||
namespace {
|
||||
|
||||
class WindowsIntegration final
|
||||
: public Integration
|
||||
, public QAbstractNativeEventFilter {
|
||||
public:
|
||||
void init() override;
|
||||
|
||||
private:
|
||||
bool nativeEventFilter(
|
||||
const QByteArray &eventType,
|
||||
void *message,
|
||||
long *result) override;
|
||||
bool processEvent(
|
||||
HWND hWnd,
|
||||
UINT msg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam,
|
||||
LRESULT *result);
|
||||
|
||||
};
|
||||
|
||||
void WindowsIntegration::init() {
|
||||
QCoreApplication::instance()->installNativeEventFilter(this);
|
||||
_taskbarCreatedMsgId = RegisterWindowMessage(L"TaskbarButtonCreated");
|
||||
}
|
||||
|
||||
ITaskbarList3 *WindowsIntegration::taskbarList() const {
|
||||
return _taskbarList.get();
|
||||
}
|
||||
|
||||
WindowsIntegration &WindowsIntegration::Instance() {
|
||||
return static_cast<WindowsIntegration&>(Integration::Instance());
|
||||
}
|
||||
|
||||
bool WindowsIntegration::nativeEventFilter(
|
||||
@@ -64,6 +53,12 @@ bool WindowsIntegration::processEvent(
|
||||
WPARAM wParam,
|
||||
LPARAM lParam,
|
||||
LRESULT *result) {
|
||||
if (msg && msg == _taskbarCreatedMsgId && !_taskbarList) {
|
||||
_taskbarList = base::WinRT::TryCreateInstance<ITaskbarList3>(
|
||||
CLSID_TaskbarList,
|
||||
CLSCTX_ALL);
|
||||
}
|
||||
|
||||
switch (msg) {
|
||||
case WM_ENDSESSION:
|
||||
Core::Quit();
|
||||
@@ -90,8 +85,6 @@ bool WindowsIntegration::processEvent(
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<Integration> CreateIntegration() {
|
||||
return std::make_unique<WindowsIntegration>();
|
||||
}
|
||||
|
||||
@@ -7,9 +7,41 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "platform/platform_integration.h"
|
||||
|
||||
#include <QAbstractNativeEventFilter>
|
||||
|
||||
#include <winrt/base.h>
|
||||
#include <ShlObj.h>
|
||||
|
||||
namespace Platform {
|
||||
|
||||
class Integration;
|
||||
class WindowsIntegration final
|
||||
: public Integration
|
||||
, public QAbstractNativeEventFilter {
|
||||
public:
|
||||
void init() override;
|
||||
|
||||
[[nodiscard]] ITaskbarList3 *taskbarList() const;
|
||||
|
||||
[[nodiscard]] static WindowsIntegration &Instance();
|
||||
|
||||
private:
|
||||
bool nativeEventFilter(
|
||||
const QByteArray &eventType,
|
||||
void *message,
|
||||
long *result) override;
|
||||
bool processEvent(
|
||||
HWND hWnd,
|
||||
UINT msg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam,
|
||||
LRESULT *result);
|
||||
|
||||
uint32 _taskbarCreatedMsgId = 0;
|
||||
winrt::com_ptr<ITaskbarList3> _taskbarList;
|
||||
|
||||
};
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Integration> CreateIntegration();
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "platform/platform_notifications_manager.h"
|
||||
#include "platform/win/tray_win.h"
|
||||
#include "platform/win/windows_dlls.h"
|
||||
#include "platform/win/integration_win.h"
|
||||
#include "window/notifications_manager.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "mainwindow.h"
|
||||
@@ -82,9 +83,7 @@ private:
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
ComPtr<ITaskbarList3> taskbarList;
|
||||
bool handleSessionNotification = false;
|
||||
uint32 kTaskbarCreatedMsgId = 0;
|
||||
|
||||
[[nodiscard]] HICON NativeIcon(const QIcon &icon, QSize size) {
|
||||
if (!icon.isNull()) {
|
||||
@@ -124,15 +123,6 @@ bool EventFilter::mainWindowEvent(
|
||||
WPARAM wParam,
|
||||
LPARAM lParam,
|
||||
LRESULT *result) {
|
||||
if (const auto tbCreatedMsgId = kTaskbarCreatedMsgId) {
|
||||
if (msg == tbCreatedMsgId) {
|
||||
HRESULT hr = CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&taskbarList));
|
||||
if (!SUCCEEDED(hr)) {
|
||||
taskbarList.Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (msg) {
|
||||
|
||||
case WM_DESTROY: {
|
||||
@@ -179,9 +169,6 @@ MainWindow::MainWindow(not_null<Window::Controller*> controller)
|
||||
, _taskbarHiderWindow(std::make_unique<QWindow>()) {
|
||||
qApp->installNativeEventFilter(&_private->filter);
|
||||
|
||||
if (!kTaskbarCreatedMsgId) {
|
||||
kTaskbarCreatedMsgId = RegisterWindowMessage(L"TaskbarButtonCreated");
|
||||
}
|
||||
setupNativeWindowFrame();
|
||||
|
||||
using namespace rpl::mappers;
|
||||
@@ -356,7 +343,9 @@ void MainWindow::updateIconCounters() {
|
||||
QIcon iconSmall, iconBig;
|
||||
iconSmall.addPixmap(iconSmallPixmap16);
|
||||
iconSmall.addPixmap(iconSmallPixmap32);
|
||||
const auto bigCounter = taskbarList.Get() ? 0 : counter;
|
||||
const auto integration = &Platform::WindowsIntegration::Instance();
|
||||
const auto taskbarList = integration->taskbarList();
|
||||
const auto bigCounter = taskbarList ? 0 : counter;
|
||||
iconBig.addPixmap(Tray::IconWithCounter(
|
||||
Tray::CounterLayerArgs(32, bigCounter, muted),
|
||||
false,
|
||||
@@ -528,9 +517,6 @@ void MainWindow::destroyCachedIcons() {
|
||||
MainWindow::~MainWindow() {
|
||||
WTSUnRegisterSessionNotification(_hWnd);
|
||||
_private->viewSettings.Reset();
|
||||
if (taskbarList) {
|
||||
taskbarList.Reset();
|
||||
}
|
||||
destroyCachedIcons();
|
||||
}
|
||||
|
||||
|
||||
@@ -440,6 +440,7 @@ private:
|
||||
const QString &subtitle,
|
||||
const QString &msg,
|
||||
DisplayOptions options);
|
||||
void tryHide(const ToastNotification ¬ification);
|
||||
[[nodiscard]] std::wstring ensureSendButtonIcon();
|
||||
|
||||
Window::Notifications::CachedUserpics _cachedUserpics;
|
||||
@@ -485,7 +486,7 @@ void Manager::Private::clearAll() {
|
||||
|
||||
for (const auto &[key, notifications] : base::take(_notifications)) {
|
||||
for (const auto &[msgId, notification] : notifications) {
|
||||
_notifier.Hide(notification);
|
||||
tryHide(notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -511,7 +512,7 @@ void Manager::Private::clearFromItem(not_null<HistoryItem*> item) {
|
||||
if (i->second.empty()) {
|
||||
_notifications.erase(i);
|
||||
}
|
||||
_notifier.Hide(taken);
|
||||
tryHide(taken);
|
||||
}
|
||||
|
||||
void Manager::Private::clearFromHistory(not_null<History*> history) {
|
||||
@@ -528,7 +529,7 @@ void Manager::Private::clearFromHistory(not_null<History*> history) {
|
||||
_notifications.erase(i);
|
||||
|
||||
for (const auto &[msgId, notification] : temp) {
|
||||
_notifier.Hide(notification);
|
||||
tryHide(notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -548,7 +549,7 @@ void Manager::Private::clearFromSession(not_null<Main::Session*> session) {
|
||||
_notifications.erase(i);
|
||||
|
||||
for (const auto &[msgId, notification] : temp) {
|
||||
_notifier.Hide(notification);
|
||||
tryHide(notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -807,7 +808,7 @@ bool Manager::Private::showNotificationInTryCatch(
|
||||
if (j != i->second.end()) {
|
||||
const auto existing = j->second;
|
||||
i->second.erase(j);
|
||||
_notifier.Hide(existing);
|
||||
tryHide(existing);
|
||||
i = _notifications.find(key);
|
||||
}
|
||||
}
|
||||
@@ -827,7 +828,14 @@ bool Manager::Private::showNotificationInTryCatch(
|
||||
return true;
|
||||
}
|
||||
|
||||
Manager::Manager(Window::Notifications::System *system) : NativeManager(system)
|
||||
void Manager::Private::tryHide(const ToastNotification ¬ification) {
|
||||
base::WinRT::Try([&] {
|
||||
_notifier.Hide(notification);
|
||||
});
|
||||
}
|
||||
|
||||
Manager::Manager(Window::Notifications::System *system)
|
||||
: NativeManager(system)
|
||||
, _private(std::make_unique<Private>(this, Private::Type::Rounded)) {
|
||||
}
|
||||
|
||||
|
||||
@@ -231,6 +231,10 @@ rpl::producer<> Tray::iconClicks() const {
|
||||
return _iconClicks.events();
|
||||
}
|
||||
|
||||
bool Tray::hasIcon() const {
|
||||
return _icon;
|
||||
}
|
||||
|
||||
rpl::lifetime &Tray::lifetime() {
|
||||
return _lifetime;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ public:
|
||||
[[nodiscard]] rpl::producer<> hideToTrayRequests() const;
|
||||
[[nodiscard]] rpl::producer<> iconClicks() const;
|
||||
|
||||
[[nodiscard]] bool hasIcon() const;
|
||||
|
||||
void createIcon();
|
||||
void destroyIcon();
|
||||
|
||||
|
||||
@@ -402,7 +402,7 @@ void GroupMembersWidget::setItemFlags(
|
||||
const auto rankIt = megagroup->mgInfo->admins.find(peerToUser(user->id));
|
||||
const auto adminCanEdit = isAdmin && adminIt->second.canEdit;
|
||||
const auto rank = (amCreator || isCreator)
|
||||
? (megagroup->mgInfo->creatorRank.isEmpty()
|
||||
? (!megagroup->mgInfo->creatorRank.isEmpty()
|
||||
? megagroup->mgInfo->creatorRank
|
||||
: tr::lng_owner_badge(tr::now))
|
||||
: (amAdmin || isAdmin)
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace {
|
||||
// max 512kb uploaded at the same time in each session
|
||||
constexpr auto kMaxUploadFileParallelSize = MTP::kUploadSessionsCount * 512 * 1024;
|
||||
|
||||
constexpr auto kDocumentMaxPartsCount = 8000;
|
||||
constexpr auto kDocumentMaxPartsCountDefault = 4000;
|
||||
|
||||
// 32kb for tiny document ( < 1mb )
|
||||
constexpr auto kDocumentUploadPartSize0 = 32 * 1024;
|
||||
@@ -120,9 +120,7 @@ void Uploader::File::setDocSize(int64 size) {
|
||||
if (docSize > limit1 || !setPartSize(kDocumentUploadPartSize1)) {
|
||||
if (!setPartSize(kDocumentUploadPartSize2)) {
|
||||
if (!setPartSize(kDocumentUploadPartSize3)) {
|
||||
if (!setPartSize(kDocumentUploadPartSize4)) {
|
||||
LOG(("Upload Error: bad doc size: %1").arg(docSize));
|
||||
}
|
||||
setPartSize(kDocumentUploadPartSize4);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -133,7 +131,7 @@ bool Uploader::File::setPartSize(uint32 partSize) {
|
||||
docPartSize = partSize;
|
||||
docPartsCount = (docSize / docPartSize)
|
||||
+ ((docSize % docPartSize) ? 1 : 0);
|
||||
return (docPartsCount <= kDocumentMaxPartsCount);
|
||||
return (docPartsCount <= kDocumentMaxPartsCountDefault);
|
||||
}
|
||||
|
||||
uint64 Uploader::File::id() const {
|
||||
|
||||
@@ -165,8 +165,8 @@ MimeDataState ComputeMimeDataState(const QMimeData *data) {
|
||||
const auto filesize = info.size();
|
||||
if (filesize > kFileSizePremiumLimit) {
|
||||
return MimeDataState::None;
|
||||
} else if (filesize > kFileSizeLimit) {
|
||||
return MimeDataState::PremiumFile;
|
||||
//} else if (filesize > kFileSizeLimit) {
|
||||
// return MimeDataState::PremiumFile;
|
||||
} else if (allAreSmallImages) {
|
||||
if (filesize > Images::kReadBytesLimit) {
|
||||
allAreSmallImages = false;
|
||||
|
||||
@@ -23,7 +23,7 @@ enum class MimeDataState {
|
||||
None,
|
||||
Files,
|
||||
PhotoFiles,
|
||||
PremiumFile,
|
||||
//PremiumFile,
|
||||
Image,
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "platform/platform_specific.h"
|
||||
|
||||
#include <QtWidgets/QApplication>
|
||||
|
||||
@@ -19,17 +20,20 @@ Tray::Tray() {
|
||||
|
||||
void Tray::create() {
|
||||
rebuildMenu();
|
||||
if (Core::App().settings().workMode() != Settings::WorkMode::WindowOnly) {
|
||||
using WorkMode = Settings::WorkMode;
|
||||
if (Platform::TrayIconSupported()
|
||||
&& (Core::App().settings().workMode() != WorkMode::WindowOnly)) {
|
||||
_tray.createIcon();
|
||||
}
|
||||
|
||||
Core::App().settings().workModeValue(
|
||||
) | rpl::combine_previous(
|
||||
) | rpl::start_with_next([=](
|
||||
Settings::WorkMode previous,
|
||||
Settings::WorkMode state) {
|
||||
const auto wasHasIcon = (previous != Settings::WorkMode::WindowOnly);
|
||||
const auto nowHasIcon = (state != Settings::WorkMode::WindowOnly);
|
||||
) | rpl::start_with_next([=](WorkMode previous, WorkMode state) {
|
||||
if (!Platform::TrayIconSupported()) {
|
||||
return;
|
||||
}
|
||||
const auto wasHasIcon = (previous != WorkMode::WindowOnly);
|
||||
const auto nowHasIcon = (state != WorkMode::WindowOnly);
|
||||
if (wasHasIcon != nowHasIcon) {
|
||||
if (nowHasIcon) {
|
||||
_tray.createIcon();
|
||||
@@ -177,4 +181,8 @@ void Tray::toggleSoundNotifications() {
|
||||
}
|
||||
}
|
||||
|
||||
bool Tray::has() const {
|
||||
return _tray.hasIcon();
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -23,6 +23,8 @@ public:
|
||||
[[nodiscard]] rpl::producer<> showFromTrayRequests() const;
|
||||
[[nodiscard]] rpl::producer<> hideToTrayRequests() const;
|
||||
|
||||
[[nodiscard]] bool has() const;
|
||||
|
||||
private:
|
||||
void rebuildMenu();
|
||||
void toggleSoundNotifications();
|
||||
|
||||
@@ -110,25 +110,7 @@ int DrawPeerBadgeGetWidth(
|
||||
int nameWidth,
|
||||
int outerWidth,
|
||||
const PeerBadgeStyle &st) {
|
||||
if (peer->isVerified() && st.verified) {
|
||||
const auto iconw = st.verified->width();
|
||||
st.verified->paint(
|
||||
p,
|
||||
rectForName.x() + qMin(nameWidth, rectForName.width() - iconw),
|
||||
rectForName.y(),
|
||||
outerWidth);
|
||||
return iconw;
|
||||
} else if (peer->isPremium()
|
||||
&& st.premium
|
||||
&& peer->session().premiumPossible()) {
|
||||
const auto iconw = st.premium->width();
|
||||
st.premium->paint(
|
||||
p,
|
||||
rectForName.x() + qMin(nameWidth, rectForName.width() - iconw),
|
||||
rectForName.y(),
|
||||
outerWidth);
|
||||
return iconw;
|
||||
} else if ((peer->isScam() || peer->isFake()) && st.scam) {
|
||||
if ((peer->isScam() || peer->isFake()) && st.scam) {
|
||||
const auto phrase = peer->isScam()
|
||||
? tr::lng_scam_badge(tr::now)
|
||||
: tr::lng_fake_badge(tr::now);
|
||||
@@ -149,6 +131,24 @@ int DrawPeerBadgeGetWidth(
|
||||
height);
|
||||
DrawScamFakeBadge(p, rect, outerWidth, *st.scam, phrase, phraseWidth);
|
||||
return st::dialogsScamSkip + width;
|
||||
} else if (peer->isVerified() && st.verified) {
|
||||
const auto iconw = st.verified->width();
|
||||
st.verified->paint(
|
||||
p,
|
||||
rectForName.x() + qMin(nameWidth, rectForName.width() - iconw),
|
||||
rectForName.y(),
|
||||
outerWidth);
|
||||
return iconw;
|
||||
} else if (peer->isPremium()
|
||||
&& st.premium
|
||||
&& peer->session().premiumBadgesShown()) {
|
||||
const auto iconw = st.premium->width();
|
||||
st.premium->paint(
|
||||
p,
|
||||
rectForName.x() + qMin(nameWidth, rectForName.width() - iconw),
|
||||
rectForName.y(),
|
||||
outerWidth);
|
||||
return iconw;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -903,7 +903,7 @@ Core::WindowPosition MainWindow::SecondaryInitPosition() {
|
||||
}
|
||||
|
||||
bool MainWindow::minimizeToTray() {
|
||||
if (Core::Quitting()/* || !hasTrayIcon()*/) {
|
||||
if (Core::Quitting() || !Core::App().tray().has()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <QtCore/QBuffer>
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonObject>
|
||||
#include <QtCore/QFileSystemWatcher>
|
||||
|
||||
namespace Window {
|
||||
namespace Theme {
|
||||
@@ -540,6 +541,8 @@ ChatBackground::ChatBackground() : _adjustableColors({
|
||||
st::historyScrollBarBgOver }) {
|
||||
}
|
||||
|
||||
ChatBackground::~ChatBackground() = default;
|
||||
|
||||
void ChatBackground::setThemeData(QImage &&themeImage, bool themeTile) {
|
||||
_themeImage = PostprocessBackgroundImage(
|
||||
std::move(themeImage),
|
||||
@@ -566,6 +569,7 @@ void ChatBackground::start() {
|
||||
|
||||
_updates.events(
|
||||
) | rpl::start_with_next([=](const BackgroundUpdate &update) {
|
||||
refreshThemeWatcher();
|
||||
if (update.paletteChanged()) {
|
||||
style::NotifyPaletteChanged();
|
||||
}
|
||||
@@ -584,6 +588,25 @@ void ChatBackground::start() {
|
||||
Core::App().settings().setSystemDarkMode(Platform::IsDarkMode());
|
||||
}
|
||||
|
||||
void ChatBackground::refreshThemeWatcher() {
|
||||
const auto path = _themeObject.pathAbsolute;
|
||||
if (path.isEmpty()
|
||||
|| !QFileInfo(path).isNativePath()
|
||||
|| editingTheme()) {
|
||||
_themeWatcher = nullptr;
|
||||
} else if (!_themeWatcher || !_themeWatcher->files().contains(path)) {
|
||||
_themeWatcher = std::make_unique<QFileSystemWatcher>(
|
||||
QStringList(path));
|
||||
QObject::connect(
|
||||
_themeWatcher.get(),
|
||||
&QFileSystemWatcher::fileChanged,
|
||||
[](const QString &path) {
|
||||
Apply(path);
|
||||
KeepApplied();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ChatBackground::checkUploadWallPaper() {
|
||||
if (!_session) {
|
||||
_wallPaperUploadLifetime = rpl::lifetime();
|
||||
@@ -807,6 +830,7 @@ std::optional<Data::CloudTheme> ChatBackground::editingTheme() const {
|
||||
|
||||
void ChatBackground::setEditingTheme(const Data::CloudTheme &editing) {
|
||||
_editingTheme = editing;
|
||||
refreshThemeWatcher();
|
||||
}
|
||||
|
||||
void ChatBackground::clearEditingTheme(ClearEditing clear) {
|
||||
@@ -822,6 +846,7 @@ void ChatBackground::clearEditingTheme(ClearEditing clear) {
|
||||
reapplyWithNightMode(std::nullopt, _nightMode);
|
||||
KeepApplied();
|
||||
}
|
||||
refreshThemeWatcher();
|
||||
}
|
||||
|
||||
void ChatBackground::adjustPaletteUsingBackground(const QImage &image) {
|
||||
|
||||
@@ -11,6 +11,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_cloud_themes.h"
|
||||
#include "ui/style/style_core_palette.h"
|
||||
|
||||
class QFileSystemWatcher;
|
||||
|
||||
namespace style {
|
||||
struct colorizer;
|
||||
} // namespace style
|
||||
@@ -154,6 +156,7 @@ enum class ClearEditing {
|
||||
class ChatBackground final {
|
||||
public:
|
||||
ChatBackground();
|
||||
~ChatBackground();
|
||||
|
||||
[[nodiscard]] rpl::producer<BackgroundUpdate> updates() const {
|
||||
return _updates.events();
|
||||
@@ -240,6 +243,7 @@ private:
|
||||
[[nodiscard]] bool isNonDefaultBackground();
|
||||
void checkUploadWallPaper();
|
||||
[[nodiscard]] QImage postprocessBackgroundImage(QImage image);
|
||||
void refreshThemeWatcher();
|
||||
|
||||
friend bool IsNightMode();
|
||||
friend void SetNightModeValue(bool nightMode);
|
||||
@@ -276,6 +280,7 @@ private:
|
||||
QImage _themeImage;
|
||||
bool _themeTile = false;
|
||||
std::optional<Data::CloudTheme> _editingTheme;
|
||||
std::unique_ptr<QFileSystemWatcher> _themeWatcher;
|
||||
|
||||
Data::WallPaper _paperForRevert
|
||||
= Data::details::UninitializedWallPaper();
|
||||
|
||||
@@ -1201,7 +1201,9 @@ QPointer<Ui::BoxContent> ShowForwardMessagesBox(
|
||||
navigation
|
||||
](not_null<PeerData*> peer) mutable {
|
||||
const auto content = navigation->parentController()->content();
|
||||
if (peer->isSelf()) {
|
||||
if (peer->isSelf()
|
||||
&& !draft.ids.empty()
|
||||
&& draft.ids.front().peer != peer->id) {
|
||||
const auto history = peer->owner().history(peer);
|
||||
auto resolved = history->resolveForwardDraft(draft);
|
||||
if (!resolved.items.empty()) {
|
||||
|
||||
@@ -1220,6 +1220,11 @@ void SessionController::closeThirdSection() {
|
||||
}
|
||||
}
|
||||
|
||||
bool SessionController::canShowSeparateWindow(
|
||||
not_null<PeerData*> peer) const {
|
||||
return peer->computeUnavailableReason().isEmpty();
|
||||
}
|
||||
|
||||
void SessionController::showPeer(not_null<PeerData*> peer, MsgId msgId) {
|
||||
const auto currentPeer = activeChatCurrent().peer();
|
||||
if (peer && peer->isChannel() && currentPeer != peer) {
|
||||
@@ -1926,8 +1931,8 @@ Show::Show(not_null<SessionNavigation*> navigation)
|
||||
: Show(&navigation->parentController()->window()) {
|
||||
}
|
||||
|
||||
Show::Show(not_null<Controller*> window)
|
||||
: _window(base::make_weak(window.get())) {
|
||||
Show::Show(Controller *window)
|
||||
: _window(base::make_weak(window)) {
|
||||
}
|
||||
|
||||
Show::~Show() = default;
|
||||
|
||||
@@ -380,6 +380,7 @@ public:
|
||||
void resizeForThirdSection();
|
||||
void closeThirdSection();
|
||||
|
||||
[[nodiscard]] bool canShowSeparateWindow(not_null<PeerData*> peer) const;
|
||||
void showPeer(not_null<PeerData*> peer, MsgId msgId = ShowAtUnreadMsgId);
|
||||
|
||||
void startOrJoinGroupCall(
|
||||
@@ -609,7 +610,7 @@ void ActivateWindow(not_null<SessionController*> controller);
|
||||
class Show : public Ui::Show {
|
||||
public:
|
||||
explicit Show(not_null<SessionNavigation*> navigation);
|
||||
explicit Show(not_null<Controller*> window);
|
||||
explicit Show(Controller *window);
|
||||
~Show();
|
||||
void showBox(
|
||||
object_ptr<Ui::BoxContent> content,
|
||||
|
||||
2
Telegram/ThirdParty/tgcalls
vendored
2
Telegram/ThirdParty/tgcalls
vendored
Submodule Telegram/ThirdParty/tgcalls updated: 7dd3cf86a3...c2620d42ee
@@ -422,15 +422,13 @@ RUN git init ffmpeg \
|
||||
&& rm -rf ffmpeg
|
||||
|
||||
FROM builder AS pipewire
|
||||
RUN git clone -b 0.3.42 --depth=1 $GIT/PipeWire/pipewire.git \
|
||||
RUN git clone -b 0.3.33 --depth=1 $GIT/PipeWire/pipewire.git \
|
||||
&& cd pipewire \
|
||||
&& meson build \
|
||||
--buildtype=release \
|
||||
-Dtests=disabled \
|
||||
-Dexamples=disabled \
|
||||
-Dpipewire-v4l2=disabled \
|
||||
-Dspa-plugins=disabled \
|
||||
-Dsession-managers=[] \
|
||||
&& meson compile -C build \
|
||||
&& DESTDIR="$LibrariesPath/pipewire-cache" meson install -C build \
|
||||
&& cd .. \
|
||||
@@ -439,15 +437,13 @@ RUN git clone -b 0.3.42 --depth=1 $GIT/PipeWire/pipewire.git \
|
||||
FROM builder AS openal
|
||||
COPY --from=pipewire ${LibrariesPath}/pipewire-cache /
|
||||
|
||||
RUN git clone -b 1.22.0 --depth=1 $GIT/kcat/openal-soft.git \
|
||||
RUN git clone -b 1.22.1 --depth=1 $GIT/kcat/openal-soft.git \
|
||||
&& cd openal-soft \
|
||||
&& curl -sSL https://github.com/kcat/openal-soft/commit/2ea5bb91686ee1a7350672bf15b7b63649dbf111.patch \
|
||||
| git apply \
|
||||
&& sed -i 's@PW_CHECK_VERSION(major, minor, revision)@!PW_CHECK_VERSION(major, minor, revision + 1)@' alc/backends/pipewire.cpp \
|
||||
&& CFLAGS="$HFLAGS" CXXFLAGS="$HFLAGS" cmake -GNinja -B build . \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DLIBTYPE:STRING=STATIC \
|
||||
-DALSOFT_EXAMPLES=OFF \
|
||||
-DALSOFT_TESTS=OFF \
|
||||
-DALSOFT_UTILS=OFF \
|
||||
-DALSOFT_INSTALL_CONFIG=OFF \
|
||||
&& cmake --build build --parallel \
|
||||
|
||||
@@ -399,7 +399,7 @@ if customRunCommand:
|
||||
stage('patches', """
|
||||
git clone https://github.com/desktop-app/patches.git
|
||||
cd patches
|
||||
git checkout e1383b0e8f
|
||||
git checkout 38af8ef4c6
|
||||
""")
|
||||
|
||||
stage('depot_tools', """
|
||||
@@ -976,7 +976,7 @@ release:
|
||||
mac:
|
||||
git clone https://github.com/kcat/openal-soft.git
|
||||
cd openal-soft
|
||||
git checkout af8e756d
|
||||
git checkout 1.22.1
|
||||
CFLAGS=$UNGUARDED CPPFLAGS=$UNGUARDED cmake -B build . \\
|
||||
-D CMAKE_INSTALL_PREFIX:PATH=$USED_PREFIX \\
|
||||
-D ALSOFT_EXAMPLES=OFF \\
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
AppVersion 3007006
|
||||
AppVersionStrMajor 3.7
|
||||
AppVersionStrSmall 3.7.6
|
||||
AppVersionStr 3.7.6
|
||||
BetaChannel 1
|
||||
AppVersion 4000002
|
||||
AppVersionStrMajor 4.0
|
||||
AppVersionStrSmall 4.0.2
|
||||
AppVersionStr 4.0.2
|
||||
BetaChannel 0
|
||||
AlphaVersion 0
|
||||
AppVersionOriginal 3.7.6.beta
|
||||
AppVersionOriginal 4.0.2
|
||||
|
||||
Submodule Telegram/lib_base updated: e3880a61bb...2bd3ac73e0
Submodule Telegram/lib_lottie updated: b2fd42d374...7ae2b9480e
Submodule Telegram/lib_ui updated: 3aa78fb000...c499a437f8
Submodule Telegram/lib_webrtc updated: e5c89d2c55...9b11599c3c
@@ -1,3 +1,31 @@
|
||||
4.0.2 (24.06.22)
|
||||
|
||||
- Fix window title on Windows 7. (again)
|
||||
- Fix file chooser and global menu on macOS.
|
||||
- Crash fix and OpenAL check for PipeWire fix on Linux.
|
||||
|
||||
4.0.1 (23.06.22)
|
||||
|
||||
- Fix window title on Windows 7.
|
||||
- Bug fixes and other minor improvements.
|
||||
|
||||
4.0 (22.06.22)
|
||||
|
||||
- Premium: Send media and files each up to 4 GB in size.
|
||||
- Premium: Download media and files at the fastest possible speed, with no limits.
|
||||
- Premium: Double most of the limits in the app.
|
||||
- Premium: Get a new button next to any voice message to generate a transcript of its audio.
|
||||
- Premium: React with even more emoji, including :clown: and :heart_eyes:.
|
||||
- Premium: Send unique stickers with additional effects, updated monthly.
|
||||
- Premium: Set a default chat folder or enable tools to auto-archive and hide new chats.
|
||||
- Premium: Subscribers have a badge next to their name, showing they help support Telegram.
|
||||
- Premium: Show off your profile video that will be animated for everyone in chats and the chat list.
|
||||
- Premium: Sponsored Messages that are sometimes shown in public channels will no longer appear.
|
||||
- Enable join requests for your public groups – no invite links required.
|
||||
- Users who open the group will see an Apply to Join Group button.
|
||||
- Once approved by an admin, users will be able to participate in the chat.
|
||||
- Bots that are integrated into the attachment menu can be programmed to work in groups and channels.
|
||||
|
||||
3.7.6 beta (16.06.22)
|
||||
|
||||
- Settings > Advanced > Experimental adds an option to open chats in separate windows.
|
||||
|
||||
2
cmake
2
cmake
Submodule cmake updated: 06237779c2...d8442d4d96
@@ -237,7 +237,7 @@ parts:
|
||||
openal:
|
||||
source: https://github.com/kcat/openal-soft.git
|
||||
source-depth: 1
|
||||
source-tag: 1.22.0
|
||||
source-tag: 1.22.1
|
||||
plugin: cmake
|
||||
build-packages:
|
||||
- libasound2-dev
|
||||
@@ -254,9 +254,11 @@ parts:
|
||||
- -DCMAKE_BUILD_TYPE=Release
|
||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||
- -DALSOFT_EXAMPLES=OFF
|
||||
- -DALSOFT_TESTS=OFF
|
||||
- -DALSOFT_UTILS=OFF
|
||||
- -DALSOFT_INSTALL_CONFIG=OFF
|
||||
override-pull: |
|
||||
craftctl default
|
||||
sed -i 's@PW_CHECK_VERSION(major, minor, revision)@!PW_CHECK_VERSION(major, minor, revision + 1)@' alc/backends/pipewire.cpp
|
||||
prime:
|
||||
- -./usr/include
|
||||
- -./usr/lib/$CRAFT_ARCH_TRIPLET/cmake
|
||||
|
||||
Reference in New Issue
Block a user