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)
desktop_app_parse_version(Telegram/build/version)
set(project_langs C CXX)
set(project_langs ASM C CXX)
if (APPLE)
set(project_langs C CXX OBJC OBJCXX)
list(APPEND project_langs OBJC OBJCXX)
endif()
project(Telegram
@ -43,9 +43,10 @@ endif()
include(cmake/variables.cmake)
include(cmake/nice_target_sources.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_static_libraries.cmake)
include(cmake/target_link_frameworks.cmake)
include(cmake/init_target.cmake)
include(cmake/generate_target.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_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_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#other" = "You can increase this limit to **{count}** by upgrading to **Telegram Premium**.";

View file

@ -10,7 +10,7 @@
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
ProcessorArchitecture="ARCHITECTURE"
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
Version="4.8.10.0" />
Version="4.8.11.0" />
<Properties>
<DisplayName>Telegram Desktop</DisplayName>
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>

View file

@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,8,10,0
PRODUCTVERSION 4,8,10,0
FILEVERSION 4,8,11,0
PRODUCTVERSION 4,8,11,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -62,10 +62,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop"
VALUE "FileVersion", "4.8.10.0"
VALUE "FileVersion", "4.8.11.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "4.8.10.0"
VALUE "ProductVersion", "4.8.11.0"
END
END
BLOCK "VarFileInfo"

View file

@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,8,10,0
PRODUCTVERSION 4,8,10,0
FILEVERSION 4,8,11,0
PRODUCTVERSION 4,8,11,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -53,10 +53,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Radolyn Labs"
VALUE "FileDescription", "AyuGram Desktop Updater"
VALUE "FileVersion", "4.8.10.0"
VALUE "FileVersion", "4.8.11.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
VALUE "ProductName", "AyuGram Desktop"
VALUE "ProductVersion", "4.8.10.0"
VALUE "ProductVersion", "4.8.11.0"
END
END
BLOCK "VarFileInfo"

View file

@ -510,7 +510,7 @@ void ShowImportError(
if (error == u"CHANNELS_TOO_MUCH"_q) {
window->show(Box(ChannelsLimitBox, session));
} 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) {
window->show(Box(ShareableFiltersLimitBox, session));
} else {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -336,14 +336,18 @@ void EditExceptions(
Fn<void()> refresh) {
const auto include = (options & Flag::Contacts) != Flags(0);
const auto rules = data->current();
const auto session = &window->session();
auto controller = std::make_unique<EditFilterChatsListController>(
&window->session(),
session,
(include
? tr::lng_filters_include_title()
: tr::lng_filters_exclude_title()),
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();
auto initBox = [=](not_null<PeerListBox*> box) {
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 "data/data_premium_limits.h"
#include "history/history.h"
#include "window/window_session_controller.h"
#include "boxes/premium_limits_box.h"
#include "lang/lang_keys.h"
#include "ui/widgets/labels.h"
#include "ui/wrap/vertical_layout.h"
@ -99,22 +99,6 @@ private:
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)) {
}
@ -338,15 +322,18 @@ EditFilterChatsListController::EditFilterChatsListController(
rpl::producer<QString> title,
Flags options,
Flags selected,
const base::flat_set<not_null<History*>> &peers)
const base::flat_set<not_null<History*>> &peers,
LimitBoxFactory limitBox)
: ChatsListBoxController(session)
, _session(session)
, _limitBox(std::move(limitBox))
, _title(std::move(title))
, _peers(peers)
, _options(options & ~Flag::Chatlist)
, _selected(selected)
, _limit(Limit(session))
, _limit(Data::PremiumLimits(session).dialogFiltersChatsCurrent())
, _chatlist(options & Flag::Chatlist) {
Expects(_limitBox != nullptr);
}
Main::Session &EditFilterChatsListController::session() const {
@ -375,8 +362,7 @@ void EditFilterChatsListController::rowClicked(not_null<PeerListRow*> row) {
delegate()->peerListSetRowChecked(row, !row->checked());
updateTitle();
} else {
delegate()->peerListShowBox(
Box(FilterChatsLimitBox, _session, count));
delegate()->peerListShowBox(_limitBox(count));
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -313,10 +313,26 @@ stickersUndoRemove: RoundButton(defaultLightButton) {
}
stickersRemoveSkip: 4px;
stickersReorderIcon: icon {{ "stickers_reorder", menuIconFg }};
stickersReorderSkip: 13px;
stickersReorderSkip: 18px;
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;
stickersFeaturedBadgeFont: font(12px bold);
@ -351,11 +367,7 @@ filtersRemove: IconButton(stickersRemove) {
emojiPanMargins: margins(10px, 10px, 10px, 10px);
emojiTabs: SettingsSlider(defaultTabsSlider) {
height: 43px;
barTop: 40px;
labelTop: 12px;
}
emojiTabs: defaultTabsSlider;
emojiCategoryIconTop: 6px;
emojiPanAnimation: PanelAnimation(defaultPanelAnimation) {
@ -508,6 +520,7 @@ sendBoxAlbumGroupSkipRight: 5px;
sendBoxAlbumGroupSkipTop: 5px;
sendBoxAlbumGroupRadius: 4px;
sendBoxAlbumGroupSize: size(62px, 25px);
sendBoxAlbumGroupSizeVertical: size(30px, 50px);
sendBoxAlbumSmallGroupSize: size(30px, 25px);
sendBoxFileGroupSkipTop: 2px;

View file

@ -123,7 +123,7 @@ void SetCrashAnnotationsGL() {
case Ui::GL::ANGLE::D3D11: return "Direct3D 11";
case Ui::GL::ANGLE::D3D9: return "Direct3D 9";
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.");
}());

View file

@ -125,7 +125,15 @@ std::map<int, const char*> BetaLogs() {
"- Fix several possible crashes.\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 AppName = "AyuGram Desktop"_cs;
constexpr auto AppFile = "AyuGram"_cs;
constexpr auto AppVersion = 4008010;
constexpr auto AppVersionStr = "4.8.10";
constexpr auto AppBetaVersion = false;
constexpr auto AppVersion = 4008011;
constexpr auto AppVersionStr = "4.8.11";
constexpr auto AppBetaVersion = true;
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;

View file

@ -467,16 +467,17 @@ HistoryItem *ScheduledMessages::append(
// probably this message was edited.
if (data.is_edit_hide()) {
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);
history->owner().requestItemTextRefresh(existing);
}, [&](const auto &data) {});

View file

@ -18,6 +18,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
extern "C" {
#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"
namespace FFmpeg {
@ -85,6 +88,47 @@ void PremultiplyLine(uchar *dst, const uchar *src, int intsCount) {
#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) {
AVCodecContext *parent = static_cast<AVCodecContext*>(context->opaque);
@ -125,6 +169,9 @@ void PremultiplyLine(uchar *dst, const uchar *src, int intsCount) {
}
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{
#ifdef Q_OS_WIN
AV_PIX_FMT_D3D11,
@ -138,6 +185,7 @@ void PremultiplyLine(uchar *dst, const uchar *src, int intsCount) {
AV_PIX_FMT_CUDA,
#endif // Q_OS_WIN || Q_OS_MAC
};
#endif // DESKTOP_APP_USE_PACKAGED || Q_OS_WIN || Q_OS_MAC
for (const auto format : list) {
if (!has(format)) {
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) {
_flags |= MessageFlag::HideEdited;
} else {
@ -1488,8 +1494,14 @@ void HistoryItem::applyEdition(HistoryMessageEdition &&edition) {
setReplyMarkup(base::take(edition.replyMarkup));
}
if (!isLocalUpdateMedia()) {
removeFromSharedMediaIndex();
refreshMedia(edition.mtpMedia);
if (updatingSavedLocalEdit) {
_savedLocalEditMediaData->media = edition.mtpMedia
? CreateMedia(this, *edition.mtpMedia)
: nullptr;
} else {
removeFromSharedMediaIndex();
refreshMedia(edition.mtpMedia);
}
}
if (!edition.useSameReactions) {
updateReactions(edition.mtpReactions);
@ -1500,10 +1512,18 @@ void HistoryItem::applyEdition(HistoryMessageEdition &&edition) {
if (!edition.useSameForwards) {
setForwardsCount(edition.forwards);
}
setText(_media
const auto &checkedMedia = updatingSavedLocalEdit
? _savedLocalEditMediaData->media
: _media;
auto updatedText = checkedMedia
? edition.textWithEntities
: EnsureNonEmpty(edition.textWithEntities));
if (!isLocalUpdateMedia()) {
: EnsureNonEmpty(edition.textWithEntities);
if (updatingSavedLocalEdit) {
_savedLocalEditMediaData->text = std::move(updatedText);
} else {
setText(std::move(updatedText));
}
if (!isLocalUpdateMedia() && !updatingSavedLocalEdit) {
indexAsNewItem();
}
if (!edition.useSameReplies) {
@ -1652,6 +1672,9 @@ void HistoryItem::applySentMessage(
void HistoryItem::updateSentContent(
const TextWithEntities &textWithEntities,
const MTPMessageMedia *media) {
if (_savedLocalEditMediaData) {
return;
}
setText(textWithEntities);
if (_flags & MessageFlag::FromInlineBot) {
if (!media || !_media || !_media->updateInlineResultMedia(*media)) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -17,79 +17,168 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtCore/QAbstractEventDispatcher>
#include <glibmm.h>
#include <gio/gio.hpp>
#include <xdpinhibit/xdpinhibit.hpp>
#include <giomm.h>
typedef GApplication TDesktopApplication;
typedef GApplicationClass TDesktopApplicationClass;
namespace Platform {
namespace {
G_DEFINE_TYPE(
TDesktopApplication,
t_desktop_application,
G_TYPE_APPLICATION)
using namespace gi::repository;
static void t_desktop_application_class_init(
TDesktopApplicationClass *klass) {
const auto application_class = G_APPLICATION_CLASS(klass);
class Application : public Gio::impl::ApplicationImpl {
public:
Application();
application_class->local_command_line = [](
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) {
void before_emit_(GLib::Variant platformData) noexcept override {
if (Platform::IsWayland()) {
static const auto keys = {
"activation-token",
"desktop-startup-id",
};
for (const auto &key : keys) {
const char *token = nullptr;
g_variant_lookup(platformData, key, "&s", &token);
if (token) {
qputenv("XDG_ACTIVATION_TOKEN", token);
if (auto token = platformData.lookup_value(key)) {
qputenv(
"XDG_ACTIVATION_TOKEN",
token.get_string(nullptr).c_str());
break;
}
}
}
};
}
application_class->add_platform_data = [](
GApplication *application,
GVariantBuilder *builder) {
void activate_() noexcept override {
Core::Sandbox::Instance().customEnterFromEventLoop([] {
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()) {
const auto token = qgetenv("XDG_ACTIVATION_TOKEN");
if (!token.isEmpty()) {
g_variant_builder_add(
builder,
"{sv}",
"activation-token",
g_variant_new_string(token.constData()));
builder.add_value(
GLib::Variant::new_dict_entry(
GLib::Variant::new_string("activation-token"),
GLib::Variant::new_variant(
GLib::Variant::new_string(token.toStdString()))));
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 {
public:
LinuxIntegration();
@ -103,14 +192,14 @@ private:
void initInhibit();
static void LaunchNativeApplication();
const gi::ref_ptr<Application> _application;
XdpInhibit::InhibitProxy _inhibitProxy;
base::Platform::XDP::SettingWatcher _darkModeWatcher;
};
LinuxIntegration::LinuxIntegration()
: _inhibitProxy(
: _application(MakeApplication())
, _inhibitProxy(
XdpInhibit::InhibitProxy::new_for_bus_sync(
Gio::BusType::SESSION_,
Gio::DBusProxyFlags::DO_NOT_AUTO_START_AT_CONSTRUCTION_,
@ -139,16 +228,12 @@ LinuxIntegration::LinuxIntegration()
if (!QCoreApplication::eventDispatcher()->inherits(
"QEventDispatcherGlib")) {
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() {
initInhibit();
Glib::signal_idle().connect_once([] {
LaunchNativeApplication();
});
}
void LinuxIntegration::initInhibit() {
@ -156,7 +241,11 @@ void LinuxIntegration::initInhibit() {
return;
}
auto uniqueName = _inhibitProxy.get_connection().get_unique_name();
auto uniqueName = _inhibitProxy
.get_connection()
.get_unique_name()
.value_or("");
uniqueName.erase(0, 1);
uniqueName.replace(uniqueName.find('.'), 1, 1, '_');
@ -207,115 +296,6 @@ void LinuxIntegration::initInhibit() {
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
std::unique_ptr<Integration> CreateIntegration() {

View file

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

View file

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

View file

@ -238,7 +238,6 @@ MainWindow::MainWindow(not_null<Window::Controller*> controller)
: Window::MainWindow(controller)
, _private(std::make_unique<Private>(this))
, psMainMenu(this) {
auto forceOpenGL = std::make_unique<QOpenGLWidget>(this);
_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_d3d9(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),
};
const auto backendIndex = [] {
const auto disabled = int(options.size()) - 1;
const auto backendIndex = [=] {
if (Core::App().settings().disableOpenGL()) {
return 5;
return disabled;
} else switch (Ui::GL::CurrentANGLE()) {
case ANGLE::Auto: return 0;
case ANGLE::D3D11: return 1;
case ANGLE::D3D9: return 2;
case ANGLE::D3D11on12: return 3;
case ANGLE::OpenGL: return 4;
//case ANGLE::OpenGL: return 4;
}
Unexpected("Ui::GL::CurrentANGLE value in SetupANGLE.");
}();
@ -764,7 +765,7 @@ void SetupANGLE(
return;
}
const auto confirmed = crl::guard(button, [=] {
const auto nowDisabled = (index == 5);
const auto nowDisabled = (index == disabled);
if (!nowDisabled) {
Ui::GL::ChangeANGLE([&] {
switch (index) {
@ -772,12 +773,12 @@ void SetupANGLE(
case 1: return ANGLE::D3D11;
case 2: return ANGLE::D3D9;
case 3: return ANGLE::D3D11on12;
case 4: return ANGLE::OpenGL;
//case 4: return ANGLE::OpenGL;
}
Unexpected("Index in SetupANGLE.");
}());
}
const auto wasDisabled = (backendIndex == 5);
const auto wasDisabled = (backendIndex == disabled);
if (nowDisabled != wasDisabled) {
Core::App().settings().setDisableOpenGL(nowDisabled);
Local::writeSettings();

View file

@ -526,7 +526,7 @@ FileLoadTask::FileLoadTask(
FileLoadTask::FileLoadTask(
not_null<Main::Session*> session,
const QByteArray &voice,
int32 duration,
crl::time duration,
const VoiceWaveform &waveform,
const FileLoadTo &to,
const TextWithTags &caption)
@ -852,8 +852,9 @@ void FileLoadTask::process(Args &&args) {
if (auto song = std::get_if<Ui::PreparedFileInformation::Song>(
&_information->media)) {
isSong = true;
const auto seconds = song->duration / 1000;
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));
} else if (auto video = std::get_if<Ui::PreparedFileInformation::Video>(
&_information->media)) {
@ -867,9 +868,10 @@ void FileLoadTask::process(Args &&args) {
if (video->supportsStreaming) {
flags |= MTPDdocumentAttributeVideo::Flag::f_supports_streaming;
}
const auto realSeconds = video->duration / 1000.;
attributes.push_back(MTP_documentAttributeVideo(
MTP_flags(flags),
MTP_double(video->duration / 1000.),
MTP_double(realSeconds),
MTP_int(coverWidth),
MTP_int(coverHeight),
MTPint())); // preload_prefix_size
@ -971,8 +973,9 @@ void FileLoadTask::process(Args &&args) {
}
if (isVoice) {
const auto seconds = _duration / 1000;
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);
document = MTP_document(
MTP_flags(0),

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -523,7 +523,7 @@ historyFastShareSize: 31px;
historyFastShareLeft: 13px;
historyFastShareBottom: 5px;
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 }};
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);
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);
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) {
@ -62,11 +68,12 @@ void SilentToggle::mouseMoveEvent(QMouseEvent *e) {
void SilentToggle::setChecked(bool checked) {
if (_checked != checked) {
_checked = checked;
_crossLineAnimation.start(
[=] { update(); },
_checked ? 0. : 1.,
_checked ? 1. : 0.,
kAnimationDuration);
update();
// _crossLineAnimation.start(
// [=] { update(); },
// _checked ? 0. : 1.,
// _checked ? 1. : 0.,
// kAnimationDuration);
}
}
@ -75,13 +82,6 @@ void SilentToggle::leaveEventHook(QEvent *e) {
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 {
return _checked
? tr::lng_wont_be_notified(tr::now)

View file

@ -29,8 +29,8 @@ public:
bool tooltipWindowActive() const override;
protected:
void paintEvent(QPaintEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void leaveEventHook(QEvent *e) override;
QImage prepareRippleMask() const override;
@ -42,7 +42,7 @@ private:
not_null<ChannelData*> _channel;
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 {
DiscreteSlider::DiscreteSlider(QWidget *parent) : RpWidget(parent) {
DiscreteSlider::DiscreteSlider(QWidget *parent, bool snapToLabel)
: RpWidget(parent)
, _snapToLabel(snapToLabel) {
setCursor(style::cur_pointer);
}
@ -80,9 +82,23 @@ void DiscreteSlider::setSections(const std::vector<QString> &labels) {
resizeToWidth(width());
}
int DiscreteSlider::getCurrentActiveLeft() {
const auto left = _sections.empty() ? 0 : _sections[_selected].left;
return _a_left.value(left);
DiscreteSlider::Range DiscreteSlider::getFinalActiveRange() const {
const auto raw = _sections.empty() ? nullptr : &_sections[_selected];
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>
@ -138,11 +154,13 @@ void DiscreteSlider::setSelectedSection(int index) {
if (index < 0 || index >= _sections.size()) return;
if (_selected != index) {
auto from = _sections[_selected].left;
const auto from = getFinalActiveRange();
_selected = index;
auto to = _sections[_selected].left;
auto duration = getAnimationDuration();
_a_left.start([this] { update(); }, from, to, duration);
const auto to = getFinalActiveRange();
const auto duration = getAnimationDuration();
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;
}
}
@ -166,7 +184,7 @@ DiscreteSlider::Section::Section(
SettingsSlider::SettingsSlider(
QWidget *parent,
const style::SettingsSlider &st)
: DiscreteSlider(parent)
: DiscreteSlider(parent, st.barSnapToLabel)
, _st(st) {
if (_st.barRadius > 0) {
_bar.emplace(_st.barRadius, _st.barFg);
@ -299,7 +317,7 @@ void SettingsSlider::paintEvent(QPaintEvent *e) {
Painter p(this);
auto clip = e->rect();
auto activeLeft = getCurrentActiveLeft();
auto range = getCurrentActiveRange();
const auto drawRect = [&](QRect rect, bool active = false) {
const auto &bar = active ? _barActive : _bar;
@ -310,9 +328,14 @@ void SettingsSlider::paintEvent(QPaintEvent *e) {
}
};
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.
- std::clamp(
qAbs(activeLeft - section.left) / float64(section.width),
qAbs(range.left - activeLeft) / float64(section.width),
0.,
1.);
if (section.ripple) {
@ -322,36 +345,47 @@ void SettingsSlider::paintEvent(QPaintEvent *e) {
section.ripple.reset();
}
}
auto from = section.left, tofill = section.width;
if (activeLeft > from) {
auto fill = qMin(tofill, activeLeft - from);
drawRect(myrtlrect(from, _st.barTop, fill, _st.barStroke));
from += fill;
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);
if (!_st.barSnapToLabel) {
auto from = activeLeft, tofill = activeWidth;
if (range.left > from) {
auto fill = qMin(tofill, range.left - from);
drawRect(myrtlrect(from, _st.barTop, fill, _st.barStroke));
from += 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) {
drawRect(myrtlrect(from, _st.barTop, tofill, _st.barStroke));
}
if (myrtlrect(section.left, _st.labelTop, section.width, _st.labelStyle.font->height).intersects(clip)) {
const auto labelLeft = section.left + (section.width - section.label.maxWidth()) / 2;
if (myrtlrect(labelLeft, _st.labelTop, section.label.maxWidth(), _st.labelStyle.font->height).intersects(clip)) {
p.setPen(anim::pen(_st.labelFg, _st.labelFgActive, active));
section.label.drawLeft(
p,
section.left + (section.width - section.label.maxWidth()) / 2,
labelLeft,
_st.labelTop,
section.label.maxWidth(),
width());
}
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

View file

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

View file

@ -40,9 +40,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtGui/QWindow>
#if __has_include(<giomm.h>)
#include <giomm.h>
#endif // __has_include(<giomm.h>)
#if __has_include(<gio/gio.hpp>)
#include <gio/gio.hpp>
#endif // __has_include(<gio/gio.hpp>)
namespace Window {
namespace Notifications {
@ -90,11 +90,12 @@ base::options::toggle OptionGNotification({
.description = "Force enable GLib's GNotification."
" When disabled, autodetect is used.",
.scope = [] {
#if __has_include(<giomm.h>)
#if __has_include(<gio/gio.hpp>)
using namespace gi::repository;
return bool(Gio::Application::get_default());
#else // __has_include(<giomm.h>)
#else // __has_include(<gio/gio.hpp>)
return false;
#endif // __has_include(<giomm.h>)
#endif // __has_include(<gio/gio.hpp>)
},
.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 \
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 \
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 \
devtoolset-10-make devtoolset-10-gcc devtoolset-10-gcc-c++ \
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 .. \
&& 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
RUN git clone -b libXrandr-1.5.2 --depth=1 {{ GIT_FREEDESKTOP }}/libxrandr.git \
&& cd libxrandr \
@ -482,6 +493,8 @@ FROM builder AS ffmpeg
COPY --link --from=opus {{ LibrariesPath }}/opus-cache /
COPY --link --from=dav1d {{ LibrariesPath }}/dav1d-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 /
RUN git init ffmpeg \
@ -503,15 +516,29 @@ RUN git init ffmpeg \
--enable-libdav1d \
--enable-libopus \
--enable-libvpx \
--enable-vaapi \
--enable-vdpau \
--enable-xlib \
--enable-libdrm \
--enable-ffnvcodec \
--enable-nvdec \
--enable-cuvid \
--enable-protocol=file \
--enable-hwaccel=av1_vaapi \
--enable-hwaccel=av1_nvdec \
--enable-hwaccel=h264_vaapi \
--enable-hwaccel=h264_vdpau \
--enable-hwaccel=h264_nvdec \
--enable-hwaccel=hevc_vaapi \
--enable-hwaccel=hevc_vdpau \
--enable-hwaccel=hevc_nvdec \
--enable-hwaccel=mpeg2_vaapi \
--enable-hwaccel=mpeg2_vdpau \
--enable-hwaccel=mpeg2_nvdec \
--enable-hwaccel=mpeg4_vaapi \
--enable-hwaccel=mpeg4_vdpau \
--enable-hwaccel=mpeg4_nvdec \
--enable-hwaccel=vp8_vaapi \
--enable-hwaccel=vp8_nvdec \
--enable-decoder=aac \
--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=libXext {{ LibrariesPath }}/libXext-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=libXrandr {{ LibrariesPath }}/libXrandr-cache /
COPY --link --from=libXrender {{ LibrariesPath }}/libXrender-cache /

View file

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

View file

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

View file

@ -1,7 +1,7 @@
AppVersion 4008010
AppVersion 4008011
AppVersionStrMajor 4.8
AppVersionStrSmall 4.8.10
AppVersionStr 4.8.10
BetaChannel 0
AppVersionStrSmall 4.8.11
AppVersionStr 4.8.11
BetaChannel 1
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)
- 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
### 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
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
### 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 -
./tdesktop/Telegram/build/prepare/linux.sh
### 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 \
-v $PWD:/usr/src/tdesktop \