mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-14 13:17:08 +02:00
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:
commit
e5ff26b2eb
70 changed files with 701 additions and 483 deletions
|
@ -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)
|
||||
|
|
|
@ -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**.";
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -302,7 +302,7 @@ public:
|
|||
void sendVoiceMessage(
|
||||
QByteArray result,
|
||||
VoiceWaveform waveform,
|
||||
int duration,
|
||||
crl::time duration,
|
||||
const SendAction &action);
|
||||
void sendFiles(
|
||||
Ui::PreparedList &&list,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -164,7 +164,8 @@ void FillChooseFilterMenu(
|
|||
controller->show(Box(
|
||||
FilterChatsLimitBox,
|
||||
&controller->session(),
|
||||
r.count));
|
||||
r.count,
|
||||
true));
|
||||
} else if (validator.canAdd()) {
|
||||
validator.add(id);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.");
|
||||
}());
|
||||
|
|
|
@ -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"
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {});
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -29,6 +29,7 @@ struct HistoryMessageEdition {
|
|||
bool useSameReplies = false;
|
||||
bool useSameMarkup = false;
|
||||
bool useSameReactions = false;
|
||||
bool savePreviousMedia = false;
|
||||
TextWithEntities textWithEntities;
|
||||
HistoryMessageMarkupData replyMarkup;
|
||||
HistoryMessageRepliesData replies;
|
||||
|
|
|
@ -25,7 +25,7 @@ struct MessageToEdit {
|
|||
struct VoiceToSend {
|
||||
QByteArray bytes;
|
||||
VoiceWaveform waveform;
|
||||
int duration = 0;
|
||||
crl::time duration = 0;
|
||||
Api::SendOptions options;
|
||||
};
|
||||
struct SendActionUpdate {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -15,7 +15,6 @@ enum class SharedMediaType : signed char;
|
|||
} // namespace Storage
|
||||
|
||||
namespace Ui {
|
||||
class SettingsSlider;
|
||||
class FadeShadow;
|
||||
class PlainShadow;
|
||||
class PopupMenu;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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 ¶meter) {
|
||||
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 ¶meter) {
|
||||
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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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(); });
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ struct PreparedFileInformation {
|
|||
Editor::PhotoModifications modifications;
|
||||
};
|
||||
struct Song {
|
||||
int duration = -1;
|
||||
crl::time duration = -1;
|
||||
QString title;
|
||||
QString performer;
|
||||
QImage cover;
|
||||
|
|
|
@ -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 }};
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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 §ion) {
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
|
|
@ -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 /
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
2
cmake
|
@ -1 +1 @@
|
|||
Subproject commit 0620bb7b87a0ec9195151fd5eb0cf38656c1280b
|
||||
Subproject commit ae0986c9efd28c61783cfe106f8bd1b0ba3b3920
|
|
@ -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 \
|
||||
|
|
Loading…
Add table
Reference in a new issue