Merge tag 'v4.8.11' into dev

# Conflicts:
#	Telegram/Resources/winrc/Telegram.rc
#	Telegram/Resources/winrc/Updater.rc
#	Telegram/SourceFiles/core/version.h
#	Telegram/lib_ui
This commit is contained in:
ZavaruKitsu 2023-08-11 12:44:07 +00:00
commit e5ff26b2eb
70 changed files with 701 additions and 483 deletions

View file

@ -19,9 +19,9 @@ include(cmake/validate_special_target.cmake)
include(cmake/version.cmake) include(cmake/version.cmake)
desktop_app_parse_version(Telegram/build/version) desktop_app_parse_version(Telegram/build/version)
set(project_langs C CXX) set(project_langs ASM C CXX)
if (APPLE) if (APPLE)
set(project_langs C CXX OBJC OBJCXX) list(APPEND project_langs OBJC OBJCXX)
endif() endif()
project(Telegram project(Telegram
@ -43,9 +43,10 @@ endif()
include(cmake/variables.cmake) include(cmake/variables.cmake)
include(cmake/nice_target_sources.cmake) include(cmake/nice_target_sources.cmake)
include(cmake/target_compile_options_if_exists.cmake) include(cmake/target_compile_options_if_exists.cmake)
include(cmake/target_link_frameworks.cmake)
include(cmake/target_link_optional_libraries.cmake)
include(cmake/target_link_options_if_exists.cmake) include(cmake/target_link_options_if_exists.cmake)
include(cmake/target_link_static_libraries.cmake) include(cmake/target_link_static_libraries.cmake)
include(cmake/target_link_frameworks.cmake)
include(cmake/init_target.cmake) include(cmake/init_target.cmake)
include(cmake/generate_target.cmake) include(cmake/generate_target.cmake)
include(cmake/nuget.cmake) include(cmake/nuget.cmake)

View file

@ -189,6 +189,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_filter_chats_limit_title" = "Limit Reached"; "lng_filter_chats_limit_title" = "Limit Reached";
"lng_filter_chats_limit1#one" = "Sorry, you can't add more than **{count}** chat to a folder."; "lng_filter_chats_limit1#one" = "Sorry, you can't add more than **{count}** chat to a folder.";
"lng_filter_chats_limit1#other" = "Sorry, you can't add more than **{count}** chats to a folder."; "lng_filter_chats_limit1#other" = "Sorry, you can't add more than **{count}** chats to a folder.";
"lng_filter_chats_exlude_limit1#one" = "Sorry, you can't exlude more than **{count}** chat from a folder.";
"lng_filter_chats_exlude_limit1#other" = "Sorry, you can't exlude more than **{count}** chats from a folder.";
"lng_filter_chats_limit2#one" = "You can increase this limit to **{count}** by upgrading to **Telegram Premium**."; "lng_filter_chats_limit2#one" = "You can increase this limit to **{count}** by upgrading to **Telegram Premium**.";
"lng_filter_chats_limit2#other" = "You can increase this limit to **{count}** by upgrading to **Telegram Premium**."; "lng_filter_chats_limit2#other" = "You can increase this limit to **{count}** by upgrading to **Telegram Premium**.";

View file

@ -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.8.10.0" /> Version="4.8.11.0" />
<Properties> <Properties>
<DisplayName>Telegram Desktop</DisplayName> <DisplayName>Telegram Desktop</DisplayName>
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName> <PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>

View file

@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,8,10,0 FILEVERSION 4,8,11,0
PRODUCTVERSION 4,8,10,0 PRODUCTVERSION 4,8,11,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.8.10.0" VALUE "FileVersion", "4.8.11.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2023" VALUE "LegalCopyright", "Copyright (C) 2014-2023"
VALUE "ProductName", "AyuGram Desktop" VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "4.8.10.0" VALUE "ProductVersion", "4.8.11.0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,8,10,0 FILEVERSION 4,8,11,0
PRODUCTVERSION 4,8,10,0 PRODUCTVERSION 4,8,11,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.8.10.0" VALUE "FileVersion", "4.8.11.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2023" VALUE "LegalCopyright", "Copyright (C) 2014-2023"
VALUE "ProductName", "AyuGram Desktop" VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "4.8.10.0" VALUE "ProductVersion", "4.8.11.0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -510,7 +510,7 @@ void ShowImportError(
if (error == u"CHANNELS_TOO_MUCH"_q) { if (error == u"CHANNELS_TOO_MUCH"_q) {
window->show(Box(ChannelsLimitBox, session)); window->show(Box(ChannelsLimitBox, session));
} else if (error == u"FILTER_INCLUDE_TOO_MUCH"_q) { } else if (error == u"FILTER_INCLUDE_TOO_MUCH"_q) {
window->show(Box(FilterChatsLimitBox, session, count)); window->show(Box(FilterChatsLimitBox, session, count, true));
} else if (error == u"CHATLISTS_TOO_MUCH"_q) { } else if (error == u"CHATLISTS_TOO_MUCH"_q) {
window->show(Box(ShareableFiltersLimitBox, session)); window->show(Box(ShareableFiltersLimitBox, session));
} else { } else {

View file

@ -456,7 +456,6 @@ void SendConfirmedFile(
}()); }());
if (itemToEdit) { if (itemToEdit) {
itemToEdit->savePreviousMedia();
auto edition = HistoryMessageEdition(); auto edition = HistoryMessageEdition();
edition.isEditHide = (flags & MessageFlag::HideEdited); edition.isEditHide = (flags & MessageFlag::HideEdited);
edition.editDate = 0; edition.editDate = 0;
@ -468,6 +467,7 @@ void SendConfirmedFile(
edition.useSameMarkup = true; edition.useSameMarkup = true;
edition.useSameReplies = true; edition.useSameReplies = true;
edition.useSameReactions = true; edition.useSameReactions = true;
edition.savePreviousMedia = true;
itemToEdit->applyEdition(std::move(edition)); itemToEdit->applyEdition(std::move(edition));
} else { } else {
const auto viaBotId = UserId(); const auto viaBotId = UserId();

View file

@ -3419,7 +3419,7 @@ void ApiWrap::sendSharedContact(
void ApiWrap::sendVoiceMessage( void ApiWrap::sendVoiceMessage(
QByteArray result, QByteArray result,
VoiceWaveform waveform, VoiceWaveform waveform,
int duration, crl::time duration,
const SendAction &action) { const SendAction &action) {
const auto caption = TextWithTags(); const auto caption = TextWithTags();
const auto to = fileLoadTaskOptions(action); const auto to = fileLoadTaskOptions(action);

View file

@ -302,7 +302,7 @@ public:
void sendVoiceMessage( void sendVoiceMessage(
QByteArray result, QByteArray result,
VoiceWaveform waveform, VoiceWaveform waveform,
int duration, crl::time duration,
const SendAction &action); const SendAction &action);
void sendFiles( void sendFiles(
Ui::PreparedList &&list, Ui::PreparedList &&list,

View file

@ -607,7 +607,7 @@ groupStickersField: InputField(defaultMultiSelectSearchField) {
textBg: boxBg; textBg: boxBg;
heightMin: 32px; heightMin: 32px;
} }
groupStickersSubTitleHeight: 36px; groupStickersSubTitleHeight: 48px;
proxyUsePadding: margins(22px, 6px, 22px, 5px); proxyUsePadding: margins(22px, 6px, 22px, 5px);
proxyTryIPv6Padding: margins(22px, 8px, 22px, 5px); proxyTryIPv6Padding: margins(22px, 8px, 22px, 5px);

View file

@ -164,7 +164,8 @@ void FillChooseFilterMenu(
controller->show(Box( controller->show(Box(
FilterChatsLimitBox, FilterChatsLimitBox,
&controller->session(), &controller->session(),
r.count)); r.count,
true));
} else if (validator.canAdd()) { } else if (validator.canAdd()) {
validator.add(id); validator.add(id);
} }

View file

@ -336,14 +336,18 @@ void EditExceptions(
Fn<void()> refresh) { Fn<void()> refresh) {
const auto include = (options & Flag::Contacts) != Flags(0); const auto include = (options & Flag::Contacts) != Flags(0);
const auto rules = data->current(); const auto rules = data->current();
const auto session = &window->session();
auto controller = std::make_unique<EditFilterChatsListController>( auto controller = std::make_unique<EditFilterChatsListController>(
&window->session(), session,
(include (include
? tr::lng_filters_include_title() ? tr::lng_filters_include_title()
: tr::lng_filters_exclude_title()), : tr::lng_filters_exclude_title()),
options, options,
rules.flags() & options, rules.flags() & options,
include ? rules.always() : rules.never()); include ? rules.always() : rules.never(),
[=](int count) {
return Box(FilterChatsLimitBox, session, count, include);
});
const auto rawController = controller.get(); const auto rawController = controller.get();
auto initBox = [=](not_null<PeerListBox*> box) { auto initBox = [=](not_null<PeerListBox*> box) {
box->setCloseByOutsideClick(false); box->setCloseByOutsideClick(false);

View file

@ -7,9 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "boxes/filters/edit_filter_chats_list.h" #include "boxes/filters/edit_filter_chats_list.h"
#include "data/data_premium_limits.h"
#include "history/history.h" #include "history/history.h"
#include "window/window_session_controller.h" #include "window/window_session_controller.h"
#include "boxes/premium_limits_box.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/wrap/vertical_layout.h" #include "ui/wrap/vertical_layout.h"
@ -99,22 +99,6 @@ private:
return PeerId(FakeChatId(static_cast<BareId>(flag))).value; return PeerId(FakeChatId(static_cast<BareId>(flag))).value;
} }
[[nodiscard]] int Limit(
not_null<Main::Session*> session,
const QString &key,
int fallback) {
return session->account().appConfig().get<int>(key, fallback);
}
[[nodiscard]] int Limit(not_null<Main::Session*> session) {
const auto premium = session->premium();
return Limit(session,
(premium
? "dialog_filters_chats_limit_premium"
: "dialog_filters_chats_limit_default"),
premium ? 200 : 100);
}
TypeRow::TypeRow(Flag flag) : PeerListRow(TypeId(flag)) { TypeRow::TypeRow(Flag flag) : PeerListRow(TypeId(flag)) {
} }
@ -338,15 +322,18 @@ EditFilterChatsListController::EditFilterChatsListController(
rpl::producer<QString> title, rpl::producer<QString> title,
Flags options, Flags options,
Flags selected, Flags selected,
const base::flat_set<not_null<History*>> &peers) const base::flat_set<not_null<History*>> &peers,
LimitBoxFactory limitBox)
: ChatsListBoxController(session) : ChatsListBoxController(session)
, _session(session) , _session(session)
, _limitBox(std::move(limitBox))
, _title(std::move(title)) , _title(std::move(title))
, _peers(peers) , _peers(peers)
, _options(options & ~Flag::Chatlist) , _options(options & ~Flag::Chatlist)
, _selected(selected) , _selected(selected)
, _limit(Limit(session)) , _limit(Data::PremiumLimits(session).dialogFiltersChatsCurrent())
, _chatlist(options & Flag::Chatlist) { , _chatlist(options & Flag::Chatlist) {
Expects(_limitBox != nullptr);
} }
Main::Session &EditFilterChatsListController::session() const { Main::Session &EditFilterChatsListController::session() const {
@ -375,8 +362,7 @@ void EditFilterChatsListController::rowClicked(not_null<PeerListRow*> row) {
delegate()->peerListSetRowChecked(row, !row->checked()); delegate()->peerListSetRowChecked(row, !row->checked());
updateTitle(); updateTitle();
} else { } else {
delegate()->peerListShowBox( delegate()->peerListShowBox(_limitBox(count));
Box(FilterChatsLimitBox, _session, count));
} }
} }

View file

@ -43,13 +43,15 @@ class EditFilterChatsListController final : public ChatsListBoxController {
public: public:
using Flag = Data::ChatFilter::Flag; using Flag = Data::ChatFilter::Flag;
using Flags = Data::ChatFilter::Flags; using Flags = Data::ChatFilter::Flags;
using LimitBoxFactory = Fn<object_ptr<Ui::BoxContent>(int)>;
EditFilterChatsListController( EditFilterChatsListController(
not_null<Main::Session*> session, not_null<Main::Session*> session,
rpl::producer<QString> title, rpl::producer<QString> title,
Flags options, Flags options,
Flags selected, Flags selected,
const base::flat_set<not_null<History*>> &peers); const base::flat_set<not_null<History*>> &peers,
LimitBoxFactory limitBox);
[[nodiscard]] Main::Session &session() const override; [[nodiscard]] Main::Session &session() const override;
[[nodiscard]] Flags chosenOptions() const { [[nodiscard]] Flags chosenOptions() const {
@ -70,6 +72,7 @@ private:
void updateTitle(); void updateTitle();
const not_null<Main::Session*> _session; const not_null<Main::Session*> _session;
const LimitBoxFactory _limitBox;
rpl::producer<QString> _title; rpl::producer<QString> _title;
base::flat_set<not_null<History*>> _peers; base::flat_set<not_null<History*>> _peers;
Flags _options; Flags _options;

View file

@ -694,7 +694,8 @@ void PublicLinksLimitBox(
void FilterChatsLimitBox( void FilterChatsLimitBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session, not_null<Main::Session*> session,
int currentCount) { int currentCount,
bool include) {
const auto premium = session->premium(); const auto premium = session->premium();
const auto premiumPossible = session->premiumPossible(); const auto premiumPossible = session->premiumPossible();
@ -707,10 +708,12 @@ void FilterChatsLimitBox(
premiumLimit); premiumLimit);
auto text = rpl::combine( auto text = rpl::combine(
tr::lng_filter_chats_limit1( (include
lt_count, ? tr::lng_filter_chats_limit1
rpl::single(premium ? premiumLimit : defaultLimit), : tr::lng_filter_chats_exlude_limit1)(
Ui::Text::RichLangValue), lt_count,
rpl::single(premium ? premiumLimit : defaultLimit),
Ui::Text::RichLangValue),
((premium || !premiumPossible) ((premium || !premiumPossible)
? rpl::single(TextWithEntities()) ? rpl::single(TextWithEntities())
: tr::lng_filter_chats_limit2( : tr::lng_filter_chats_limit2(

View file

@ -35,7 +35,8 @@ void PublicLinksLimitBox(
void FilterChatsLimitBox( void FilterChatsLimitBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session, not_null<Main::Session*> session,
int currentCount); int currentCount,
bool include);
void FilterLinksLimitBox( void FilterLinksLimitBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session); not_null<Main::Session*> session);

View file

@ -250,6 +250,7 @@ private:
int countMaxNameWidth(bool installedSet) const; int countMaxNameWidth(bool installedSet) const;
[[nodiscard]] bool skipPremium() const; [[nodiscard]] bool skipPremium() const;
const style::PeerListItem &_st;
const std::shared_ptr<ChatHelpers::Show> _show; const std::shared_ptr<ChatHelpers::Show> _show;
const not_null<Main::Session*> _session; const not_null<Main::Session*> _session;
MTP::Sender _api; MTP::Sender _api;
@ -386,7 +387,8 @@ StickersBox::StickersBox(
std::shared_ptr<ChatHelpers::Show> show, std::shared_ptr<ChatHelpers::Show> show,
Section section, Section section,
bool masks) bool masks)
: _show(std::move(show)) : _st(st::stickersRowItem)
, _show(std::move(show))
, _session(&_show->session()) , _session(&_show->session())
, _api(&_session->mtp()) , _api(&_session->mtp())
, _tabs(this, st::stickersTabs) , _tabs(this, st::stickersTabs)
@ -407,7 +409,8 @@ StickersBox::StickersBox(
QWidget*, QWidget*,
std::shared_ptr<ChatHelpers::Show> show, std::shared_ptr<ChatHelpers::Show> show,
not_null<ChannelData*> megagroup) not_null<ChannelData*> megagroup)
: _show(std::move(show)) : _st(st::stickersRowItem)
, _show(std::move(show))
, _session(&_show->session()) , _session(&_show->session())
, _api(&_session->mtp()) , _api(&_session->mtp())
, _section(Section::Installed) , _section(Section::Installed)
@ -425,7 +428,8 @@ StickersBox::StickersBox(
QWidget*, QWidget*,
std::shared_ptr<ChatHelpers::Show> show, std::shared_ptr<ChatHelpers::Show> show,
const QVector<MTPStickerSetCovered> &attachedSets) const QVector<MTPStickerSetCovered> &attachedSets)
: _show(std::move(show)) : _st(st::stickersRowItem)
, _show(std::move(show))
, _session(&_show->session()) , _session(&_show->session())
, _api(&_session->mtp()) , _api(&_session->mtp())
, _section(Section::Attached) , _section(Section::Attached)
@ -440,7 +444,8 @@ StickersBox::StickersBox(
QWidget*, QWidget*,
std::shared_ptr<ChatHelpers::Show> show, std::shared_ptr<ChatHelpers::Show> show,
const std::vector<StickerSetIdentifier> &emojiSets) const std::vector<StickerSetIdentifier> &emojiSets)
: _show(std::move(show)) : _st(st::stickersRowItem)
, _show(std::move(show))
, _session(&_show->session()) , _session(&_show->session())
, _api(&_session->mtp()) , _api(&_session->mtp())
, _section(Section::Attached) , _section(Section::Attached)
@ -1131,6 +1136,7 @@ StickersBox::Inner::Inner(
std::shared_ptr<ChatHelpers::Show> show, std::shared_ptr<ChatHelpers::Show> show,
StickersBox::Section section) StickersBox::Section section)
: RpWidget(parent) : RpWidget(parent)
, _st(st::stickersRowItem)
, _show(std::move(show)) , _show(std::move(show))
, _session(&_show->session()) , _session(&_show->session())
, _api(&_session->mtp()) , _api(&_session->mtp())
@ -1150,11 +1156,11 @@ StickersBox::Inner::Inner(
, _inactiveButtonBg( , _inactiveButtonBg(
ImageRoundRadius::Large, ImageRoundRadius::Large,
st::stickersTrendingInstalled.textBg) st::stickersTrendingInstalled.textBg)
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) , _rowHeight(_st.height)
, _shiftingAnimation([=](crl::time now) { , _shiftingAnimation([=](crl::time now) {
return shiftingAnimationCallback(now); return shiftingAnimationCallback(now);
}) })
, _itemsTop(st::membersMarginTop) , _itemsTop(st::lineWidth)
, _addText(tr::lng_stickers_featured_add(tr::now)) , _addText(tr::lng_stickers_featured_add(tr::now))
, _addWidth(st::stickersTrendingAdd.font->width(_addText)) , _addWidth(st::stickersTrendingAdd.font->width(_addText))
, _undoText(tr::lng_stickers_return(tr::now)) , _undoText(tr::lng_stickers_return(tr::now))
@ -1169,6 +1175,7 @@ StickersBox::Inner::Inner(
std::shared_ptr<ChatHelpers::Show> show, std::shared_ptr<ChatHelpers::Show> show,
not_null<ChannelData*> megagroup) not_null<ChannelData*> megagroup)
: RpWidget(parent) : RpWidget(parent)
, _st(st::stickersRowItem)
, _show(std::move(show)) , _show(std::move(show))
, _session(&_show->session()) , _session(&_show->session())
, _api(&_session->mtp()) , _api(&_session->mtp())
@ -1188,11 +1195,11 @@ StickersBox::Inner::Inner(
, _inactiveButtonBg( , _inactiveButtonBg(
ImageRoundRadius::Large, ImageRoundRadius::Large,
st::stickersTrendingInstalled.textBg) st::stickersTrendingInstalled.textBg)
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) , _rowHeight(_st.height)
, _shiftingAnimation([=](crl::time now) { , _shiftingAnimation([=](crl::time now) {
return shiftingAnimationCallback(now); return shiftingAnimationCallback(now);
}) })
, _itemsTop(st::membersMarginTop) , _itemsTop(st::lineWidth)
, _megagroupSet(megagroup) , _megagroupSet(megagroup)
, _megagroupSetInput(_megagroupSet->mgInfo->stickerSet) , _megagroupSetInput(_megagroupSet->mgInfo->stickerSet)
, _megagroupSetField( , _megagroupSetField(
@ -1328,8 +1335,8 @@ QRect StickersBox::Inner::relativeButtonRect(
buttonh = st.height; buttonh = st.height;
buttonshift = 0; buttonshift = 0;
} }
auto buttonx = width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - buttonw + buttonshift; auto buttonx = width() - st::contactsPadding.right() - buttonw + buttonshift;
auto buttony = st::contactsPadding.top() + (st::contactsPhotoSize - buttonh) / 2; auto buttony = (_st.height - buttonh) / 2;
return QRect(buttonx, buttony, buttonw, buttonh); return QRect(buttonx, buttony, buttonw, buttonh);
} }
@ -1345,7 +1352,7 @@ void StickersBox::Inner::paintRow(Painter &p, not_null<Row*> row, int index) {
return -1; return -1;
}(); }();
if (index >= 0 && index == selectedIndex) { if (index >= 0 && index == selectedIndex) {
p.fillRect(0, 0, width(), _rowHeight, st::contactsBgOver); p.fillRect(0, 0, width(), _rowHeight, _st.button.textBgOver);
if (row->ripple) { if (row->ripple) {
row->ripple->paint(p, 0, 0, width()); row->ripple->paint(p, 0, 0, width());
} }
@ -1362,7 +1369,7 @@ void StickersBox::Inner::paintRow(Painter &p, not_null<Row*> row, int index) {
current = reachedOpacity; current = reachedOpacity;
} }
} }
auto rect = myrtlrect(st::contactsPadding.left() / 2, st::contactsPadding.top() / 2, width() - (st::contactsPadding.left() / 2) - _scrollbar - st::contactsPadding.left() / 2, _rowHeight - ((st::contactsPadding.top() + st::contactsPadding.bottom()) / 2)); auto rect = myrtlrect(_st.photoPosition.x() / 2, _st.photoPosition.y() / 2, width() - _st.photoPosition.x() - _scrollbar, _rowHeight - _st.photoPosition.y());
p.setOpacity(current); p.setOpacity(current);
Ui::Shadow::paint(p, rect, width(), st::boxRoundShadow); Ui::Shadow::paint(p, rect, width(), st::boxRoundShadow);
p.setOpacity(1); p.setOpacity(1);
@ -1383,27 +1390,27 @@ void StickersBox::Inner::paintRow(Painter &p, not_null<Row*> row, int index) {
p.setOpacity(st::stickersRowDisabledOpacity); p.setOpacity(st::stickersRowDisabledOpacity);
} }
auto stickerx = st::contactsPadding.left(); auto stickerskip = 0;
if (!_megagroupSet && _isInstalledTab) { if (!_megagroupSet && _isInstalledTab) {
stickerx += st::stickersReorderIcon.width() + st::stickersReorderSkip; stickerskip += st::stickersReorderIcon.width() + st::stickersReorderSkip;
if (!row->isRecentSet()) { if (!row->isRecentSet()) {
st::stickersReorderIcon.paint(p, st::contactsPadding.left(), (_rowHeight - st::stickersReorderIcon.height()) / 2, width()); st::stickersReorderIcon.paint(p, _st.photoPosition.x(), (_rowHeight - st::stickersReorderIcon.height()) / 2, width());
} }
} }
if (row->sticker) { if (row->sticker) {
paintRowThumbnail(p, row, stickerx); paintRowThumbnail(p, row, stickerskip + _st.photoPosition.x());
} }
int namex = stickerx + st::contactsPhotoSize + st::contactsPadding.left(); int namex = stickerskip + _st.namePosition.x();
int namey = st::contactsPadding.top() + st::contactsNameTop; int namey = _st.namePosition.y();
int statusx = namex; int statusx = stickerskip + _st.statusPosition.x();
int statusy = st::contactsPadding.top() + st::contactsStatusTop; int statusy = _st.statusPosition.y();
p.setFont(st::contactsNameStyle.font); p.setFont(st::contactsNameStyle.font);
p.setPen(st::contactsNameFg); p.setPen(_st.nameFg);
p.drawTextLeft(namex, namey, width(), row->title, row->titleWidth); p.drawTextLeft(namex, namey, width(), row->title, row->titleWidth);
if (row->isUnread()) { if (row->isUnread()) {
@ -1425,7 +1432,7 @@ void StickersBox::Inner::paintRow(Painter &p, not_null<Row*> row, int index) {
: tr::lng_stickers_count(tr::now, lt_count, row->count); : tr::lng_stickers_count(tr::now, lt_count, row->count);
p.setFont(st::contactsStatusFont); p.setFont(st::contactsStatusFont);
p.setPen(st::contactsStatusFg); p.setPen(_st.statusFg);
p.drawTextLeft(statusx, statusy, width(), statusText); p.drawTextLeft(statusx, statusy, width(), statusText);
p.setOpacity(1); p.setOpacity(1);
@ -1457,15 +1464,15 @@ void StickersBox::Inner::paintRowThumbnail(
? row->stickerMedia->thumbnail() ? row->stickerMedia->thumbnail()
: nullptr; : nullptr;
const auto paused = _show->paused(ChatHelpers::PauseReason::Layer); const auto paused = _show->paused(ChatHelpers::PauseReason::Layer);
const auto x = left + (st::contactsPhotoSize - row->pixw) / 2; const auto x = left + (_st.photoSize - row->pixw) / 2;
const auto y = st::contactsPadding.top() + (st::contactsPhotoSize - row->pixh) / 2; const auto y = _st.photoPosition.y() + (_st.photoSize - row->pixh) / 2;
if (row->lottie && row->lottie->ready()) { if (row->lottie && row->lottie->ready()) {
const auto frame = row->lottie->frame(); const auto frame = row->lottie->frame();
const auto size = frame.size() / cIntRetinaFactor(); const auto size = frame.size() / cIntRetinaFactor();
p.drawImage( p.drawImage(
QRect( QRect(
left + (st::contactsPhotoSize - size.width()) / 2, left + (_st.photoSize - size.width()) / 2,
st::contactsPadding.top() + (st::contactsPhotoSize - size.height()) / 2, _st.photoPosition.y() + (_st.photoSize - size.height()) / 2,
size.width(), size.width(),
size.height()), size.height()),
frame); frame);
@ -1500,9 +1507,7 @@ void StickersBox::Inner::validateLottieAnimation(not_null<Row*> row) {
row->thumbnailMedia.get(), row->thumbnailMedia.get(),
row->stickerMedia.get(), row->stickerMedia.get(),
ChatHelpers::StickerLottieSize::SetsListThumbnail, ChatHelpers::StickerLottieSize::SetsListThumbnail,
QSize( QSize(_st.photoSize, _st.photoSize) * cIntRetinaFactor());
st::contactsPhotoSize,
st::contactsPhotoSize) * cIntRetinaFactor());
if (!player) { if (!player) {
return; return;
} }
@ -1572,15 +1577,12 @@ void StickersBox::Inner::updateRowThumbnail(not_null<Row*> row) {
} }
Unexpected("StickersBox::Inner::updateRowThumbnail: row not found"); Unexpected("StickersBox::Inner::updateRowThumbnail: row not found");
}(); }();
const auto left = st::contactsPadding.left() const auto left = _st.photoPosition.x()
+ ((!_megagroupSet && _isInstalledTab) + ((!_megagroupSet && _isInstalledTab)
? st::stickersReorderIcon.width() + st::stickersReorderSkip ? st::stickersReorderIcon.width() + st::stickersReorderSkip
: 0); : 0);
update( const auto top = rowTop + _st.photoPosition.y();
left, update(left, top, _st.photoSize, _st.photoSize);
rowTop + st::contactsPadding.top(),
st::contactsPhotoSize,
st::contactsPhotoSize);
} }
void StickersBox::Inner::paintFakeButton(Painter &p, not_null<Row*> row, int index) { void StickersBox::Inner::paintFakeButton(Painter &p, not_null<Row*> row, int index) {
@ -1818,7 +1820,7 @@ void StickersBox::Inner::updateSelected() {
actionSel = -1; actionSel = -1;
} }
if (!_megagroupSet && _isInstalledTab && !row->isRecentSet()) { if (!_megagroupSet && _isInstalledTab && !row->isRecentSet()) {
auto dragAreaWidth = st::contactsPadding.left() + st::stickersReorderIcon.width() + st::stickersReorderSkip; auto dragAreaWidth = _st.photoPosition.x() + st::stickersReorderIcon.width() + st::stickersReorderSkip;
auto dragArea = myrtlrect(0, 0, dragAreaWidth, _rowHeight); auto dragArea = myrtlrect(0, 0, dragAreaWidth, _rowHeight);
inDragArea = dragArea.contains(local); inDragArea = dragArea.contains(local);
} }
@ -2142,7 +2144,7 @@ void StickersBox::Inner::rebuildMegagroupSet() {
} }
void StickersBox::Inner::rebuild(bool masks) { void StickersBox::Inner::rebuild(bool masks) {
_itemsTop = st::membersMarginTop; _itemsTop = st::lineWidth;
if (_megagroupSet) { if (_megagroupSet) {
_itemsTop += st::groupStickersFieldPadding.top() + _megagroupSetField->height() + st::groupStickersFieldPadding.bottom(); _itemsTop += st::groupStickersFieldPadding.top() + _megagroupSetField->height() + st::groupStickersFieldPadding.bottom();
@ -2291,11 +2293,11 @@ bool StickersBox::Inner::skipPremium() const {
} }
int StickersBox::Inner::countMaxNameWidth(bool installedSet) const { int StickersBox::Inner::countMaxNameWidth(bool installedSet) const {
int namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(); int namex = _st.namePosition.x();
if (!_megagroupSet && _isInstalledTab) { if (!_megagroupSet && _isInstalledTab) {
namex += st::stickersReorderIcon.width() + st::stickersReorderSkip; namex += st::stickersReorderIcon.width() + st::stickersReorderSkip;
} }
int namew = st::boxWideWidth - namex - st::contactsPadding.right() - st::contactsCheckPosition.x(); int namew = st::boxWideWidth - namex - st::contactsPadding.right();
if (_isInstalledTab) { if (_isInstalledTab) {
if (!_megagroupSet) { if (!_megagroupSet) {
namew -= _undoWidth - st::stickersUndoRemove.width; namew -= _undoWidth - st::stickersUndoRemove.width;
@ -2401,17 +2403,17 @@ void StickersBox::Inner::fillSetCover(
: QSize(1, 1); : QSize(1, 1);
auto pixw = size.width(); auto pixw = size.width();
auto pixh = size.height(); auto pixh = size.height();
if (pixw > st::contactsPhotoSize) { if (pixw > _st.photoSize) {
if (pixw > pixh) { if (pixw > pixh) {
pixh = (pixh * st::contactsPhotoSize) / pixw; pixh = (pixh * _st.photoSize) / pixw;
pixw = st::contactsPhotoSize; pixw = _st.photoSize;
} else { } else {
pixw = (pixw * st::contactsPhotoSize) / pixh; pixw = (pixw * _st.photoSize) / pixh;
pixh = st::contactsPhotoSize; pixh = _st.photoSize;
} }
} else if (pixh > st::contactsPhotoSize) { } else if (pixh > _st.photoSize) {
pixw = (pixw * st::contactsPhotoSize) / pixh; pixw = (pixw * _st.photoSize) / pixh;
pixh = st::contactsPhotoSize; pixh = _st.photoSize;
} }
*outWidth = pixw; *outWidth = pixw;
*outHeight = pixh; *outHeight = pixh;

View file

@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace style { namespace style {
struct RippleAnimation; struct RippleAnimation;
struct PeerListItem;
} // namespace style } // namespace style
namespace Ui { namespace Ui {
@ -142,6 +143,7 @@ private:
std::array<Inner*, 5> widgets() const; std::array<Inner*, 5> widgets() const;
const style::PeerListItem &_st;
const std::shared_ptr<ChatHelpers::Show> _show; const std::shared_ptr<ChatHelpers::Show> _show;
const not_null<Main::Session*> _session; const not_null<Main::Session*> _session;
MTP::Sender _api; MTP::Sender _api;

View file

@ -95,6 +95,7 @@ Panel::Panel(not_null<Call*> call)
_decline->entity()->setText(tr::lng_call_decline()); _decline->entity()->setText(tr::lng_call_decline());
_cancel->setDuration(st::callPanelDuration); _cancel->setDuration(st::callPanelDuration);
_cancel->entity()->setText(tr::lng_call_cancel()); _cancel->entity()->setText(tr::lng_call_cancel());
_screencast->setDuration(st::callPanelDuration);
initWindow(); initWindow();
initWidget(); initWidget();
@ -299,6 +300,7 @@ void Panel::initControls() {
_decline->finishAnimating(); _decline->finishAnimating();
_cancel->finishAnimating(); _cancel->finishAnimating();
_screencast->finishAnimating();
} }
void Panel::setIncomingSize(QSize size) { void Panel::setIncomingSize(QSize size) {
@ -595,6 +597,7 @@ void Panel::showControls() {
widget()->showChildren(); widget()->showChildren();
_decline->setVisible(_decline->toggled()); _decline->setVisible(_decline->toggled());
_cancel->setVisible(_cancel->toggled()); _cancel->setVisible(_cancel->toggled());
_screencast->setVisible(_screencast->toggled());
const auto shown = !_incomingFrameSize.isEmpty(); const auto shown = !_incomingFrameSize.isEmpty();
_incoming->widget()->setVisible(shown); _incoming->widget()->setVisible(shown);
@ -753,12 +756,6 @@ void Panel::updateControlsGeometry() {
updateOutgoingVideoBubbleGeometry(); updateOutgoingVideoBubbleGeometry();
} }
auto threeWidth = _answerHangupRedial->width()
+ st::callCancel.button.width
- _screencast->width();
_decline->moveToLeft((widget()->width() - threeWidth) / 2, _buttonsTop);
_cancel->moveToLeft((widget()->width() - threeWidth) / 2, _buttonsTop);
updateHangupGeometry(); updateHangupGeometry();
} }
@ -779,22 +776,28 @@ void Panel::updateOutgoingVideoBubbleGeometry() {
} }
void Panel::updateHangupGeometry() { void Panel::updateHangupGeometry() {
auto twoWidth = _answerHangupRedial->width() + _screencast->width(); const auto isWaitingUser = (_call
auto threeWidth = twoWidth + st::callCancel.button.width; && _call->state() == State::WaitingUserConfirmation);
auto rightFrom = (widget()->width() - threeWidth) / 2; const auto hangupProgress = isWaitingUser
auto rightTo = (widget()->width() - twoWidth) / 2;
auto hangupProgress = (_call
&& _call->state() == State::WaitingUserConfirmation)
? 0. ? 0.
: _hangupShownProgress.value(_hangupShown ? 1. : 0.); : _hangupShownProgress.value(_hangupShown ? 1. : 0.);
auto hangupRight = anim::interpolate(rightFrom, rightTo, hangupProgress);
_answerHangupRedial->moveToRight(hangupRight, _buttonsTop);
_answerHangupRedial->setProgress(hangupProgress); _answerHangupRedial->setProgress(hangupProgress);
_mute->moveToRight(hangupRight - _mute->width(), _buttonsTop);
_screencast->moveToLeft(hangupRight - _mute->width(), _buttonsTop); // Screencast - Camera - Cancel/Decline - Answer/Hangup/Redial - Mute.
_camera->moveToLeft( const auto buttonWidth = st::callCancel.button.width;
hangupRight - _mute->width() + _screencast->width(), const auto cancelWidth = buttonWidth * (1. - hangupProgress);
_buttonsTop); const auto cancelLeft = (isWaitingUser)
? ((widget()->width() - buttonWidth) / 2)
: (_mute->animating())
? ((widget()->width() - cancelWidth) / 2)
: ((widget()->width() / 2) - cancelWidth);
_cancel->moveToLeft(cancelLeft, _buttonsTop);
_decline->moveToLeft(cancelLeft, _buttonsTop);
_camera->moveToLeft(cancelLeft - buttonWidth, _buttonsTop);
_screencast->moveToLeft(_camera->x() - buttonWidth, _buttonsTop);
_answerHangupRedial->moveToLeft(cancelLeft + cancelWidth, _buttonsTop);
_mute->moveToLeft(_answerHangupRedial->x() + buttonWidth, _buttonsTop);
if (_startVideo) { if (_startVideo) {
_startVideo->moveToLeft(_camera->x(), _camera->y()); _startVideo->moveToLeft(_camera->x(), _camera->y());
} }
@ -877,7 +880,9 @@ void Panel::stateChanged(State state) {
toggleButton(_decline, incomingWaiting); toggleButton(_decline, incomingWaiting);
toggleButton(_cancel, (isBusy || isWaitingUser)); toggleButton(_cancel, (isBusy || isWaitingUser));
toggleButton(_mute, !isWaitingUser); toggleButton(_mute, !isWaitingUser);
toggleButton(_screencast, !isWaitingUser); toggleButton(
_screencast,
!(isBusy || isWaitingUser || incomingWaiting));
const auto hangupShown = !_decline->toggled() const auto hangupShown = !_decline->toggled()
&& !_cancel->toggled(); && !_cancel->toggled();
if (_hangupShown != hangupShown) { if (_hangupShown != hangupShown) {

View file

@ -313,10 +313,26 @@ stickersUndoRemove: RoundButton(defaultLightButton) {
} }
stickersRemoveSkip: 4px; stickersRemoveSkip: 4px;
stickersReorderIcon: icon {{ "stickers_reorder", menuIconFg }}; stickersReorderIcon: icon {{ "stickers_reorder", menuIconFg }};
stickersReorderSkip: 13px; stickersReorderSkip: 18px;
stickersTabs: defaultTabsSlider; stickersTabs: defaultTabsSlider;
stickersRowItem: PeerListItem(defaultPeerListItem) {
height: 52px;
photoSize: 32px;
photoPosition: point(18px, 10px);
namePosition: point(66px, 7px);
statusPosition: point(66px, 26px);
button: OutlineButton(defaultPeerListButton) {
textBg: contactsBg;
textBgOver: contactsBgOver;
ripple: defaultRippleAnimation;
}
statusFg: contactsStatusFg;
statusFgOver: contactsStatusFgOver;
statusFgActive: contactsStatusFgOnline;
}
stickerEmojiSkip: 5px; stickerEmojiSkip: 5px;
stickersFeaturedBadgeFont: font(12px bold); stickersFeaturedBadgeFont: font(12px bold);
@ -351,11 +367,7 @@ filtersRemove: IconButton(stickersRemove) {
emojiPanMargins: margins(10px, 10px, 10px, 10px); emojiPanMargins: margins(10px, 10px, 10px, 10px);
emojiTabs: SettingsSlider(defaultTabsSlider) { emojiTabs: defaultTabsSlider;
height: 43px;
barTop: 40px;
labelTop: 12px;
}
emojiCategoryIconTop: 6px; emojiCategoryIconTop: 6px;
emojiPanAnimation: PanelAnimation(defaultPanelAnimation) { emojiPanAnimation: PanelAnimation(defaultPanelAnimation) {
@ -508,6 +520,7 @@ sendBoxAlbumGroupSkipRight: 5px;
sendBoxAlbumGroupSkipTop: 5px; sendBoxAlbumGroupSkipTop: 5px;
sendBoxAlbumGroupRadius: 4px; sendBoxAlbumGroupRadius: 4px;
sendBoxAlbumGroupSize: size(62px, 25px); sendBoxAlbumGroupSize: size(62px, 25px);
sendBoxAlbumGroupSizeVertical: size(30px, 50px);
sendBoxAlbumSmallGroupSize: size(30px, 25px); sendBoxAlbumSmallGroupSize: size(30px, 25px);
sendBoxFileGroupSkipTop: 2px; sendBoxFileGroupSkipTop: 2px;

View file

@ -123,7 +123,7 @@ void SetCrashAnnotationsGL() {
case Ui::GL::ANGLE::D3D11: return "Direct3D 11"; case Ui::GL::ANGLE::D3D11: return "Direct3D 11";
case Ui::GL::ANGLE::D3D9: return "Direct3D 9"; case Ui::GL::ANGLE::D3D9: return "Direct3D 9";
case Ui::GL::ANGLE::D3D11on12: return "D3D11on12"; case Ui::GL::ANGLE::D3D11on12: return "D3D11on12";
case Ui::GL::ANGLE::OpenGL: return "OpenGL"; //case Ui::GL::ANGLE::OpenGL: return "OpenGL";
} }
Unexpected("Ui::GL::CurrentANGLE value in SetupANGLE."); Unexpected("Ui::GL::CurrentANGLE value in SetupANGLE.");
}()); }());

View file

@ -125,7 +125,15 @@ std::map<int, const char*> BetaLogs() {
"- Fix several possible crashes.\n" "- Fix several possible crashes.\n"
"- Deprecate macOS 10.12, Ubuntu 18.04 and CentOS 7 in July.\n" "- Deprecate macOS 10.12, Ubuntu 18.04 and CentOS 7 in July.\n"
} },
{
4008011,
"- Fix initial video playback speed.\n"
"- Use native window resize on Windows 11.\n"
"- Fix memory leak in Direct3D 11 media viewer on Windows.\n"
},
}; };
}; };

View file

@ -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 = 4008010; constexpr auto AppVersion = 4008011;
constexpr auto AppVersionStr = "4.8.10"; constexpr auto AppVersionStr = "4.8.11";
constexpr auto AppBetaVersion = false; constexpr auto AppBetaVersion = true;
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;

View file

@ -467,16 +467,17 @@ HistoryItem *ScheduledMessages::append(
// probably this message was edited. // probably this message was edited.
if (data.is_edit_hide()) { if (data.is_edit_hide()) {
existing->applyEdition(HistoryMessageEdition(_session, data)); existing->applyEdition(HistoryMessageEdition(_session, data));
} else {
existing->updateSentContent({
qs(data.vmessage()),
Api::EntitiesFromMTP(
_session,
data.ventities().value_or_empty())
}, data.vmedia());
existing->updateReplyMarkup(
HistoryMessageMarkupData(data.vreply_markup()));
existing->updateForwardedInfo(data.vfwd_from());
} }
existing->updateSentContent({
qs(data.vmessage()),
Api::EntitiesFromMTP(
_session,
data.ventities().value_or_empty())
}, data.vmedia());
existing->updateReplyMarkup(
HistoryMessageMarkupData(data.vreply_markup()));
existing->updateForwardedInfo(data.vfwd_from());
existing->updateDate(data.vdate().v); existing->updateDate(data.vdate().v);
history->owner().requestItemTextRefresh(existing); history->owner().requestItemTextRefresh(existing);
}, [&](const auto &data) {}); }, [&](const auto &data) {});

View file

@ -18,6 +18,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
extern "C" { extern "C" {
#include <libavutil/opt.h> #include <libavutil/opt.h>
#if !defined DESKTOP_APP_USE_PACKAGED && !defined Q_OS_WIN && !defined Q_OS_MAC
#include <dlfcn.h>
#endif // !DESKTOP_APP_USE_PACKAGED && !Q_OS_WIN && !Q_OS_MAC
} // extern "C" } // extern "C"
namespace FFmpeg { namespace FFmpeg {
@ -85,6 +88,47 @@ void PremultiplyLine(uchar *dst, const uchar *src, int intsCount) {
#endif // LIB_FFMPEG_USE_QT_PRIVATE_API #endif // LIB_FFMPEG_USE_QT_PRIVATE_API
} }
#if !defined DESKTOP_APP_USE_PACKAGED && !defined Q_OS_WIN && !defined Q_OS_MAC
[[nodiscard]] auto CheckHwLibs() {
auto list = std::deque{
AV_PIX_FMT_CUDA,
};
const auto vdpau = [&] {
if (const auto handle = dlopen("libvdpau.so.1", RTLD_LAZY)) {
dlclose(handle);
}
if (dlerror()) {
return false;
}
return true;
}();
if (vdpau) {
list.push_front(AV_PIX_FMT_VDPAU);
}
const auto va = [&] {
const auto list = std::array{
"libva-drm.so.1",
"libva-x11.so.1",
"libva.so.1",
"libdrm.so.2",
};
for (const auto lib : list) {
if (const auto handle = dlopen(lib, RTLD_LAZY)) {
dlclose(handle);
}
if (dlerror()) {
return false;
}
}
return true;
}();
if (va) {
list.push_front(AV_PIX_FMT_VAAPI);
}
return list;
}
#endif // !DESKTOP_APP_USE_PACKAGED && !Q_OS_WIN && !Q_OS_MAC
[[nodiscard]] bool InitHw(AVCodecContext *context, AVHWDeviceType type) { [[nodiscard]] bool InitHw(AVCodecContext *context, AVHWDeviceType type) {
AVCodecContext *parent = static_cast<AVCodecContext*>(context->opaque); AVCodecContext *parent = static_cast<AVCodecContext*>(context->opaque);
@ -125,6 +169,9 @@ void PremultiplyLine(uchar *dst, const uchar *src, int intsCount) {
} }
return false; return false;
}; };
#if !defined DESKTOP_APP_USE_PACKAGED && !defined Q_OS_WIN && !defined Q_OS_MAC
static const auto list = CheckHwLibs();
#else // !DESKTOP_APP_USE_PACKAGED && !Q_OS_WIN && !Q_OS_MAC
const auto list = std::array{ const auto list = std::array{
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
AV_PIX_FMT_D3D11, AV_PIX_FMT_D3D11,
@ -138,6 +185,7 @@ void PremultiplyLine(uchar *dst, const uchar *src, int intsCount) {
AV_PIX_FMT_CUDA, AV_PIX_FMT_CUDA,
#endif // Q_OS_WIN || Q_OS_MAC #endif // Q_OS_WIN || Q_OS_MAC
}; };
#endif // DESKTOP_APP_USE_PACKAGED || Q_OS_WIN || Q_OS_MAC
for (const auto format : list) { for (const auto format : list) {
if (!has(format)) { if (!has(format)) {
continue; continue;

View file

@ -1469,6 +1469,12 @@ void HistoryItem::applyEdition(HistoryMessageEdition &&edition) {
// } // }
//} //}
const auto updatingSavedLocalEdit = !edition.savePreviousMedia
&& (_savedLocalEditMediaData != nullptr);
if (!_savedLocalEditMediaData && edition.savePreviousMedia) {
savePreviousMedia();
}
if (edition.isEditHide) { if (edition.isEditHide) {
_flags |= MessageFlag::HideEdited; _flags |= MessageFlag::HideEdited;
} else { } else {
@ -1488,8 +1494,14 @@ void HistoryItem::applyEdition(HistoryMessageEdition &&edition) {
setReplyMarkup(base::take(edition.replyMarkup)); setReplyMarkup(base::take(edition.replyMarkup));
} }
if (!isLocalUpdateMedia()) { if (!isLocalUpdateMedia()) {
removeFromSharedMediaIndex(); if (updatingSavedLocalEdit) {
refreshMedia(edition.mtpMedia); _savedLocalEditMediaData->media = edition.mtpMedia
? CreateMedia(this, *edition.mtpMedia)
: nullptr;
} else {
removeFromSharedMediaIndex();
refreshMedia(edition.mtpMedia);
}
} }
if (!edition.useSameReactions) { if (!edition.useSameReactions) {
updateReactions(edition.mtpReactions); updateReactions(edition.mtpReactions);
@ -1500,10 +1512,18 @@ void HistoryItem::applyEdition(HistoryMessageEdition &&edition) {
if (!edition.useSameForwards) { if (!edition.useSameForwards) {
setForwardsCount(edition.forwards); setForwardsCount(edition.forwards);
} }
setText(_media const auto &checkedMedia = updatingSavedLocalEdit
? _savedLocalEditMediaData->media
: _media;
auto updatedText = checkedMedia
? edition.textWithEntities ? edition.textWithEntities
: EnsureNonEmpty(edition.textWithEntities)); : EnsureNonEmpty(edition.textWithEntities);
if (!isLocalUpdateMedia()) { if (updatingSavedLocalEdit) {
_savedLocalEditMediaData->text = std::move(updatedText);
} else {
setText(std::move(updatedText));
}
if (!isLocalUpdateMedia() && !updatingSavedLocalEdit) {
indexAsNewItem(); indexAsNewItem();
} }
if (!edition.useSameReplies) { if (!edition.useSameReplies) {
@ -1652,6 +1672,9 @@ void HistoryItem::applySentMessage(
void HistoryItem::updateSentContent( void HistoryItem::updateSentContent(
const TextWithEntities &textWithEntities, const TextWithEntities &textWithEntities,
const MTPMessageMedia *media) { const MTPMessageMedia *media) {
if (_savedLocalEditMediaData) {
return;
}
setText(textWithEntities); setText(textWithEntities);
if (_flags & MessageFlag::FromInlineBot) { if (_flags & MessageFlag::FromInlineBot) {
if (!media || !_media || !_media->updateInlineResultMedia(*media)) { if (!media || !_media || !_media->updateInlineResultMedia(*media)) {

View file

@ -29,6 +29,7 @@ struct HistoryMessageEdition {
bool useSameReplies = false; bool useSameReplies = false;
bool useSameMarkup = false; bool useSameMarkup = false;
bool useSameReactions = false; bool useSameReactions = false;
bool savePreviousMedia = false;
TextWithEntities textWithEntities; TextWithEntities textWithEntities;
HistoryMessageMarkupData replyMarkup; HistoryMessageMarkupData replyMarkup;
HistoryMessageRepliesData replies; HistoryMessageRepliesData replies;

View file

@ -25,7 +25,7 @@ struct MessageToEdit {
struct VoiceToSend { struct VoiceToSend {
QByteArray bytes; QByteArray bytes;
VoiceWaveform waveform; VoiceWaveform waveform;
int duration = 0; crl::time duration = 0;
Api::SendOptions options; Api::SendOptions options;
}; };
struct SendActionUpdate { struct SendActionUpdate {

View file

@ -77,8 +77,8 @@ enum class FilterType {
return std::clamp(float64(low) / high, 0., 1.); return std::clamp(float64(low) / high, 0., 1.);
} }
[[nodiscard]] auto Duration(int samples) { [[nodiscard]] crl::time Duration(int samples) {
return samples / ::Media::Player::kDefaultFrequency; return samples * crl::time(1000) / ::Media::Player::kDefaultFrequency;
} }
[[nodiscard]] auto FormatVoiceDuration(int samples) { [[nodiscard]] auto FormatVoiceDuration(int samples) {

View file

@ -55,7 +55,9 @@ namespace {
result.preview = kEmpty; result.preview = kEmpty;
result.spoilerRepaint = nullptr; result.spoilerRepaint = nullptr;
} else { } else {
result.preview = preview->original(); result.preview = Images::Round(
preview->original(),
ImageRoundRadius::Small);
result.spoilerRepaint = spoiler ? repaint : nullptr; result.spoilerRepaint = spoiler ? repaint : nullptr;
} }
return result; return result;

View file

@ -607,7 +607,7 @@ void ScheduledWidget::send(Api::SendOptions options) {
void ScheduledWidget::sendVoice( void ScheduledWidget::sendVoice(
QByteArray bytes, QByteArray bytes,
VoiceWaveform waveform, VoiceWaveform waveform,
int duration) { crl::time duration) {
const auto callback = [=](Api::SendOptions options) { const auto callback = [=](Api::SendOptions options) {
sendVoice(bytes, waveform, duration, options); sendVoice(bytes, waveform, duration, options);
}; };
@ -617,7 +617,7 @@ void ScheduledWidget::sendVoice(
void ScheduledWidget::sendVoice( void ScheduledWidget::sendVoice(
QByteArray bytes, QByteArray bytes,
VoiceWaveform waveform, VoiceWaveform waveform,
int duration, crl::time duration,
Api::SendOptions options) { Api::SendOptions options) {
session().api().sendVoiceMessage( session().api().sendVoiceMessage(
bytes, bytes,

View file

@ -197,11 +197,14 @@ private:
Api::SendOptions options) const; Api::SendOptions options) const;
void send(); void send();
void send(Api::SendOptions options); void send(Api::SendOptions options);
void sendVoice(QByteArray bytes, VoiceWaveform waveform, int duration);
void sendVoice( void sendVoice(
QByteArray bytes, QByteArray bytes,
VoiceWaveform waveform, VoiceWaveform waveform,
int duration, crl::time duration);
void sendVoice(
QByteArray bytes,
VoiceWaveform waveform,
crl::time duration,
Api::SendOptions options); Api::SendOptions options);
void edit( void edit(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,

View file

@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/unique_qptr.h" #include "base/unique_qptr.h"
namespace Ui { namespace Ui {
class SettingsSlider;
class VerticalLayout; class VerticalLayout;
class SearchFieldController; class SearchFieldController;
} // namespace Ui } // namespace Ui

View file

@ -10,10 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <rpl/event_stream.h> #include <rpl/event_stream.h>
#include "window/section_widget.h" #include "window/section_widget.h"
namespace Ui {
class SettingsSlider;
} // namespace Ui
namespace Window { namespace Window {
class ConnectionState; class ConnectionState;
} // namespace Window } // namespace Window

View file

@ -15,7 +15,6 @@ enum class SharedMediaType : signed char;
} // namespace Storage } // namespace Storage
namespace Ui { namespace Ui {
class SettingsSlider;
class FadeShadow; class FadeShadow;
class PlainShadow; class PlainShadow;
class PopupMenu; class PopupMenu;

View file

@ -14,7 +14,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/media/info_media_list_widget.h" #include "info/media/info_media_list_widget.h"
namespace Ui { namespace Ui {
class SettingsSlider;
class VerticalLayout; class VerticalLayout;
class SearchFieldController; class SearchFieldController;
} // namespace Ui } // namespace Ui

View file

@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/unique_qptr.h" #include "base/unique_qptr.h"
namespace Ui { namespace Ui {
class SettingsSlider;
class VerticalLayout; class VerticalLayout;
} // namespace Ui } // namespace Ui

View file

@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/sandbox.h" #include "core/sandbox.h"
#include "core/application.h" #include "core/application.h"
#include "export/export_manager.h" #include "export/export_manager.h"
#include "inline_bots/bot_attach_web_view.h" // AttachWebView::cancel.
#include "intro/intro_widget.h" #include "intro/intro_widget.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "main/main_account.h" // Account::sessionValue. #include "main/main_account.h" // Account::sessionValue.
@ -198,6 +199,9 @@ void MainWindow::setupPasscodeLock() {
_passcodeLock->showFinished(); _passcodeLock->showFinished();
setInnerFocus(); setInnerFocus();
} }
if (const auto sessionController = controller().sessionController()) {
sessionController->session().attachWebView().cancel();
}
} }
void MainWindow::clearPasscodeLock() { void MainWindow::clearPasscodeLock() {

View file

@ -1560,7 +1560,7 @@ Ui::PreparedFileInformation PrepareForSending(
FFMpegAttributesReader reader(Core::FileLocation(fname), data); FFMpegAttributesReader reader(Core::FileLocation(fname), data);
const auto positionMs = crl::time(0); const auto positionMs = crl::time(0);
if (reader.open(positionMs) && reader.duration() > 0) { if (reader.open(positionMs) && reader.duration() > 0) {
result.duration = reader.duration() / 1000; result.duration = reader.duration();
result.title = reader.title(); result.title = reader.title();
result.performer = reader.performer(); result.performer = reader.performer();
result.cover = reader.cover(); result.cover = reader.cover();

View file

@ -900,7 +900,7 @@ void OverlayWidget::savePosition() {
void OverlayWidget::updateGeometry(bool inMove) { void OverlayWidget::updateGeometry(bool inMove) {
initFullScreen(); initFullScreen();
if (_fullscreen) { if (_fullscreen && (!Platform::IsWindows11OrGreater() || !isHidden())) {
updateGeometryToScreen(inMove); updateGeometryToScreen(inMove);
} else if (_windowed && _normalGeometryInited) { } else if (_windowed && _normalGeometryInited) {
_window->setGeometry(_normalGeometry); _window->setGeometry(_normalGeometry);
@ -3209,6 +3209,12 @@ void OverlayWidget::show(OpenRequest request) {
// Count top notch on macOS before counting geometry. // Count top notch on macOS before counting geometry.
_helper->beforeShow(_fullscreen); _helper->beforeShow(_fullscreen);
} }
if (_cachedShow) {
_cachedShow->showOrHideBoxOrLayer(
v::null,
Ui::LayerOption::CloseOther,
anim::type::instant);
}
if (photo) { if (photo) {
if (contextItem && contextPeer) { if (contextItem && contextPeer) {
return; return;
@ -3529,6 +3535,9 @@ void OverlayWidget::showAndActivate() {
_wasWindowedMode = true; _wasWindowedMode = true;
} else if (_fullscreen) { } else if (_fullscreen) {
_window->showFullScreen(); _window->showFullScreen();
if (Platform::IsWindows11OrGreater()) {
updateGeometry();
}
} else { } else {
_window->showMaximized(); _window->showMaximized();
} }
@ -4045,8 +4054,8 @@ void OverlayWidget::restartAtSeekPosition(crl::time position) {
const auto messageId = _message ? _message->fullId() : FullMsgId(); const auto messageId = _message ? _message->fullId() : FullMsgId();
options.audioId = AudioMsgId(_document, messageId); options.audioId = AudioMsgId(_document, messageId);
options.speed = _stories options.speed = _stories
? Core::App().settings().videoPlaybackSpeed() ? 1.
: 1.; : Core::App().settings().videoPlaybackSpeed();
if (_pip) { if (_pip) {
_pip = nullptr; _pip = nullptr;
} }

View file

@ -65,7 +65,7 @@ QByteArray DnsUserAgent() {
static const auto kResult = QByteArray( static const auto kResult = QByteArray(
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) " "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) " "AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/114.0.5735.133 Safari/537.36"); "Chrome/115.0.5790.102 Safari/537.36");
return kResult; return kResult;
} }

View file

@ -12,21 +12,25 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtGui/QDesktopServices> #include <QtGui/QDesktopServices>
#include <glibmm.h> #include <gio/gio.hpp>
#include <giomm.h>
using namespace gi::repository;
namespace Platform { namespace Platform {
namespace File { namespace File {
void UnsafeOpenUrl(const QString &url) { void UnsafeOpenUrl(const QString &url) {
try { {
if (Gio::AppInfo::launch_default_for_uri( const auto result = Gio::AppInfo::launch_default_for_uri(
url.toStdString(), url.toStdString(),
base::Platform::AppLaunchContext())) { base::Platform::AppLaunchContext());
if (!result) {
LOG(("App Error: %1").arg(
QString::fromStdString(result.error().what())));
} else if (*result) {
return; return;
} }
} catch (const std::exception &e) {
LOG(("App Error: %1").arg(QString::fromStdString(e.what())));
} }
QDesktopServices::openUrl(url); QDesktopServices::openUrl(url);
@ -45,14 +49,29 @@ bool UnsafeShowOpenWith(const QString &filepath) {
} }
void UnsafeLaunch(const QString &filepath) { void UnsafeLaunch(const QString &filepath) {
try { if ([&] {
if (Gio::AppInfo::launch_default_for_uri( const auto filename = GLib::filename_to_uri(filepath.toStdString());
Glib::filename_to_uri(filepath.toStdString()), if (!filename) {
base::Platform::AppLaunchContext())) { LOG(("App Error: %1").arg(
return; QString::fromStdString(filename.error().what())));
return false;
} }
} catch (const std::exception &e) {
LOG(("App Error: %1").arg(QString::fromStdString(e.what()))); const auto result = Gio::AppInfo::launch_default_for_uri(
*filename,
base::Platform::AppLaunchContext());
if (!result) {
LOG(("App Error: %1").arg(
QString::fromStdString(result.error().what())));
return false;
}
return *result;
}()) {
return;
} }
if (UnsafeShowOpenWith(filepath)) { if (UnsafeShowOpenWith(filepath)) {

View file

@ -17,79 +17,168 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtCore/QAbstractEventDispatcher> #include <QtCore/QAbstractEventDispatcher>
#include <glibmm.h>
#include <gio/gio.hpp>
#include <xdpinhibit/xdpinhibit.hpp> #include <xdpinhibit/xdpinhibit.hpp>
#include <giomm.h>
typedef GApplication TDesktopApplication; namespace Platform {
typedef GApplicationClass TDesktopApplicationClass; namespace {
G_DEFINE_TYPE( using namespace gi::repository;
TDesktopApplication,
t_desktop_application,
G_TYPE_APPLICATION)
static void t_desktop_application_class_init( class Application : public Gio::impl::ApplicationImpl {
TDesktopApplicationClass *klass) { public:
const auto application_class = G_APPLICATION_CLASS(klass); Application();
application_class->local_command_line = []( void before_emit_(GLib::Variant platformData) noexcept override {
GApplication *application,
char ***arguments,
int *exit_status) -> gboolean {
return false;
};
application_class->command_line = [](
GApplication *application,
GApplicationCommandLine *cmdline) {
return 0;
};
application_class->before_emit = [](
GApplication *application,
GVariant *platformData) {
if (Platform::IsWayland()) { if (Platform::IsWayland()) {
static const auto keys = { static const auto keys = {
"activation-token", "activation-token",
"desktop-startup-id", "desktop-startup-id",
}; };
for (const auto &key : keys) { for (const auto &key : keys) {
const char *token = nullptr; if (auto token = platformData.lookup_value(key)) {
g_variant_lookup(platformData, key, "&s", &token); qputenv(
if (token) { "XDG_ACTIVATION_TOKEN",
qputenv("XDG_ACTIVATION_TOKEN", token); token.get_string(nullptr).c_str());
break; break;
} }
} }
} }
}; }
application_class->add_platform_data = []( void activate_() noexcept override {
GApplication *application, Core::Sandbox::Instance().customEnterFromEventLoop([] {
GVariantBuilder *builder) { Core::App().activate();
});
}
void open_(GFile **files, int n_files, const char*) noexcept override {
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
for (int i = 0; i < n_files; ++i) {
QFileOpenEvent e(
QUrl(QString::fromUtf8(g_file_get_uri(files[i]))));
QGuiApplication::sendEvent(qApp, &e);
}
});
}
void add_platform_data_(GLib::VariantBuilder builder) noexcept override {
if (Platform::IsWayland()) { if (Platform::IsWayland()) {
const auto token = qgetenv("XDG_ACTIVATION_TOKEN"); const auto token = qgetenv("XDG_ACTIVATION_TOKEN");
if (!token.isEmpty()) { if (!token.isEmpty()) {
g_variant_builder_add( builder.add_value(
builder, GLib::Variant::new_dict_entry(
"{sv}", GLib::Variant::new_string("activation-token"),
"activation-token", GLib::Variant::new_variant(
g_variant_new_string(token.constData())); GLib::Variant::new_string(token.toStdString()))));
qunsetenv("XDG_ACTIVATION_TOKEN"); qunsetenv("XDG_ACTIVATION_TOKEN");
} }
} }
}; }
};
Application::Application()
: Gio::impl::ApplicationImpl(this) {
const auto appId = QGuiApplication::desktopFileName().toStdString();
if (Gio::Application::id_is_valid(appId)) {
set_application_id(appId);
}
set_flags(Gio::ApplicationFlags::HANDLES_OPEN_);
auto actionMap = Gio::ActionMap(*this);
auto quitAction = Gio::SimpleAction::new_("quit");
quitAction.signal_activate().connect([](
Gio::SimpleAction,
GLib::Variant parameter) {
Core::Sandbox::Instance().customEnterFromEventLoop([] {
Core::Quit();
});
});
actionMap.add_action(quitAction);
using Window::Notifications::Manager;
using NotificationId = Manager::NotificationId;
using NotificationIdTuple = std::invoke_result_t<
decltype(&NotificationId::toTuple),
NotificationId*
>;
const auto notificationIdVariantType = [] {
try {
return gi::wrap(
Glib::create_variant(
NotificationId().toTuple()
).get_type().gobj_copy(),
gi::transfer_full,
gi::direction_out
);
} catch (...) {
return GLib::VariantType();
}
}();
auto notificationActivateAction = Gio::SimpleAction::new_(
"notification-activate",
notificationIdVariantType);
notificationActivateAction.signal_activate().connect([](
Gio::SimpleAction,
GLib::Variant parameter) {
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
try {
const auto &app = Core::App();
app.notifications().manager().notificationActivated(
NotificationId::FromTuple(
Glib::wrap(
parameter.gobj_copy_()
).get_dynamic<NotificationIdTuple>()
)
);
} catch (...) {
}
});
});
actionMap.add_action(notificationActivateAction);
auto notificationMarkAsReadAction = Gio::SimpleAction::new_(
"notification-mark-as-read",
notificationIdVariantType);
notificationMarkAsReadAction.signal_activate().connect([](
Gio::SimpleAction,
GLib::Variant parameter) {
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
try {
const auto &app = Core::App();
app.notifications().manager().notificationReplied(
NotificationId::FromTuple(
Glib::wrap(
parameter.gobj_copy_()
).get_dynamic<NotificationIdTuple>()
),
{}
);
} catch (...) {
}
});
});
actionMap.add_action(notificationMarkAsReadAction);
} }
static void t_desktop_application_init(TDesktopApplication *application) { gi::ref_ptr<Application> MakeApplication() {
const auto result = gi::make_ref<Application>();
if (const auto registered = result->register_(); !registered) {
LOG(("App Error: Failed to register: %1").arg(
QString::fromStdString(registered.error().message_())));
return nullptr;
}
return result;
} }
namespace Platform {
namespace {
using namespace gi::repository;
namespace Gio = gi::repository::Gio;
class LinuxIntegration final : public Integration { class LinuxIntegration final : public Integration {
public: public:
LinuxIntegration(); LinuxIntegration();
@ -103,14 +192,14 @@ private:
void initInhibit(); void initInhibit();
static void LaunchNativeApplication(); const gi::ref_ptr<Application> _application;
XdpInhibit::InhibitProxy _inhibitProxy; XdpInhibit::InhibitProxy _inhibitProxy;
base::Platform::XDP::SettingWatcher _darkModeWatcher; base::Platform::XDP::SettingWatcher _darkModeWatcher;
}; };
LinuxIntegration::LinuxIntegration() LinuxIntegration::LinuxIntegration()
: _inhibitProxy( : _application(MakeApplication())
, _inhibitProxy(
XdpInhibit::InhibitProxy::new_for_bus_sync( XdpInhibit::InhibitProxy::new_for_bus_sync(
Gio::BusType::SESSION_, Gio::BusType::SESSION_,
Gio::DBusProxyFlags::DO_NOT_AUTO_START_AT_CONSTRUCTION_, Gio::DBusProxyFlags::DO_NOT_AUTO_START_AT_CONSTRUCTION_,
@ -139,16 +228,12 @@ LinuxIntegration::LinuxIntegration()
if (!QCoreApplication::eventDispatcher()->inherits( if (!QCoreApplication::eventDispatcher()->inherits(
"QEventDispatcherGlib")) { "QEventDispatcherGlib")) {
g_warning("Qt is running without GLib event loop integration, " g_warning("Qt is running without GLib event loop integration, "
"except various functionality to not to work."); "expect various functionality to not to work.");
} }
} }
void LinuxIntegration::init() { void LinuxIntegration::init() {
initInhibit(); initInhibit();
Glib::signal_idle().connect_once([] {
LaunchNativeApplication();
});
} }
void LinuxIntegration::initInhibit() { void LinuxIntegration::initInhibit() {
@ -156,7 +241,11 @@ void LinuxIntegration::initInhibit() {
return; return;
} }
auto uniqueName = _inhibitProxy.get_connection().get_unique_name(); auto uniqueName = _inhibitProxy
.get_connection()
.get_unique_name()
.value_or("");
uniqueName.erase(0, 1); uniqueName.erase(0, 1);
uniqueName.replace(uniqueName.find('.'), 1, 1, '_'); uniqueName.replace(uniqueName.find('.'), 1, 1, '_');
@ -207,115 +296,6 @@ void LinuxIntegration::initInhibit() {
nullptr); nullptr);
} }
void LinuxIntegration::LaunchNativeApplication() {
const auto appId = QGuiApplication::desktopFileName().toStdString();
const auto app = Glib::wrap(
G_APPLICATION(
g_object_new(
t_desktop_application_get_type(),
"application-id",
::Gio::Application::id_is_valid(appId)
? appId.c_str()
: nullptr,
"flags",
G_APPLICATION_HANDLES_OPEN,
nullptr)));
app->signal_startup().connect([weak = std::weak_ptr(app)] {
const auto app = weak.lock();
if (!app) {
return;
}
// GNotification
InvokeQueued(qApp, [] {
Core::App().notifications().createManager();
});
QEventLoop().exec();
app->quit();
}, true);
app->signal_activate().connect([] {
Core::Sandbox::Instance().customEnterFromEventLoop([] {
Core::App().activate();
});
}, true);
app->signal_open().connect([](
const ::Gio::Application::type_vec_files &files,
const Glib::ustring &hint) {
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
for (const auto &file : files) {
QFileOpenEvent e(
QUrl(QString::fromStdString(file->get_uri())));
QGuiApplication::sendEvent(qApp, &e);
}
});
}, true);
app->add_action("quit", [] {
Core::Sandbox::Instance().customEnterFromEventLoop([] {
Core::Quit();
});
});
using Window::Notifications::Manager;
using NotificationId = Manager::NotificationId;
using NotificationIdTuple = std::invoke_result_t<
decltype(&NotificationId::toTuple),
NotificationId*
>;
const auto notificationIdVariantType = [] {
try {
return Glib::create_variant(
NotificationId().toTuple()
).get_type();
} catch (...) {
return Glib::VariantType();
}
}();
app->add_action_with_parameter(
"notification-activate",
notificationIdVariantType,
[](const Glib::VariantBase &parameter) {
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
try {
const auto &app = Core::App();
app.notifications().manager().notificationActivated(
NotificationId::FromTuple(
parameter.get_dynamic<NotificationIdTuple>()
)
);
} catch (...) {
}
});
});
app->add_action_with_parameter(
"notification-mark-as-read",
notificationIdVariantType,
[](const Glib::VariantBase &parameter) {
Core::Sandbox::Instance().customEnterFromEventLoop([&] {
try {
const auto &app = Core::App();
app.notifications().manager().notificationReplied(
NotificationId::FromTuple(
parameter.get_dynamic<NotificationIdTuple>()
),
{}
);
} catch (...) {
}
});
});
app->run(0, nullptr);
}
} // namespace } // namespace
std::unique_ptr<Integration> CreateIntegration() { std::unique_ptr<Integration> CreateIntegration() {

View file

@ -360,6 +360,7 @@ private:
Glib::RefPtr<Gio::Application> _application; Glib::RefPtr<Gio::Application> _application;
Glib::RefPtr<Gio::Notification> _notification; Glib::RefPtr<Gio::Notification> _notification;
const std::string _guid;
Glib::RefPtr<Gio::DBus::Connection> _dbusConnection; Glib::RefPtr<Gio::DBus::Connection> _dbusConnection;
Glib::ustring _title; Glib::ustring _title;
@ -390,7 +391,8 @@ NotificationData::NotificationData(
, _id(id) , _id(id)
, _application(UseGNotification() , _application(UseGNotification()
? Gio::Application::get_default() ? Gio::Application::get_default()
: nullptr) { : nullptr)
, _guid(_application ? Gio::DBus::generate_guid() : std::string()) {
} }
bool NotificationData::init( bool NotificationData::init(
@ -623,13 +625,7 @@ NotificationData::~NotificationData() {
void NotificationData::show() { void NotificationData::show() {
if (_application && _notification) { if (_application && _notification) {
_application->send_notification( _application->send_notification(_guid, _notification);
std::to_string(_id.contextId.sessionId)
+ '-'
+ std::to_string(_id.contextId.peerId.value)
+ '-'
+ std::to_string(_id.msgId.bare),
_notification);
return; return;
} }
@ -679,12 +675,7 @@ void NotificationData::show() {
void NotificationData::close() { void NotificationData::close() {
if (_application) { if (_application) {
_application->withdraw_notification( _application->withdraw_notification(_guid);
std::to_string(_id.contextId.sessionId)
+ '-'
+ std::to_string(_id.contextId.peerId.value)
+ '-'
+ std::to_string(_id.msgId.bare));
_manager->clearNotification(_id); _manager->clearNotification(_id);
return; return;
} }

View file

@ -382,11 +382,18 @@ bool GenerateServiceFile(bool silent = false) {
md5Hash)); md5Hash));
} }
QProcess::execute(u"systemctl"_q, { try {
u"--user"_q, const auto connection = Gio::DBus::Connection::get_sync(
u"reload"_q, Gio::DBus::BusType::SESSION);
u"dbus"_q,
}); connection->call_sync(
base::Platform::DBus::kObjectPath,
base::Platform::DBus::kInterface,
"ReloadConfig",
{},
base::Platform::DBus::kService);
} catch (...) {
}
return true; return true;
} }

View file

@ -238,7 +238,6 @@ MainWindow::MainWindow(not_null<Window::Controller*> controller)
: Window::MainWindow(controller) : Window::MainWindow(controller)
, _private(std::make_unique<Private>(this)) , _private(std::make_unique<Private>(this))
, psMainMenu(this) { , psMainMenu(this) {
auto forceOpenGL = std::make_unique<QOpenGLWidget>(this);
_hideAfterFullScreenTimer.setCallback([this] { hideAndDeactivate(); }); _hideAfterFullScreenTimer.setCallback([this] { hideAndDeactivate(); });
} }

View file

@ -737,18 +737,19 @@ void SetupANGLE(
tr::lng_settings_angle_backend_d3d11(tr::now), tr::lng_settings_angle_backend_d3d11(tr::now),
tr::lng_settings_angle_backend_d3d9(tr::now), tr::lng_settings_angle_backend_d3d9(tr::now),
tr::lng_settings_angle_backend_d3d11on12(tr::now), tr::lng_settings_angle_backend_d3d11on12(tr::now),
tr::lng_settings_angle_backend_opengl(tr::now), //tr::lng_settings_angle_backend_opengl(tr::now),
tr::lng_settings_angle_backend_disabled(tr::now), tr::lng_settings_angle_backend_disabled(tr::now),
}; };
const auto backendIndex = [] { const auto disabled = int(options.size()) - 1;
const auto backendIndex = [=] {
if (Core::App().settings().disableOpenGL()) { if (Core::App().settings().disableOpenGL()) {
return 5; return disabled;
} else switch (Ui::GL::CurrentANGLE()) { } else switch (Ui::GL::CurrentANGLE()) {
case ANGLE::Auto: return 0; case ANGLE::Auto: return 0;
case ANGLE::D3D11: return 1; case ANGLE::D3D11: return 1;
case ANGLE::D3D9: return 2; case ANGLE::D3D9: return 2;
case ANGLE::D3D11on12: return 3; case ANGLE::D3D11on12: return 3;
case ANGLE::OpenGL: return 4; //case ANGLE::OpenGL: return 4;
} }
Unexpected("Ui::GL::CurrentANGLE value in SetupANGLE."); Unexpected("Ui::GL::CurrentANGLE value in SetupANGLE.");
}(); }();
@ -764,7 +765,7 @@ void SetupANGLE(
return; return;
} }
const auto confirmed = crl::guard(button, [=] { const auto confirmed = crl::guard(button, [=] {
const auto nowDisabled = (index == 5); const auto nowDisabled = (index == disabled);
if (!nowDisabled) { if (!nowDisabled) {
Ui::GL::ChangeANGLE([&] { Ui::GL::ChangeANGLE([&] {
switch (index) { switch (index) {
@ -772,12 +773,12 @@ void SetupANGLE(
case 1: return ANGLE::D3D11; case 1: return ANGLE::D3D11;
case 2: return ANGLE::D3D9; case 2: return ANGLE::D3D9;
case 3: return ANGLE::D3D11on12; case 3: return ANGLE::D3D11on12;
case 4: return ANGLE::OpenGL; //case 4: return ANGLE::OpenGL;
} }
Unexpected("Index in SetupANGLE."); Unexpected("Index in SetupANGLE.");
}()); }());
} }
const auto wasDisabled = (backendIndex == 5); const auto wasDisabled = (backendIndex == disabled);
if (nowDisabled != wasDisabled) { if (nowDisabled != wasDisabled) {
Core::App().settings().setDisableOpenGL(nowDisabled); Core::App().settings().setDisableOpenGL(nowDisabled);
Local::writeSettings(); Local::writeSettings();

View file

@ -526,7 +526,7 @@ FileLoadTask::FileLoadTask(
FileLoadTask::FileLoadTask( FileLoadTask::FileLoadTask(
not_null<Main::Session*> session, not_null<Main::Session*> session,
const QByteArray &voice, const QByteArray &voice,
int32 duration, crl::time duration,
const VoiceWaveform &waveform, const VoiceWaveform &waveform,
const FileLoadTo &to, const FileLoadTo &to,
const TextWithTags &caption) const TextWithTags &caption)
@ -852,8 +852,9 @@ void FileLoadTask::process(Args &&args) {
if (auto song = std::get_if<Ui::PreparedFileInformation::Song>( if (auto song = std::get_if<Ui::PreparedFileInformation::Song>(
&_information->media)) { &_information->media)) {
isSong = true; isSong = true;
const auto seconds = song->duration / 1000;
auto flags = MTPDdocumentAttributeAudio::Flag::f_title | MTPDdocumentAttributeAudio::Flag::f_performer; auto flags = MTPDdocumentAttributeAudio::Flag::f_title | MTPDdocumentAttributeAudio::Flag::f_performer;
attributes.push_back(MTP_documentAttributeAudio(MTP_flags(flags), MTP_int(song->duration), MTP_string(song->title), MTP_string(song->performer), MTPstring())); attributes.push_back(MTP_documentAttributeAudio(MTP_flags(flags), MTP_int(seconds), MTP_string(song->title), MTP_string(song->performer), MTPstring()));
thumbnail = PrepareFileThumbnail(std::move(song->cover)); thumbnail = PrepareFileThumbnail(std::move(song->cover));
} else if (auto video = std::get_if<Ui::PreparedFileInformation::Video>( } else if (auto video = std::get_if<Ui::PreparedFileInformation::Video>(
&_information->media)) { &_information->media)) {
@ -867,9 +868,10 @@ void FileLoadTask::process(Args &&args) {
if (video->supportsStreaming) { if (video->supportsStreaming) {
flags |= MTPDdocumentAttributeVideo::Flag::f_supports_streaming; flags |= MTPDdocumentAttributeVideo::Flag::f_supports_streaming;
} }
const auto realSeconds = video->duration / 1000.;
attributes.push_back(MTP_documentAttributeVideo( attributes.push_back(MTP_documentAttributeVideo(
MTP_flags(flags), MTP_flags(flags),
MTP_double(video->duration / 1000.), MTP_double(realSeconds),
MTP_int(coverWidth), MTP_int(coverWidth),
MTP_int(coverHeight), MTP_int(coverHeight),
MTPint())); // preload_prefix_size MTPint())); // preload_prefix_size
@ -971,8 +973,9 @@ void FileLoadTask::process(Args &&args) {
} }
if (isVoice) { if (isVoice) {
const auto seconds = _duration / 1000;
auto flags = MTPDdocumentAttributeAudio::Flag::f_voice | MTPDdocumentAttributeAudio::Flag::f_waveform; auto flags = MTPDdocumentAttributeAudio::Flag::f_voice | MTPDdocumentAttributeAudio::Flag::f_waveform;
attributes[0] = MTP_documentAttributeAudio(MTP_flags(flags), MTP_int(_duration), MTPstring(), MTPstring(), MTP_bytes(documentWaveformEncode5bit(_waveform))); attributes[0] = MTP_documentAttributeAudio(MTP_flags(flags), MTP_int(seconds), MTPstring(), MTPstring(), MTP_bytes(documentWaveformEncode5bit(_waveform)));
attributes.resize(1); attributes.resize(1);
document = MTP_document( document = MTP_document(
MTP_flags(0), MTP_flags(0),

View file

@ -256,7 +256,7 @@ public:
FileLoadTask( FileLoadTask(
not_null<Main::Session*> session, not_null<Main::Session*> session,
const QByteArray &voice, const QByteArray &voice,
int32 duration, crl::time duration,
const VoiceWaveform &waveform, const VoiceWaveform &waveform,
const FileLoadTo &to, const FileLoadTo &to,
const TextWithTags &caption); const TextWithTags &caption);
@ -306,7 +306,7 @@ private:
QString _filepath; QString _filepath;
QByteArray _content; QByteArray _content;
std::unique_ptr<Ui::PreparedFileInformation> _information; std::unique_ptr<Ui::PreparedFileInformation> _information;
int32 _duration = 0; crl::time _duration = 0;
VoiceWaveform _waveform; VoiceWaveform _waveform;
SendMediaType _type; SendMediaType _type;
TextWithTags _caption; TextWithTags _caption;

View file

@ -259,8 +259,7 @@ void AlbumThumbnail::paintInAlbum(
_lastRectOfButtons = paintButtons( _lastRectOfButtons = paintButtons(
p, p,
geometry.topLeft(), geometry,
geometry.width(),
shrinkProgress); shrinkProgress);
_lastRectOfModify = geometry; _lastRectOfModify = geometry;
} }
@ -460,8 +459,7 @@ void AlbumThumbnail::paintPhoto(Painter &p, int left, int top, int outerWidth) {
_lastRectOfButtons = paintButtons( _lastRectOfButtons = paintButtons(
p, p,
topLeft, QRect(left, top, st::sendMediaPreviewSize, size.height()),
st::sendMediaPreviewSize,
0); 0);
_lastRectOfModify = QRect(topLeft, size); _lastRectOfModify = QRect(topLeft, size);
@ -521,7 +519,9 @@ AttachButtonType AlbumThumbnail::buttonTypeFromPoint(QPoint position) const {
} }
return (!_lastRectOfButtons.contains(position) && !_isCompressedSticker) return (!_lastRectOfButtons.contains(position) && !_isCompressedSticker)
? AttachButtonType::Modify ? AttachButtonType::Modify
: (position.x() < _lastRectOfButtons.center().x()) : (_buttons.vertical()
? (position.y() < _lastRectOfButtons.center().y())
: (position.x() < _lastRectOfButtons.center().x()))
? AttachButtonType::Edit ? AttachButtonType::Edit
: AttachButtonType::Delete; : AttachButtonType::Delete;
} }
@ -585,24 +585,31 @@ void AlbumThumbnail::finishAnimations() {
QRect AlbumThumbnail::paintButtons( QRect AlbumThumbnail::paintButtons(
QPainter &p, QPainter &p,
QPoint point, QRect geometry,
int outerWidth,
float64 shrinkProgress) { float64 shrinkProgress) {
const auto &skipRight = st::sendBoxAlbumGroupSkipRight; const auto &skipRight = st::sendBoxAlbumGroupSkipRight;
const auto &skipTop = st::sendBoxAlbumGroupSkipTop; const auto &skipTop = st::sendBoxAlbumGroupSkipTop;
const auto groupWidth = _buttons.width(); const auto outerWidth = geometry.width();
const auto outerHeight = geometry.height();
// If the width is tiny, it would be better to not display the buttons. if (st::sendBoxAlbumGroupSize.width() <= outerWidth) {
if (groupWidth > outerWidth) { _buttons.setVertical(false);
} else if (st::sendBoxAlbumGroupSize.height() <= outerHeight) {
_buttons.setVertical(true);
} else {
// If the size is tiny, skip the buttons.
return QRect(); return QRect();
} }
const auto groupWidth = _buttons.width();
const auto groupHeight = _buttons.height();
// If the width is too small, // If the width is too small,
// it would be better to display the buttons in the center. // it would be better to display the buttons in the center.
const auto groupX = point.x() + ((groupWidth + skipRight * 2 > outerWidth) const auto groupX = geometry.x() + ((groupWidth + skipRight * 2 > outerWidth)
? (outerWidth - groupWidth) / 2 ? (outerWidth - groupWidth) / 2
: outerWidth - skipRight - groupWidth); : outerWidth - skipRight - groupWidth);
const auto groupY = point.y() + skipTop; const auto groupY = geometry.y() + ((groupHeight + skipTop * 2 > outerHeight)
? (outerHeight - groupHeight) / 2
: skipTop);
const auto opacity = p.opacity(); const auto opacity = p.opacity();
p.setOpacity(1.0 - shrinkProgress); p.setOpacity(1.0 - shrinkProgress);

View file

@ -78,8 +78,7 @@ private:
void drawSimpleFrame(QPainter &p, QRect to, QSize size) const; void drawSimpleFrame(QPainter &p, QRect to, QSize size) const;
QRect paintButtons( QRect paintButtons(
QPainter &p, QPainter &p,
QPoint point, QRect geometry,
int outerWidth,
float64 shrinkProgress); float64 shrinkProgress);
void paintPlayVideo(QPainter &p, QRect geometry); void paintPlayVideo(QPainter &p, QRect geometry);

View file

@ -25,10 +25,15 @@ void AttachControls::paint(QPainter &p, int x, int y) {
if (full) { if (full) {
const auto groupHalfWidth = groupWidth / 2; const auto groupHalfWidth = groupWidth / 2;
QRect leftRect(x, y, groupHalfWidth, groupHeight); const auto groupHalfHeight = groupHeight / 2;
st::sendBoxAlbumGroupButtonMediaEdit.paintInCenter(p, leftRect); const auto editRect = _vertical
QRect rightRect(x + groupHalfWidth, y, groupHalfWidth, groupHeight); ? QRect(x, y, groupWidth, groupHalfHeight)
st::sendBoxAlbumGroupButtonMediaDelete.paintInCenter(p, rightRect); : QRect(x, y, groupHalfWidth, groupHeight);
st::sendBoxAlbumGroupButtonMediaEdit.paintInCenter(p, editRect);
const auto deleteRect = _vertical
? QRect(x, y + groupHalfHeight, groupWidth, groupHalfHeight)
: QRect(x + groupHalfWidth, y, groupHalfWidth, groupHeight);
st::sendBoxAlbumGroupButtonMediaDelete.paintInCenter(p, deleteRect);
} else if (_type == Type::EditOnly) { } else if (_type == Type::EditOnly) {
st::sendBoxAlbumButtonMediaEdit.paintInCenter(p, groupRect); st::sendBoxAlbumButtonMediaEdit.paintInCenter(p, groupRect);
} }
@ -36,7 +41,9 @@ void AttachControls::paint(QPainter &p, int x, int y) {
int AttachControls::width() const { int AttachControls::width() const {
return (_type == Type::Full) return (_type == Type::Full)
? st::sendBoxAlbumGroupSize.width() ? (_vertical
? st::sendBoxAlbumGroupSizeVertical.width()
: st::sendBoxAlbumGroupSize.width())
: (_type == Type::EditOnly) : (_type == Type::EditOnly)
? st::sendBoxAlbumSmallGroupSize.width() ? st::sendBoxAlbumSmallGroupSize.width()
: 0; : 0;
@ -44,7 +51,9 @@ int AttachControls::width() const {
int AttachControls::height() const { int AttachControls::height() const {
return (_type == Type::Full) return (_type == Type::Full)
? st::sendBoxAlbumGroupSize.height() ? (_vertical
? st::sendBoxAlbumGroupSizeVertical.height()
: st::sendBoxAlbumGroupSize.height())
: (_type == Type::EditOnly) : (_type == Type::EditOnly)
? st::sendBoxAlbumSmallGroupSize.height() ? st::sendBoxAlbumSmallGroupSize.height()
: 0; : 0;
@ -54,12 +63,20 @@ AttachControls::Type AttachControls::type() const {
return _type; return _type;
} }
bool AttachControls::vertical() const {
return _vertical;
}
void AttachControls::setType(Type type) { void AttachControls::setType(Type type) {
if (_type != type) { if (_type != type) {
_type = type; _type = type;
} }
} }
void AttachControls::setVertical(bool vertical) {
_vertical = vertical;
}
AttachControlsWidget::AttachControlsWidget( AttachControlsWidget::AttachControlsWidget(
not_null<RpWidget*> parent, not_null<RpWidget*> parent,
AttachControls::Type type) AttachControls::Type type)

View file

@ -25,14 +25,17 @@ public:
void paint(QPainter &p, int x, int y); void paint(QPainter &p, int x, int y);
void setType(Type type); void setType(Type type);
void setVertical(bool vertical);
[[nodiscard]] int width() const; [[nodiscard]] int width() const;
[[nodiscard]] int height() const; [[nodiscard]] int height() const;
[[nodiscard]] Type type() const; [[nodiscard]] Type type() const;
[[nodiscard]] bool vertical() const;
private: private:
RoundRect _rect; RoundRect _rect;
Type _type = Type::Full; Type _type = Type::Full;
bool _vertical = false;
}; };

View file

@ -27,7 +27,7 @@ struct PreparedFileInformation {
Editor::PhotoModifications modifications; Editor::PhotoModifications modifications;
}; };
struct Song { struct Song {
int duration = -1; crl::time duration = -1;
QString title; QString title;
QString performer; QString performer;
QImage cover; QImage cover;

View file

@ -523,7 +523,7 @@ historyFastShareSize: 31px;
historyFastShareLeft: 13px; historyFastShareLeft: 13px;
historyFastShareBottom: 5px; historyFastShareBottom: 5px;
historyFastShareIcon: icon {{ "fast_share", msgServiceFg }}; historyFastShareIcon: icon {{ "fast_share", msgServiceFg }};
historyGoToOriginalIcon: icon {{ "fast_to_original", msgServiceFg }}; historyGoToOriginalIcon: icon {{ "fast_to_original", msgServiceFg, point(1px, 0px) }};
historyFastCommentsIcon: icon {{ "fast_comments", msgServiceFg }}; historyFastCommentsIcon: icon {{ "fast_comments", msgServiceFg }};
historyFastTranscribeIcon: icon {{ "chat/voice_to_text", msgServiceFg }}; historyFastTranscribeIcon: icon {{ "chat/voice_to_text", msgServiceFg }};

View file

@ -31,23 +31,29 @@ SilentToggle::SilentToggle(QWidget *parent, not_null<ChannelData*> channel)
resize(_st.width, _st.height); resize(_st.width, _st.height);
paintRequest(
) | rpl::start_with_next([=](const QRect &clip) {
auto p = QPainter(this);
paintRipple(p, _st.rippleAreaPosition, nullptr);
//const auto checked = _crossLineAnimation.value(_checked ? 1. : 0.);
const auto over = isOver();
(_checked
? (over
? st::historySilentToggleOnOver
: st::historySilentToggleOn)
: (over
? st::historySilentToggle.iconOver
: st::historySilentToggle.icon)).paintInCenter(p, rect());
}, lifetime());
setMouseTracking(true); setMouseTracking(true);
clicks(
) | rpl::start_with_next([=] {
setChecked(!_checked);
Ui::Tooltip::Show(0, this);
_channel->owner().notifySettings().update(_channel, {}, _checked);
}, lifetime());
}
void SilentToggle::paintEvent(QPaintEvent *e) {
auto p = QPainter(this);
paintRipple(p, _st.rippleAreaPosition, nullptr);
//const auto checked = _crossLineAnimation.value(_checked ? 1. : 0.);
const auto over = isOver();
(_checked
? (over
? st::historySilentToggleOnOver
: st::historySilentToggleOn)
: (over
? st::historySilentToggle.iconOver
: st::historySilentToggle.icon)).paintInCenter(p, rect());
} }
void SilentToggle::mouseMoveEvent(QMouseEvent *e) { void SilentToggle::mouseMoveEvent(QMouseEvent *e) {
@ -62,11 +68,12 @@ void SilentToggle::mouseMoveEvent(QMouseEvent *e) {
void SilentToggle::setChecked(bool checked) { void SilentToggle::setChecked(bool checked) {
if (_checked != checked) { if (_checked != checked) {
_checked = checked; _checked = checked;
_crossLineAnimation.start( update();
[=] { update(); }, // _crossLineAnimation.start(
_checked ? 0. : 1., // [=] { update(); },
_checked ? 1. : 0., // _checked ? 0. : 1.,
kAnimationDuration); // _checked ? 1. : 0.,
// kAnimationDuration);
} }
} }
@ -75,13 +82,6 @@ void SilentToggle::leaveEventHook(QEvent *e) {
Ui::Tooltip::Hide(); Ui::Tooltip::Hide();
} }
void SilentToggle::mouseReleaseEvent(QMouseEvent *e) {
setChecked(!_checked);
RippleButton::mouseReleaseEvent(e);
Ui::Tooltip::Show(0, this);
_channel->owner().notifySettings().update(_channel, {}, _checked);
}
QString SilentToggle::tooltipText() const { QString SilentToggle::tooltipText() const {
return _checked return _checked
? tr::lng_wont_be_notified(tr::now) ? tr::lng_wont_be_notified(tr::now)

View file

@ -29,8 +29,8 @@ public:
bool tooltipWindowActive() const override; bool tooltipWindowActive() const override;
protected: protected:
void paintEvent(QPaintEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void leaveEventHook(QEvent *e) override; void leaveEventHook(QEvent *e) override;
QImage prepareRippleMask() const override; QImage prepareRippleMask() const override;
@ -42,7 +42,7 @@ private:
not_null<ChannelData*> _channel; not_null<ChannelData*> _channel;
bool _checked = false; bool _checked = false;
Animations::Simple _crossLineAnimation; // Animations::Simple _crossLineAnimation;
}; };

View file

@ -13,7 +13,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Ui { namespace Ui {
DiscreteSlider::DiscreteSlider(QWidget *parent) : RpWidget(parent) { DiscreteSlider::DiscreteSlider(QWidget *parent, bool snapToLabel)
: RpWidget(parent)
, _snapToLabel(snapToLabel) {
setCursor(style::cur_pointer); setCursor(style::cur_pointer);
} }
@ -80,9 +82,23 @@ void DiscreteSlider::setSections(const std::vector<QString> &labels) {
resizeToWidth(width()); resizeToWidth(width());
} }
int DiscreteSlider::getCurrentActiveLeft() { DiscreteSlider::Range DiscreteSlider::getFinalActiveRange() const {
const auto left = _sections.empty() ? 0 : _sections[_selected].left; const auto raw = _sections.empty() ? nullptr : &_sections[_selected];
return _a_left.value(left); if (!raw) {
return { 0, 0 };
}
const auto width = _snapToLabel
? std::min(raw->width, raw->label.maxWidth())
: raw->width;
return { raw->left + ((raw->width - width) / 2), width };
}
DiscreteSlider::Range DiscreteSlider::getCurrentActiveRange() const {
const auto to = getFinalActiveRange();
return {
int(base::SafeRound(_a_left.value(to.left))),
int(base::SafeRound(_a_width.value(to.width))),
};
} }
template <typename Lambda> template <typename Lambda>
@ -138,11 +154,13 @@ void DiscreteSlider::setSelectedSection(int index) {
if (index < 0 || index >= _sections.size()) return; if (index < 0 || index >= _sections.size()) return;
if (_selected != index) { if (_selected != index) {
auto from = _sections[_selected].left; const auto from = getFinalActiveRange();
_selected = index; _selected = index;
auto to = _sections[_selected].left; const auto to = getFinalActiveRange();
auto duration = getAnimationDuration(); const auto duration = getAnimationDuration();
_a_left.start([this] { update(); }, from, to, duration); const auto updater = [=] { update(); };
_a_left.start(updater, from.left, to.left, duration);
_a_width.start(updater, from.width, to.width, duration);
_callbackAfterMs = crl::now() + duration; _callbackAfterMs = crl::now() + duration;
} }
} }
@ -166,7 +184,7 @@ DiscreteSlider::Section::Section(
SettingsSlider::SettingsSlider( SettingsSlider::SettingsSlider(
QWidget *parent, QWidget *parent,
const style::SettingsSlider &st) const style::SettingsSlider &st)
: DiscreteSlider(parent) : DiscreteSlider(parent, st.barSnapToLabel)
, _st(st) { , _st(st) {
if (_st.barRadius > 0) { if (_st.barRadius > 0) {
_bar.emplace(_st.barRadius, _st.barFg); _bar.emplace(_st.barRadius, _st.barFg);
@ -299,7 +317,7 @@ void SettingsSlider::paintEvent(QPaintEvent *e) {
Painter p(this); Painter p(this);
auto clip = e->rect(); auto clip = e->rect();
auto activeLeft = getCurrentActiveLeft(); auto range = getCurrentActiveRange();
const auto drawRect = [&](QRect rect, bool active = false) { const auto drawRect = [&](QRect rect, bool active = false) {
const auto &bar = active ? _barActive : _bar; const auto &bar = active ? _barActive : _bar;
@ -310,9 +328,14 @@ void SettingsSlider::paintEvent(QPaintEvent *e) {
} }
}; };
enumerateSections([&](Section &section) { enumerateSections([&](Section &section) {
const auto activeWidth = _st.barSnapToLabel
? section.label.maxWidth()
: section.width;
const auto activeLeft = section.left
+ (section.width - activeWidth) / 2;
auto active = 1. auto active = 1.
- std::clamp( - std::clamp(
qAbs(activeLeft - section.left) / float64(section.width), qAbs(range.left - activeLeft) / float64(section.width),
0., 0.,
1.); 1.);
if (section.ripple) { if (section.ripple) {
@ -322,36 +345,47 @@ void SettingsSlider::paintEvent(QPaintEvent *e) {
section.ripple.reset(); section.ripple.reset();
} }
} }
auto from = section.left, tofill = section.width; if (!_st.barSnapToLabel) {
if (activeLeft > from) { auto from = activeLeft, tofill = activeWidth;
auto fill = qMin(tofill, activeLeft - from); if (range.left > from) {
drawRect(myrtlrect(from, _st.barTop, fill, _st.barStroke)); auto fill = qMin(tofill, range.left - from);
from += fill; drawRect(myrtlrect(from, _st.barTop, fill, _st.barStroke));
tofill -= fill;
}
if (activeLeft + section.width > from) {
if (auto fill = qMin(tofill, activeLeft + section.width - from)) {
drawRect(
myrtlrect(from, _st.barTop, fill, _st.barStroke),
true);
from += fill; from += fill;
tofill -= fill; tofill -= fill;
} }
if (range.left + activeWidth > from) {
if (auto fill = qMin(tofill, range.left + activeWidth - from)) {
drawRect(
myrtlrect(from, _st.barTop, fill, _st.barStroke),
true);
from += fill;
tofill -= fill;
}
}
if (tofill) {
drawRect(myrtlrect(from, _st.barTop, tofill, _st.barStroke));
}
} }
if (tofill) { const auto labelLeft = section.left + (section.width - section.label.maxWidth()) / 2;
drawRect(myrtlrect(from, _st.barTop, tofill, _st.barStroke)); if (myrtlrect(labelLeft, _st.labelTop, section.label.maxWidth(), _st.labelStyle.font->height).intersects(clip)) {
}
if (myrtlrect(section.left, _st.labelTop, section.width, _st.labelStyle.font->height).intersects(clip)) {
p.setPen(anim::pen(_st.labelFg, _st.labelFgActive, active)); p.setPen(anim::pen(_st.labelFg, _st.labelFgActive, active));
section.label.drawLeft( section.label.drawLeft(
p, p,
section.left + (section.width - section.label.maxWidth()) / 2, labelLeft,
_st.labelTop, _st.labelTop,
section.label.maxWidth(), section.label.maxWidth(),
width()); width());
} }
return true; return true;
}); });
if (_st.barSnapToLabel) {
const auto add = _st.barStroke / 2;
const auto from = std::max(range.left - add, 0);
const auto till = std::min(range.left + range.width + add, width());
if (from < till) {
drawRect(myrtlrect(from, _st.barTop, till - from, _st.barStroke), true);
}
}
} }
} // namespace Ui } // namespace Ui

View file

@ -18,7 +18,7 @@ class RippleAnimation;
class DiscreteSlider : public RpWidget { class DiscreteSlider : public RpWidget {
public: public:
DiscreteSlider(QWidget *parent); DiscreteSlider(QWidget *parent, bool snapToLabel);
void addSection(const QString &label); void addSection(const QString &label);
void setSections(const std::vector<QString> &labels); void setSections(const std::vector<QString> &labels);
@ -49,10 +49,15 @@ protected:
Ui::Text::String label; Ui::Text::String label;
std::unique_ptr<RippleAnimation> ripple; std::unique_ptr<RippleAnimation> ripple;
}; };
struct Range {
int left = 0;
int width = 0;
};
int getCurrentActiveLeft(); [[nodiscard]] Range getFinalActiveRange() const;
[[nodiscard]] Range getCurrentActiveRange() const;
int getSectionsCount() const { [[nodiscard]] int getSectionsCount() const {
return _sections.size(); return _sections.size();
} }
@ -67,6 +72,7 @@ protected:
void stopAnimation() { void stopAnimation() {
_a_left.stop(); _a_left.stop();
_a_width.stop();
} }
void setSelectOnPress(bool selectOnPress); void setSelectOnPress(bool selectOnPress);
@ -82,12 +88,14 @@ private:
std::vector<Section> _sections; std::vector<Section> _sections;
int _activeIndex = 0; int _activeIndex = 0;
bool _selectOnPress = true; bool _selectOnPress = true;
bool _snapToLabel = false;
rpl::event_stream<int> _sectionActivated; rpl::event_stream<int> _sectionActivated;
int _pressed = -1; int _pressed = -1;
int _selected = 0; int _selected = 0;
Ui::Animations::Simple _a_left; Ui::Animations::Simple _a_left;
Ui::Animations::Simple _a_width;
int _timerId = -1; int _timerId = -1;
crl::time _callbackAfterMs = 0; crl::time _callbackAfterMs = 0;

View file

@ -40,9 +40,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtGui/QWindow> #include <QtGui/QWindow>
#if __has_include(<giomm.h>) #if __has_include(<gio/gio.hpp>)
#include <giomm.h> #include <gio/gio.hpp>
#endif // __has_include(<giomm.h>) #endif // __has_include(<gio/gio.hpp>)
namespace Window { namespace Window {
namespace Notifications { namespace Notifications {
@ -90,11 +90,12 @@ base::options::toggle OptionGNotification({
.description = "Force enable GLib's GNotification." .description = "Force enable GLib's GNotification."
" When disabled, autodetect is used.", " When disabled, autodetect is used.",
.scope = [] { .scope = [] {
#if __has_include(<giomm.h>) #if __has_include(<gio/gio.hpp>)
using namespace gi::repository;
return bool(Gio::Application::get_default()); return bool(Gio::Application::get_default());
#else // __has_include(<giomm.h>) #else // __has_include(<gio/gio.hpp>)
return false; return false;
#endif // __has_include(<giomm.h>) #endif // __has_include(<gio/gio.hpp>)
}, },
.restartRequired = true, .restartRequired = true,
}); });

View file

@ -26,7 +26,7 @@ RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.n
autoconf automake libtool patch gperf flex \ autoconf automake libtool patch gperf flex \
fontconfig-devel freetype-devel libX11-devel at-spi2-core-devel alsa-lib-devel \ fontconfig-devel freetype-devel libX11-devel at-spi2-core-devel alsa-lib-devel \
pulseaudio-libs-devel mesa-libGL-devel mesa-libEGL-devel mesa-libgbm-devel \ pulseaudio-libs-devel mesa-libGL-devel mesa-libEGL-devel mesa-libgbm-devel \
libdrm-devel vulkan-devel boost169-devel fmt-devel \ libdrm-devel vulkan-devel libva-devel libvdpau-devel boost169-devel fmt-devel \
gtk3-devel perl-XML-Parser pkgconfig bison yasm file which xorg-x11-util-macros \ gtk3-devel perl-XML-Parser pkgconfig bison yasm file which xorg-x11-util-macros \
devtoolset-10-make devtoolset-10-gcc devtoolset-10-gcc-c++ \ devtoolset-10-make devtoolset-10-gcc devtoolset-10-gcc-c++ \
devtoolset-10-binutils llvm-toolset-7.0 llvm-toolset-7.0-clang-devel \ devtoolset-10-binutils llvm-toolset-7.0 llvm-toolset-7.0-clang-devel \
@ -420,6 +420,17 @@ RUN git clone -b libXfixes-5.0.3 --depth=1 {{ GIT_FREEDESKTOP }}/libxfixes.git \
&& cd .. \ && cd .. \
&& rm -rf libxfixes && rm -rf libxfixes
FROM builder AS libXv
COPY --link --from=libXext {{ LibrariesPath }}/libXext-cache /
RUN git clone -b libXv-1.0.12 --depth=1 {{ GIT_FREEDESKTOP }}/libxv.git \
&& cd libxv \
&& ./autogen.sh --enable-static \
&& make -j$(nproc) \
&& make DESTDIR="{{ LibrariesPath }}/libXv-cache" install \
&& cd .. \
&& rm -rf libxv
FROM builder AS libXrandr FROM builder AS libXrandr
RUN git clone -b libXrandr-1.5.2 --depth=1 {{ GIT_FREEDESKTOP }}/libxrandr.git \ RUN git clone -b libXrandr-1.5.2 --depth=1 {{ GIT_FREEDESKTOP }}/libxrandr.git \
&& cd libxrandr \ && cd libxrandr \
@ -482,6 +493,8 @@ FROM builder AS ffmpeg
COPY --link --from=opus {{ LibrariesPath }}/opus-cache / COPY --link --from=opus {{ LibrariesPath }}/opus-cache /
COPY --link --from=dav1d {{ LibrariesPath }}/dav1d-cache / COPY --link --from=dav1d {{ LibrariesPath }}/dav1d-cache /
COPY --link --from=libvpx {{ LibrariesPath }}/libvpx-cache / COPY --link --from=libvpx {{ LibrariesPath }}/libvpx-cache /
COPY --link --from=libXext {{ LibrariesPath }}/libXext-cache /
COPY --link --from=libXv {{ LibrariesPath }}/libXv-cache /
COPY --link --from=nv-codec-headers {{ LibrariesPath }}/nv-codec-headers-cache / COPY --link --from=nv-codec-headers {{ LibrariesPath }}/nv-codec-headers-cache /
RUN git init ffmpeg \ RUN git init ffmpeg \
@ -503,15 +516,29 @@ RUN git init ffmpeg \
--enable-libdav1d \ --enable-libdav1d \
--enable-libopus \ --enable-libopus \
--enable-libvpx \ --enable-libvpx \
--enable-vaapi \
--enable-vdpau \
--enable-xlib \
--enable-libdrm \
--enable-ffnvcodec \ --enable-ffnvcodec \
--enable-nvdec \ --enable-nvdec \
--enable-cuvid \ --enable-cuvid \
--enable-protocol=file \ --enable-protocol=file \
--enable-hwaccel=av1_vaapi \
--enable-hwaccel=av1_nvdec \ --enable-hwaccel=av1_nvdec \
--enable-hwaccel=h264_vaapi \
--enable-hwaccel=h264_vdpau \
--enable-hwaccel=h264_nvdec \ --enable-hwaccel=h264_nvdec \
--enable-hwaccel=hevc_vaapi \
--enable-hwaccel=hevc_vdpau \
--enable-hwaccel=hevc_nvdec \ --enable-hwaccel=hevc_nvdec \
--enable-hwaccel=mpeg2_vaapi \
--enable-hwaccel=mpeg2_vdpau \
--enable-hwaccel=mpeg2_nvdec \ --enable-hwaccel=mpeg2_nvdec \
--enable-hwaccel=mpeg4_vaapi \
--enable-hwaccel=mpeg4_vdpau \
--enable-hwaccel=mpeg4_nvdec \ --enable-hwaccel=mpeg4_nvdec \
--enable-hwaccel=vp8_vaapi \
--enable-hwaccel=vp8_nvdec \ --enable-hwaccel=vp8_nvdec \
--enable-decoder=aac \ --enable-decoder=aac \
--enable-decoder=aac_fixed \ --enable-decoder=aac_fixed \
@ -839,6 +866,7 @@ COPY --link --from=xcb-render-util {{ LibrariesPath }}/xcb-render-util-cache /
COPY --link --from=xcb-cursor {{ LibrariesPath }}/xcb-cursor-cache / COPY --link --from=xcb-cursor {{ LibrariesPath }}/xcb-cursor-cache /
COPY --link --from=libXext {{ LibrariesPath }}/libXext-cache / COPY --link --from=libXext {{ LibrariesPath }}/libXext-cache /
COPY --link --from=libXfixes {{ LibrariesPath }}/libXfixes-cache / COPY --link --from=libXfixes {{ LibrariesPath }}/libXfixes-cache /
COPY --link --from=libXv {{ LibrariesPath }}/libXv-cache /
COPY --link --from=libXtst {{ LibrariesPath }}/libXtst-cache / COPY --link --from=libXtst {{ LibrariesPath }}/libXtst-cache /
COPY --link --from=libXrandr {{ LibrariesPath }}/libXrandr-cache / COPY --link --from=libXrandr {{ LibrariesPath }}/libXrandr-cache /
COPY --link --from=libXrender {{ LibrariesPath }}/libXrender-cache / COPY --link --from=libXrender {{ LibrariesPath }}/libXrender-cache /

View file

@ -6,5 +6,6 @@ popd > /dev/null
cd $FullScriptPath/../docker/centos_env cd $FullScriptPath/../docker/centos_env
poetry install
poetry run gen_dockerfile | DOCKER_BUILDKIT=1 docker build -t tdesktop:centos_env - poetry run gen_dockerfile | DOCKER_BUILDKIT=1 docker build -t tdesktop:centos_env -
cd $FullExecPath cd $FullExecPath

View file

@ -1210,7 +1210,7 @@ stage('tg_angle', """
win: win:
git clone https://github.com/desktop-app/tg_angle.git git clone https://github.com/desktop-app/tg_angle.git
cd tg_angle cd tg_angle
git checkout 0bb011f9e4 git checkout e3f59e8d0c
mkdir out mkdir out
cd out cd out
mkdir Debug mkdir Debug

View file

@ -1,7 +1,7 @@
AppVersion 4008010 AppVersion 4008011
AppVersionStrMajor 4.8 AppVersionStrMajor 4.8
AppVersionStrSmall 4.8.10 AppVersionStrSmall 4.8.11
AppVersionStr 4.8.10 AppVersionStr 4.8.11
BetaChannel 0 BetaChannel 1
AlphaVersion 0 AlphaVersion 0
AppVersionOriginal 4.8.10 AppVersionOriginal 4.8.11.beta

@ -1 +1 @@
Subproject commit 5a11029c461416407a423ac9921356fba0088ab6 Subproject commit 2d03abc7de8558ae8862688a226b3d5a817dc466

@ -1 +1 @@
Subproject commit efd052594db9f3d85a2fbcba76db6fdecf226597 Subproject commit e497dc134de3f8e2933ee0acdbba8bd702ce2130

@ -1 +1 @@
Subproject commit ebb8b8b91fe357b2c397a3eb98655c585b8c856e Subproject commit 5850566934f2f6cae56646c36cb95f85c8a9c752

View file

@ -1,3 +1,9 @@
4.8.11 beta (10.08.23)
- Fix initial video playback speed.
- Use native window resize on Windows 11.
- Fix memory leak in Direct3D 11 media viewer on Windows.
4.8.10 (28.07.23) 4.8.10 (28.07.23)
- Send story sharing comments as separate messages. - Send story sharing comments as separate messages.

2
cmake

@ -1 +1 @@
Subproject commit 0620bb7b87a0ec9195151fd5eb0cf38656c1280b Subproject commit ae0986c9efd28c61783cfe106f8bd1b0ba3b3920

View file

@ -1,23 +1,23 @@
## Build instructions for Linux using Docker ## Build instructions for Linux using Docker
### Prepare folder
Choose a folder for the future build, for example **/home/user/TBuild**. It will be named ***BuildPath*** in the rest of this document. All commands will be launched from Terminal.
### Obtain your API credentials ### Obtain your API credentials
You will require **api_id** and **api_hash** to access the Telegram API servers. To learn how to obtain them [click here][api_credentials]. You will require **api_id** and **api_hash** to access the Telegram API servers. To learn how to obtain them [click here][api_credentials].
### Clone source code ### Clone source code and prepare libraries
Install [poetry](https://python-poetry.org), go to ***BuildPath*** and run
git clone --recursive https://github.com/telegramdesktop/tdesktop.git git clone --recursive https://github.com/telegramdesktop/tdesktop.git
./tdesktop/Telegram/build/prepare/linux.sh
### Prepare libraries
Install [poetry](https://python-poetry.org), go to the `tdesktop/Telegram/build/docker/centos_env` directory and run
poetry install
poetry run gen_dockerfile | DOCKER_BUILDKIT=1 docker build -t tdesktop:centos_env -
### Building the project ### Building the project
Go up to the `tdesktop` directory and run (using [your **api_id** and **api_hash**](#obtain-your-api-credentials)) Go to ***BuildPath*/tdesktop** and run (using [your **api_id** and **api_hash**](#obtain-your-api-credentials))
docker run --rm -it \ docker run --rm -it \
-v $PWD:/usr/src/tdesktop \ -v $PWD:/usr/src/tdesktop \