Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4247fd0c0f | ||
|
|
50f2e93623 | ||
|
|
fbfa6966f4 | ||
|
|
42eb452de8 | ||
|
|
9b3692ca22 | ||
|
|
7463aad755 | ||
|
|
9cf419999d | ||
|
|
7557a20679 | ||
|
|
91e6c42fcf | ||
|
|
3573b84e8b | ||
|
|
bb900c195c | ||
|
|
e61c058eb5 | ||
|
|
b48dee0af7 | ||
|
|
6b6afd38ac | ||
|
|
98e8a20f5f | ||
|
|
aeeb9fe761 | ||
|
|
c65b45460b | ||
|
|
1940edd6ee | ||
|
|
96ef82272b | ||
|
|
29d93d348c | ||
|
|
879df6e6a3 | ||
|
|
9d3715a36a | ||
|
|
1cb0d7c2dc | ||
|
|
1da635a5dd | ||
|
|
d0c2bec925 | ||
|
|
13a9920c11 | ||
|
|
0b100884fc | ||
|
|
6e89d41d58 | ||
|
|
20f946f657 | ||
|
|
9e49e32702 | ||
|
|
6834cdb969 | ||
|
|
36bf54b0d1 | ||
|
|
8f908ab9c0 | ||
|
|
cbd9dd0c2c | ||
|
|
a8decf154f | ||
|
|
f2ed77649e | ||
|
|
369862a3a7 | ||
|
|
e6b24a49f6 | ||
|
|
08644a9c31 | ||
|
|
9090b8ce6b | ||
|
|
646bb2ff71 |
5
.github/workflows/mac.yml
vendored
5
.github/workflows/mac.yml
vendored
@@ -64,7 +64,7 @@ jobs:
|
||||
- name: First set up.
|
||||
run: |
|
||||
sudo chown -R `whoami`:admin /usr/local/share
|
||||
brew install automake
|
||||
brew install automake ninja
|
||||
|
||||
# Disable spotlight.
|
||||
sudo mdutil -a -i off
|
||||
@@ -113,13 +113,14 @@ jobs:
|
||||
./configure.sh \
|
||||
-D CMAKE_C_FLAGS="-Werror" \
|
||||
-D CMAKE_CXX_FLAGS="-Werror" \
|
||||
-D CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=NO \
|
||||
-D TDESKTOP_API_TEST=ON \
|
||||
-D DESKTOP_APP_DISABLE_CRASH_REPORTS=OFF \
|
||||
$DEFINE
|
||||
|
||||
cd ../out
|
||||
|
||||
xcoderun='xcodebuild build -project Telegram.xcodeproj -scheme Telegram -destination "platform=macOS,arch=x86_64" -configuration Debug CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO'
|
||||
xcoderun='xcodebuild build -project Telegram.xcodeproj -scheme Telegram -destination "platform=macOS,arch=x86_64" -configuration Debug'
|
||||
bash -c "$xcoderun" || bash -c "$xcoderun" || bash -c "$xcoderun"
|
||||
|
||||
- name: Move artifact.
|
||||
|
||||
BIN
Telegram/Resources/icons/emoji_empty.png
Normal file
BIN
Telegram/Resources/icons/emoji_empty.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
BIN
Telegram/Resources/icons/emoji_empty@2x.png
Normal file
BIN
Telegram/Resources/icons/emoji_empty@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
BIN
Telegram/Resources/icons/emoji_empty@3x.png
Normal file
BIN
Telegram/Resources/icons/emoji_empty@3x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.3 KiB |
@@ -1877,6 +1877,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_masks_archive_pack" = "Archive Masks";
|
||||
"lng_masks_has_been_archived" = "Mask pack has been archived.";
|
||||
"lng_masks_installed" = "Mask pack has been installed.";
|
||||
"lng_emoji_nothing_found" = "No emoji found";
|
||||
|
||||
"lng_in_dlg_photo" = "Photo";
|
||||
"lng_in_dlg_album" = "Album";
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="4.6.2.0" />
|
||||
Version="4.6.3.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,6,2,0
|
||||
PRODUCTVERSION 4,6,2,0
|
||||
FILEVERSION 4,6,3,0
|
||||
PRODUCTVERSION 4,6,3,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -62,10 +62,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "4.6.2.0"
|
||||
VALUE "FileVersion", "4.6.3.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "4.6.2.0"
|
||||
VALUE "ProductVersion", "4.6.3.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 4,6,2,0
|
||||
PRODUCTVERSION 4,6,2,0
|
||||
FILEVERSION 4,6,3,0
|
||||
PRODUCTVERSION 4,6,3,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -53,10 +53,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop Updater"
|
||||
VALUE "FileVersion", "4.6.2.0"
|
||||
VALUE "FileVersion", "4.6.3.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2023"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "4.6.2.0"
|
||||
VALUE "ProductVersion", "4.6.3.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -26,7 +26,9 @@ void openLog() {
|
||||
return;
|
||||
}
|
||||
|
||||
NSDateFormatter *fmt = [[NSDateFormatter alloc] initWithDateFormat:@"DebugLogs/%Y%m%d_%H%M%S_upd.txt" allowNaturalLanguage:NO];
|
||||
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
|
||||
[fmt setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]];
|
||||
[fmt setDateFormat:@"'DebugLogs/'yyyyMMdd'_'HHmmss'_update.txt'"];
|
||||
NSString *logPath = [workDir stringByAppendingString:[fmt stringFromDate:[NSDate date]]];
|
||||
[[NSFileManager defaultManager] createFileAtPath:logPath contents:nil attributes:nil];
|
||||
_logFile = [NSFileHandle fileHandleForWritingAtPath:logPath];
|
||||
|
||||
@@ -140,6 +140,19 @@ void MustBePublicFailed(
|
||||
MustBePublicDestroy(channel);
|
||||
}
|
||||
|
||||
[[nodiscard]] Fn<void(not_null<PeerData*>)> WrapPeerDoneFromChannelDone(
|
||||
Fn<void(not_null<ChannelData*>)> channelDone) {
|
||||
if (!channelDone) {
|
||||
return nullptr;
|
||||
}
|
||||
return [=](not_null<PeerData*> peer) {
|
||||
if (const auto channel = peer->asChannel()) {
|
||||
const auto onstack = channelDone;
|
||||
onstack(channel);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TextWithEntities PeerFloodErrorText(
|
||||
@@ -482,13 +495,7 @@ GroupInfoBox::GroupInfoBox(
|
||||
, _api(&_navigation->session().mtp())
|
||||
, _type(type)
|
||||
, _initialTitle(title)
|
||||
, _done([channelDone = std::move(channelDone)](not_null<PeerData*> peer) {
|
||||
if (const auto channel = peer->asChannel()) {
|
||||
if (const auto onstack = channelDone) {
|
||||
onstack(channel);
|
||||
}
|
||||
}
|
||||
}) {
|
||||
, _done(WrapPeerDoneFromChannelDone(std::move(channelDone))) {
|
||||
}
|
||||
|
||||
GroupInfoBox::GroupInfoBox(
|
||||
|
||||
@@ -572,9 +572,6 @@ changePhoneError: FlatLabel(changePhoneLabel) {
|
||||
textFg: boxTextFgError;
|
||||
}
|
||||
|
||||
blockedUsersListSubtitleAddPadding: margins(0px, 1px, 0px, -14px);
|
||||
blockedUsersListIconPadding: margins(0px, 34px, 0px, 5px);
|
||||
|
||||
adminLogFilterUserpicLeft: 15px;
|
||||
adminLogFilterLittleSkip: 16px;
|
||||
adminLogFilterCheckbox: Checkbox(defaultBoxCheckbox) {
|
||||
|
||||
@@ -295,10 +295,11 @@ void AddParticipantsBoxController::Start(
|
||||
not_null<ChatData*> chat) {
|
||||
auto controller = std::make_unique<AddParticipantsBoxController>(chat);
|
||||
const auto weak = controller.get();
|
||||
const auto parent = navigation->parentController();
|
||||
auto initBox = [=](not_null<PeerListBox*> box) {
|
||||
box->addButton(tr::lng_participant_invite(), [=] {
|
||||
weak->inviteSelectedUsers(box, [=] {
|
||||
navigation->parentController()->showPeerHistory(
|
||||
parent->showPeerHistory(
|
||||
chat,
|
||||
Window::SectionShow::Way::ClearStack,
|
||||
ShowAtTheEndMsgId);
|
||||
@@ -320,11 +321,12 @@ void AddParticipantsBoxController::Start(
|
||||
channel,
|
||||
std::move(alreadyIn));
|
||||
const auto weak = controller.get();
|
||||
const auto parent = navigation->parentController();
|
||||
auto initBox = [=](not_null<PeerListBox*> box) {
|
||||
box->addButton(tr::lng_participant_invite(), [=] {
|
||||
weak->inviteSelectedUsers(box, [=] {
|
||||
if (channel->isMegagroup()) {
|
||||
navigation->parentController()->showPeerHistory(
|
||||
parent->showPeerHistory(
|
||||
channel,
|
||||
Window::SectionShow::Way::ClearStack,
|
||||
ShowAtTheEndMsgId);
|
||||
@@ -337,13 +339,16 @@ void AddParticipantsBoxController::Start(
|
||||
justCreated ? tr::lng_create_group_skip() : tr::lng_cancel(),
|
||||
[=] { box->closeBox(); });
|
||||
if (justCreated) {
|
||||
const auto weak = base::make_weak(parent);
|
||||
box->boxClosing() | rpl::start_with_next([=] {
|
||||
auto params = Window::SectionShow();
|
||||
params.activation = anim::activation::background;
|
||||
navigation->parentController()->showPeerHistory(
|
||||
channel,
|
||||
params,
|
||||
ShowAtTheEndMsgId);
|
||||
if (const auto strong = weak.get()) {
|
||||
strong->showPeerHistory(
|
||||
channel,
|
||||
params,
|
||||
ShowAtTheEndMsgId);
|
||||
}
|
||||
}, box->lifetime());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -79,7 +79,7 @@ struct NestedRestrictionLabels {
|
||||
second.erase(
|
||||
ranges::remove(
|
||||
second,
|
||||
Flag::CreateTopics,
|
||||
Flag::CreateTopics | Flag(),
|
||||
&RestrictionLabel::flags),
|
||||
end(second));
|
||||
}
|
||||
@@ -1002,7 +1002,7 @@ std::vector<AdminRightLabel> AdminRightLabels(
|
||||
result.erase(
|
||||
ranges::remove(
|
||||
result,
|
||||
Flag::ManageTopics,
|
||||
Flag::ManageTopics | Flag(),
|
||||
&AdminRightLabel::flags),
|
||||
end(result));
|
||||
}
|
||||
|
||||
@@ -854,7 +854,7 @@ void ShareBox::Inner::loadProfilePhotos(int yFrom) {
|
||||
if (((*i)->index() * _rowHeight) >= yTo) {
|
||||
break;
|
||||
}
|
||||
(*i)->entry()->loadUserpic();
|
||||
(*i)->entry()->chatListPreloadData();
|
||||
}
|
||||
}
|
||||
} else if (!_filtered.empty()) {
|
||||
@@ -865,7 +865,7 @@ void ShareBox::Inner::loadProfilePhotos(int yFrom) {
|
||||
if (to > _filtered.size()) to = _filtered.size();
|
||||
|
||||
for (; from < to; ++from) {
|
||||
_filtered[from]->entry()->loadUserpic();
|
||||
_filtered[from]->entry()->chatListPreloadData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,6 +335,7 @@ stickersToast: Toast(defaultToast) {
|
||||
}
|
||||
|
||||
stickersEmpty: icon {{ "stickers_empty", windowSubTextFg }};
|
||||
emojiEmpty: icon {{ "emoji_empty", windowSubTextFg }};
|
||||
|
||||
inlineBotsScroll: ScrollArea(defaultSolidScroll) {
|
||||
deltat: stickerPanPadding;
|
||||
@@ -396,7 +397,7 @@ reactStripBubble: icon{
|
||||
{ "chat/reactions_bubble", windowBg },
|
||||
};
|
||||
reactStripBubbleRight: 20px;
|
||||
reactPanelEmojiPan: EmojiPan(statusEmojiPan) {
|
||||
userpicBuilderEmojiPan: EmojiPan(statusEmojiPan) {
|
||||
margin: margins(reactStripSkip, 0px, reactStripSkip, 0px);
|
||||
padding: margins(reactStripSkip, 0px, reactStripSkip, reactStripSkip);
|
||||
desiredSize: reactStripSize;
|
||||
@@ -405,6 +406,8 @@ reactPanelEmojiPan: EmojiPan(statusEmojiPan) {
|
||||
search: TabbedSearch(defaultTabbedSearch) {
|
||||
defaultFieldWidth: 88px;
|
||||
}
|
||||
}
|
||||
reactPanelEmojiPan: EmojiPan(userpicBuilderEmojiPan) {
|
||||
searchMargin: margins(1px, 10px, 2px, 6px);
|
||||
}
|
||||
emojiScroll: ScrollArea(defaultSolidScroll) {
|
||||
|
||||
@@ -485,14 +485,21 @@ void EmojiListWidget::applyNextSearchQuery() {
|
||||
if (!_searchMode && !searching) {
|
||||
return;
|
||||
}
|
||||
_searchMode = searching;
|
||||
const auto modeChanged = (_searchMode != searching);
|
||||
clearSelection();
|
||||
if (modeChanged) {
|
||||
_searchMode = searching;
|
||||
}
|
||||
if (!searching) {
|
||||
_searchResults.clear();
|
||||
_searchCustomIds.clear();
|
||||
}
|
||||
clearSelection();
|
||||
resizeToWidth(width());
|
||||
update();
|
||||
if (modeChanged) {
|
||||
visibleTopBottomUpdated(getVisibleTop(), getVisibleBottom());
|
||||
}
|
||||
updateSelected();
|
||||
};
|
||||
if (_searchQuery.empty()) {
|
||||
finish(false);
|
||||
@@ -615,7 +622,7 @@ void EmojiListWidget::prepareExpanding() {
|
||||
}
|
||||
|
||||
void EmojiListWidget::paintExpanding(
|
||||
QPainter &p,
|
||||
Painter &p,
|
||||
QRect clip,
|
||||
int finalBottom,
|
||||
float64 progress,
|
||||
@@ -968,7 +975,7 @@ base::unique_qptr<Ui::PopupMenu> EmojiListWidget::fillContextMenu(
|
||||
}
|
||||
|
||||
void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
||||
auto p = QPainter(this);
|
||||
auto p = Painter(this);
|
||||
|
||||
const auto clip = e ? e->rect() : rect();
|
||||
|
||||
@@ -1012,7 +1019,7 @@ void EmojiListWidget::validateEmojiPaintContext(
|
||||
}
|
||||
|
||||
void EmojiListWidget::paint(
|
||||
QPainter &p,
|
||||
Painter &p,
|
||||
ExpandingContext context,
|
||||
QRect clip) {
|
||||
validateEmojiPaintContext(context);
|
||||
@@ -1036,6 +1043,9 @@ void EmojiListWidget::paint(
|
||||
auto selectedButton = std::get_if<OverButton>(!v::is_null(_pressed)
|
||||
? &_pressed
|
||||
: &_selected);
|
||||
if (_searchResults.empty() && _searchMode) {
|
||||
paintEmptySearchResults(p);
|
||||
}
|
||||
enumerateSections([&](const SectionInfo &info) {
|
||||
if (clip.top() >= info.rowsBottom) {
|
||||
return true;
|
||||
@@ -2001,6 +2011,13 @@ int EmojiListWidget::paintButtonGetWidth(
|
||||
return emojiRight() - rect.x();
|
||||
}
|
||||
|
||||
void EmojiListWidget::paintEmptySearchResults(Painter &p) {
|
||||
Inner::paintEmptySearchResults(
|
||||
p,
|
||||
st::emojiEmpty,
|
||||
tr::lng_emoji_nothing_found(tr::now));
|
||||
}
|
||||
|
||||
bool EmojiListWidget::eventHook(QEvent *e) {
|
||||
if (e->type() == QEvent::ParentChange) {
|
||||
if (_picker->parentWidget() != parentWidget()) {
|
||||
@@ -2190,10 +2207,13 @@ void EmojiListWidget::showSet(uint64 setId) {
|
||||
}
|
||||
|
||||
uint64 EmojiListWidget::sectionSetId(int section) const {
|
||||
Expects(section < _staticCount
|
||||
Expects(_searchMode
|
||||
|| section < _staticCount
|
||||
|| (section - _staticCount) < _custom.size());
|
||||
|
||||
return (section < _staticCount)
|
||||
return _searchMode
|
||||
? SearchEmojiSectionSetId()
|
||||
: (section < _staticCount)
|
||||
? EmojiSectionSetId(static_cast<Section>(section))
|
||||
: _custom[section - _staticCount].id;
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ public:
|
||||
|
||||
void prepareExpanding();
|
||||
void paintExpanding(
|
||||
QPainter &p,
|
||||
Painter &p,
|
||||
QRect clip,
|
||||
int finalBottom,
|
||||
float64 progress,
|
||||
@@ -271,7 +271,7 @@ private:
|
||||
Api::SendOptions options = Api::SendOptions());
|
||||
void selectEmoji(EmojiChosen data);
|
||||
void selectCustom(FileChosen data);
|
||||
void paint(QPainter &p, ExpandingContext context, QRect clip);
|
||||
void paint(Painter &p, ExpandingContext context, QRect clip);
|
||||
void drawCollapsedBadge(QPainter &p, QPoint position, int count);
|
||||
void drawRecent(
|
||||
QPainter &p,
|
||||
@@ -313,6 +313,7 @@ private:
|
||||
const SectionInfo &info,
|
||||
bool selected,
|
||||
QRect clip) const;
|
||||
void paintEmptySearchResults(Painter &p);
|
||||
|
||||
void displaySet(uint64 setId);
|
||||
void removeSet(uint64 setId);
|
||||
|
||||
@@ -161,6 +161,7 @@ object_ptr<TabbedSelector::InnerFooter> GifsListWidget::createFooter() {
|
||||
.st = &st(),
|
||||
});
|
||||
_footer = result;
|
||||
_chosenSetId = Data::Stickers::RecentSetId;
|
||||
|
||||
GifSectionsValue(
|
||||
&session()
|
||||
@@ -171,6 +172,9 @@ object_ptr<TabbedSelector::InnerFooter> GifsListWidget::createFooter() {
|
||||
|
||||
_footer->setChosen(
|
||||
) | rpl::start_with_next([=](uint64 setId) {
|
||||
if (_search) {
|
||||
_search->cancel();
|
||||
}
|
||||
_chosenSetId = setId;
|
||||
refreshIcons();
|
||||
const auto i = ranges::find(_sections, setId, [](GifSection value) {
|
||||
@@ -791,13 +795,16 @@ bool GifsListWidget::refreshInlineRows(int32 *added) {
|
||||
void GifsListWidget::setupSearch() {
|
||||
const auto session = &_controller->session();
|
||||
_search = MakeSearch(this, st(), [=](std::vector<QString> &&query) {
|
||||
_chosenSetId = Data::Stickers::RecentSetId;
|
||||
refreshIcons();
|
||||
searchForGifs(ranges::accumulate(query, QString(), [](
|
||||
const auto accumulated = ranges::accumulate(query, QString(), [](
|
||||
QString a,
|
||||
QString b) {
|
||||
return a.isEmpty() ? b : (a + ' ' + b);
|
||||
}));
|
||||
});
|
||||
_chosenSetId = accumulated.isEmpty()
|
||||
? Data::Stickers::RecentSetId
|
||||
: SearchEmojiSectionSetId();
|
||||
refreshIcons();
|
||||
searchForGifs(accumulated);
|
||||
}, session);
|
||||
}
|
||||
|
||||
|
||||
@@ -417,6 +417,16 @@ void StickersListFooter::enumerateSubicons(
|
||||
}
|
||||
|
||||
auto StickersListFooter::iconInfo(int index) const -> IconInfo {
|
||||
if (index < 0) {
|
||||
const auto iconsX = int(base::SafeRound(_iconState.x.current()));
|
||||
return {
|
||||
.index = -1,
|
||||
.left = -_singleWidth - _iconsLeft,
|
||||
.adjustedLeft = -_singleWidth - _iconsLeft - iconsX,
|
||||
.width = _singleWidth,
|
||||
.visible = false,
|
||||
};
|
||||
}
|
||||
auto result = IconInfo();
|
||||
enumerateIcons([&](const IconInfo &info) {
|
||||
if (info.index == index) {
|
||||
@@ -473,7 +483,8 @@ void StickersListFooter::validateSelectedIcon(
|
||||
&& setId == Data::Stickers::RecentSetId)) {
|
||||
newSelected = i;
|
||||
break;
|
||||
} else if (_icons[i].setId == Data::Stickers::FavedSetId) {
|
||||
} else if (_icons[i].setId == Data::Stickers::FavedSetId
|
||||
&& setId != SearchEmojiSectionSetId()) {
|
||||
favedIconIndex = i;
|
||||
} else if (isEmojiSection && _icons[i].setId == allEmojiSetId) {
|
||||
newSelected = i;
|
||||
@@ -483,7 +494,9 @@ void StickersListFooter::validateSelectedIcon(
|
||||
setSelectedIcon(
|
||||
(newSelected >= 0
|
||||
? newSelected
|
||||
: (favedIconIndex >= 0) ? favedIconIndex : 0),
|
||||
: (favedIconIndex >= 0)
|
||||
? favedIconIndex
|
||||
: -1),
|
||||
animations);
|
||||
setSelectedSubicon(
|
||||
(newSubSelected >= 0 ? newSubSelected : 0),
|
||||
@@ -522,6 +535,9 @@ void StickersListFooter::setSelectedIcon(
|
||||
if (_iconState.selected == newSelected) {
|
||||
return;
|
||||
}
|
||||
if ((_iconState.selected < 0) != (newSelected < 0)) {
|
||||
animations = ValidateIconAnimations::None;
|
||||
}
|
||||
_iconState.selected = newSelected;
|
||||
updateEmojiSectionWidth();
|
||||
const auto info = iconInfo(_iconState.selected);
|
||||
@@ -1113,7 +1129,7 @@ void StickersListFooter::refreshIconsGeometry(
|
||||
(st().footer - st().iconArea) / 2);
|
||||
refreshScrollableDimensions();
|
||||
refreshSubiconsGeometry();
|
||||
_iconState.selected = _subiconState.selected = -1;
|
||||
_iconState.selected = _subiconState.selected = -2;
|
||||
validateSelectedIcon(activeSetId, animations);
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -165,17 +165,18 @@ StickersListWidget::StickersListWidget(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
Window::GifPauseReason level,
|
||||
bool masks)
|
||||
Mode mode)
|
||||
: Inner(
|
||||
parent,
|
||||
st::defaultEmojiPan,
|
||||
&controller->session(),
|
||||
Window::PausedIn(controller, level))
|
||||
, _mode(mode)
|
||||
, _controller(controller)
|
||||
, _api(&session().mtp())
|
||||
, _localSetsManager(std::make_unique<LocalStickersManager>(&session()))
|
||||
, _section(Section::Stickers)
|
||||
, _isMasks(masks)
|
||||
, _isMasks(mode == Mode::Masks)
|
||||
, _updateItemsTimer([=] { updateItems(); })
|
||||
, _updateSetsTimer([=] { updateSets(); })
|
||||
, _trendingAddBgOver(
|
||||
@@ -1079,20 +1080,10 @@ void StickersListWidget::pauseInvisibleLottieIn(const SectionInfo &info) {
|
||||
}
|
||||
|
||||
void StickersListWidget::paintEmptySearchResults(Painter &p) {
|
||||
const auto iconLeft = (width() - st::stickersEmpty.width()) / 2;
|
||||
const auto iconTop = (height() / 3) - (st::stickersEmpty.height() / 2);
|
||||
st::stickersEmpty.paint(p, iconLeft, iconTop, width());
|
||||
|
||||
const auto text = tr::lng_stickers_nothing_found(tr::now);
|
||||
const auto textWidth = st::normalFont->width(text);
|
||||
p.setFont(st::normalFont);
|
||||
p.setPen(st::windowSubTextFg);
|
||||
p.drawTextLeft(
|
||||
(width() - textWidth) / 2,
|
||||
iconTop + st::stickersEmpty.height() - st::normalFont->height,
|
||||
width(),
|
||||
text,
|
||||
textWidth);
|
||||
Inner::paintEmptySearchResults(
|
||||
p,
|
||||
st::stickersEmpty,
|
||||
tr::lng_stickers_nothing_found(tr::now));
|
||||
}
|
||||
|
||||
int StickersListWidget::megagroupSetInfoLeft() const {
|
||||
@@ -2462,7 +2453,18 @@ auto StickersListWidget::getLottieRenderer()
|
||||
}
|
||||
|
||||
void StickersListWidget::showStickerSet(uint64 setId) {
|
||||
if (_showingSetById) {
|
||||
return;
|
||||
}
|
||||
_showingSetById = true;
|
||||
const auto guard = gsl::finally([&] { _showingSetById = false; });
|
||||
|
||||
clearSelection();
|
||||
if (_search
|
||||
&& (!_searchQuery.isEmpty() || !_searchNextQuery.isEmpty())) {
|
||||
_search->cancel();
|
||||
cancelSetsSearch();
|
||||
}
|
||||
|
||||
if (setId == Data::Stickers::FeaturedSetId) {
|
||||
if (_section != Section::Featured) {
|
||||
@@ -2565,7 +2567,7 @@ void StickersListWidget::setupSearch() {
|
||||
return a.isEmpty() ? b : (a + ' ' + b);
|
||||
});
|
||||
searchForSets(std::move(text), SearchEmoji(query, set));
|
||||
}, session);
|
||||
}, session, false, (_mode == Mode::UserpicBuilder));
|
||||
}
|
||||
|
||||
void StickersListWidget::displaySet(uint64 setId) {
|
||||
|
||||
@@ -59,13 +59,21 @@ enum class ValidateIconAnimations;
|
||||
class StickersListFooter;
|
||||
class LocalStickersManager;
|
||||
|
||||
enum class StickersListMode {
|
||||
Full,
|
||||
Masks,
|
||||
UserpicBuilder,
|
||||
};
|
||||
|
||||
class StickersListWidget final : public TabbedSelector::Inner {
|
||||
public:
|
||||
using Mode = StickersListMode;
|
||||
|
||||
StickersListWidget(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
Window::GifPauseReason level,
|
||||
bool masks = false);
|
||||
Mode mode = Mode::Full);
|
||||
|
||||
rpl::producer<FileChosen> chosen() const;
|
||||
rpl::producer<> scrollUpdated() const;
|
||||
@@ -331,6 +339,8 @@ private:
|
||||
int index,
|
||||
not_null<DocumentData*> document);
|
||||
|
||||
const Mode _mode;
|
||||
|
||||
not_null<Window::SessionController*> _controller;
|
||||
std::unique_ptr<Ui::TabbedSearch> _search;
|
||||
MTP::Sender _api;
|
||||
@@ -345,6 +355,7 @@ private:
|
||||
base::flat_set<not_null<DocumentData*>> _favedStickersMap;
|
||||
std::weak_ptr<Lottie::FrameRenderer> _lottieRenderer;
|
||||
|
||||
bool _showingSetById = false;
|
||||
crl::time _lastScrolledAt = 0;
|
||||
crl::time _lastFullUpdatedAt = 0;
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/layers/box_content.h"
|
||||
#include "ui/image/image_prepare.h"
|
||||
#include "ui/cached_round_corners.h"
|
||||
#include "ui/painter.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_session_settings.h"
|
||||
@@ -500,7 +501,7 @@ TabbedSelector::Tab TabbedSelector::createTab(SelectorTab type, int index) {
|
||||
this,
|
||||
_controller,
|
||||
_level,
|
||||
true);
|
||||
StickersListWidget::Mode::Masks);
|
||||
}
|
||||
Unexpected("Type in TabbedSelector::createTab.");
|
||||
};
|
||||
@@ -1283,6 +1284,30 @@ void TabbedSelector::Inner::checkHideWithBox(QPointer<Ui::BoxContent> box) {
|
||||
});
|
||||
}
|
||||
|
||||
void TabbedSelector::Inner::paintEmptySearchResults(
|
||||
Painter &p,
|
||||
const style::icon &icon,
|
||||
const QString &text) const {
|
||||
const auto iconLeft = (width() - icon.width()) / 2;
|
||||
const auto iconTop = std::max(
|
||||
(height() / 3) - (icon.height() / 2),
|
||||
st::normalFont->height);
|
||||
icon.paint(p, iconLeft, iconTop, width());
|
||||
|
||||
const auto textWidth = st::normalFont->width(text);
|
||||
const auto textTop = std::min(
|
||||
iconTop + icon.height() - st::normalFont->height,
|
||||
height() - 2 * st::normalFont->height);
|
||||
p.setFont(st::normalFont);
|
||||
p.setPen(st::windowSubTextFg);
|
||||
p.drawTextLeft(
|
||||
(width() - textWidth) / 2,
|
||||
textTop,
|
||||
width(),
|
||||
text,
|
||||
textWidth);
|
||||
}
|
||||
|
||||
void TabbedSelector::Inner::visibleTopBottomUpdated(
|
||||
int visibleTop,
|
||||
int visibleBottom) {
|
||||
|
||||
@@ -376,6 +376,11 @@ protected:
|
||||
|
||||
void checkHideWithBox(QPointer<Ui::BoxContent> box);
|
||||
|
||||
void paintEmptySearchResults(
|
||||
Painter &p,
|
||||
const style::icon &icon,
|
||||
const QString &text) const;
|
||||
|
||||
private:
|
||||
const style::EmojiPan &_st;
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
@@ -1118,10 +1118,11 @@ void Application::updateWindowTitles() {
|
||||
}
|
||||
|
||||
void Application::lockByPasscode() {
|
||||
_passcodeLock = true;
|
||||
enumerateWindows([&](not_null<Window::Controller*> w) {
|
||||
_passcodeLock = true;
|
||||
w->setupPasscodeLock();
|
||||
});
|
||||
hideMediaView();
|
||||
}
|
||||
|
||||
void Application::maybeLockByPasscode() {
|
||||
|
||||
@@ -426,7 +426,7 @@ LastCrashedWindow::LastCrashedWindow(
|
||||
}
|
||||
|
||||
_pleaseSendReport.setText(u"Please send us a crash report."_q);
|
||||
_yourReportName.setText(u"Your Report Tag: %1\nYour User Tag: %2"_q.arg(QString(_minidumpName).replace(".dmp", "")).arg(launcher->installationTag(), 0, 16));
|
||||
_yourReportName.setText(u"Crash ID: %1"_q.arg(QString(_minidumpName).replace(".dmp", "")));
|
||||
_yourReportName.setCursor(style::cur_text);
|
||||
_yourReportName.setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||
|
||||
|
||||
@@ -190,9 +190,6 @@ void WriteReportInfo(int signum, const char *name) {
|
||||
} else {
|
||||
dump() << "Caught signal " << signum << " in thread " << uint64(thread) << "\n";
|
||||
}
|
||||
|
||||
dump() << "\nBacktrace omitted.\n";
|
||||
dump() << "\n";
|
||||
}
|
||||
|
||||
const int HandledSignals[] = {
|
||||
|
||||
@@ -320,7 +320,14 @@ void Launcher::init() {
|
||||
}
|
||||
|
||||
void Launcher::initHighDpi() {
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 2, 0)
|
||||
qputenv("QT_DPI_ADJUSTMENT_POLICY", "AdjustDpi");
|
||||
#endif // Qt < 6.2.0
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);
|
||||
#endif // Qt < 6.0.0
|
||||
|
||||
if (OptionFractionalScalingEnabled.value()) {
|
||||
QApplication::setHighDpiScaleFactorRoundingPolicy(
|
||||
Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
||||
|
||||
@@ -239,17 +239,17 @@ void Sandbox::setupScreenScale() {
|
||||
const auto basePair = screen->handle()->logicalBaseDpi();
|
||||
const auto base = (basePair.first + basePair.second) * 0.5;
|
||||
const auto screenScaleExact = dpi / base;
|
||||
const auto screenScale = int(base::SafeRound(screenScaleExact * 4)) * 25;
|
||||
const auto screenScale = int(base::SafeRound(screenScaleExact * 20)) * 5;
|
||||
LOG(("Primary screen DPI: %1, Base: %2.").arg(dpi).arg(base));
|
||||
LOG(("Computed screen scale: %1").arg(screenScale));
|
||||
if (Platform::IsMac()) {
|
||||
// 110% for Retina screens by default.
|
||||
cSetScreenScale((useRatio == 2) ? 110 : 100);
|
||||
cSetScreenScale((useRatio == 2) ? 110 : style::kScaleDefault);
|
||||
} else {
|
||||
const auto clamped = std::clamp(
|
||||
screenScale * useRatio,
|
||||
50 * useRatio,
|
||||
300);
|
||||
style::kScaleMin * useRatio,
|
||||
style::kScaleMax);
|
||||
cSetScreenScale(int(base::SafeRound(clamped * 1. / useRatio)));
|
||||
}
|
||||
LOG(("DevicePixelRatio: %1").arg(useRatio));
|
||||
|
||||
@@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs;
|
||||
constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs;
|
||||
constexpr auto AppName = "Telegram Desktop"_cs;
|
||||
constexpr auto AppFile = "Telegram"_cs;
|
||||
constexpr auto AppVersion = 4006002;
|
||||
constexpr auto AppVersionStr = "4.6.2";
|
||||
constexpr auto AppVersion = 4006003;
|
||||
constexpr auto AppVersionStr = "4.6.3";
|
||||
constexpr auto AppBetaVersion = false;
|
||||
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
|
||||
|
||||
@@ -148,18 +148,19 @@ auto ProcessAlternativeName(Info &&info) {
|
||||
Manager::Manager(not_null<Main::Domain*> domain)
|
||||
: _path(cWorkingDir() + "tdata/countries") {
|
||||
read();
|
||||
|
||||
const auto mtpLifetime = _lifetime.make_state<rpl::lifetime>();
|
||||
domain->activeValue(
|
||||
) | rpl::map([=](Main::Account *account) {
|
||||
if (!account) {
|
||||
_api.reset();
|
||||
}
|
||||
return account
|
||||
? account->mtpMainSessionValue()
|
||||
: rpl::never<not_null<MTP::Instance*>>();
|
||||
}) | rpl::flatten_latest(
|
||||
) | rpl::start_with_next([=](not_null<MTP::Instance*> instance) {
|
||||
_api.emplace(instance);
|
||||
request();
|
||||
) | rpl::filter([=](Main::Account *account) {
|
||||
return (account != nullptr);
|
||||
}) | rpl::start_with_next_done([=](Main::Account *account) {
|
||||
*mtpLifetime = account->mtpMainSessionValue(
|
||||
) | rpl::start_with_next([=](not_null<MTP::Instance*> instance) {
|
||||
_api.emplace(instance);
|
||||
request();
|
||||
});
|
||||
}, [=] {
|
||||
_api.reset();
|
||||
}, _lifetime);
|
||||
}
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ void EmojiStatuses::requestProfilePhotoGroups() {
|
||||
const auto &data = group.data();
|
||||
auto emoticons = ranges::views::all(
|
||||
data.vemoticons().v
|
||||
) | ranges::view::transform([](const MTPstring &emoticon) {
|
||||
) | ranges::views::transform([](const MTPstring &emoticon) {
|
||||
return qs(emoticon);
|
||||
}) | ranges::to_vector;
|
||||
result.push_back({
|
||||
|
||||
@@ -211,7 +211,7 @@ not_null<Dialogs::MainList*> Folder::chatsList() {
|
||||
return &_chatsList;
|
||||
}
|
||||
|
||||
void Folder::loadUserpic() {
|
||||
void Folder::chatListPreloadData() {
|
||||
}
|
||||
|
||||
void Folder::paintUserpic(
|
||||
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
const base::flat_set<QString> &chatListNameWords() const override;
|
||||
const base::flat_set<QChar> &chatListFirstLetters() const override;
|
||||
|
||||
void loadUserpic() override;
|
||||
void chatListPreloadData() override;
|
||||
void paintUserpic(
|
||||
Painter &p,
|
||||
Ui::PeerUserpicView &view,
|
||||
|
||||
@@ -471,17 +471,7 @@ void ForumTopic::applyTopicTopMessage(MsgId topMessageId) {
|
||||
const auto itemId = FullMsgId(channel()->id, topMessageId);
|
||||
if (const auto item = owner().message(itemId)) {
|
||||
setLastServerMessage(item);
|
||||
|
||||
// If we set a single album part, request the full album.
|
||||
if (item->groupId() != MessageGroupId()) {
|
||||
if (owner().groups().isGroupOfOne(item)
|
||||
&& !item->toPreview({
|
||||
.hideSender = true,
|
||||
.hideCaption = true }).images.empty()
|
||||
&& _requestedGroups.emplace(item->fullId()).second) {
|
||||
owner().histories().requestGroupAround(item);
|
||||
}
|
||||
}
|
||||
resolveChatListMessageGroup();
|
||||
} else {
|
||||
setLastServerMessage(nullptr);
|
||||
}
|
||||
@@ -490,6 +480,23 @@ void ForumTopic::applyTopicTopMessage(MsgId topMessageId) {
|
||||
}
|
||||
}
|
||||
|
||||
void ForumTopic::resolveChatListMessageGroup() {
|
||||
if (!(_flags & Flag::ResolveChatListMessage)) {
|
||||
return;
|
||||
}
|
||||
// If we set a single album part, request the full album.
|
||||
const auto item = _lastServerMessage.value_or(nullptr);
|
||||
if (item && item->groupId() != MessageGroupId()) {
|
||||
if (owner().groups().isGroupOfOne(item)
|
||||
&& !item->toPreview({
|
||||
.hideSender = true,
|
||||
.hideCaption = true }).images.empty()
|
||||
&& _requestedGroups.emplace(item->fullId()).second) {
|
||||
owner().histories().requestGroupAround(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ForumTopic::growLastKnownServerMessageId(MsgId id) {
|
||||
_lastKnownServerMessageId = std::max(_lastKnownServerMessageId, id);
|
||||
}
|
||||
@@ -548,10 +555,11 @@ void ForumTopic::setChatListMessage(HistoryItem *item) {
|
||||
_forum->listMessageChanged(was, item);
|
||||
}
|
||||
|
||||
void ForumTopic::loadUserpic() {
|
||||
void ForumTopic::chatListPreloadData() {
|
||||
if (_icon) {
|
||||
[[maybe_unused]] const auto preload = _icon->ready();
|
||||
}
|
||||
allowChatListMessageResolve();
|
||||
}
|
||||
|
||||
void ForumTopic::paintUserpic(
|
||||
@@ -840,6 +848,14 @@ Dialogs::UnreadState ForumTopic::unreadStateFor(
|
||||
return result;
|
||||
}
|
||||
|
||||
void ForumTopic::allowChatListMessageResolve() {
|
||||
if (_flags & Flag::ResolveChatListMessage) {
|
||||
return;
|
||||
}
|
||||
_flags |= Flag::ResolveChatListMessage;
|
||||
resolveChatListMessageGroup();
|
||||
}
|
||||
|
||||
HistoryItem *ForumTopic::chatListMessage() const {
|
||||
return _lastMessage.value_or(nullptr);
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ public:
|
||||
return _notify;
|
||||
}
|
||||
|
||||
void loadUserpic() override;
|
||||
void chatListPreloadData() override;
|
||||
void paintUserpic(
|
||||
Painter &p,
|
||||
Ui::PeerUserpicView &view,
|
||||
@@ -169,6 +169,7 @@ private:
|
||||
HasPinnedMessages = (1 << 3),
|
||||
GeneralIconActive = (1 << 4),
|
||||
GeneralIconSelected = (1 << 5),
|
||||
ResolveChatListMessage = (1 << 6),
|
||||
};
|
||||
friend inline constexpr bool is_flag_type(Flag) { return true; }
|
||||
using Flags = base::flags<Flag>;
|
||||
@@ -183,6 +184,8 @@ private:
|
||||
void setLastMessage(HistoryItem *item);
|
||||
void setLastServerMessage(HistoryItem *item);
|
||||
void setChatListMessage(HistoryItem *item);
|
||||
void allowChatListMessageResolve();
|
||||
void resolveChatListMessageGroup();
|
||||
|
||||
int chatListNameVersion() const override;
|
||||
|
||||
|
||||
@@ -381,6 +381,9 @@ void Session::clear() {
|
||||
cSetRecentInlineBots(RecentInlineBots());
|
||||
cSetRecentStickers(RecentStickerPack());
|
||||
HistoryView::Element::ClearGlobal();
|
||||
_contactsNoChatsList.clear();
|
||||
_contactsList.clear();
|
||||
_chatsList.clear();
|
||||
_histories->clearAll();
|
||||
_webpages.clear();
|
||||
_locations.clear();
|
||||
|
||||
@@ -230,7 +230,7 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual void loadUserpic() = 0;
|
||||
virtual void chatListPreloadData() = 0;
|
||||
virtual void paintUserpic(
|
||||
Painter &p,
|
||||
Ui::PeerUserpicView &view,
|
||||
|
||||
@@ -205,6 +205,7 @@ void IndexedList::remove(Key key, Row *replacedBy) {
|
||||
}
|
||||
|
||||
void IndexedList::clear() {
|
||||
_list.clear();
|
||||
_index.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -2506,7 +2506,7 @@ void InnerWidget::visibleTopBottomUpdated(
|
||||
int visibleBottom) {
|
||||
_visibleTop = visibleTop;
|
||||
_visibleBottom = visibleBottom;
|
||||
loadPeerPhotos();
|
||||
preloadRowsData();
|
||||
const auto loadTill = _visibleTop
|
||||
+ PreloadHeightsCount * (_visibleBottom - _visibleTop);
|
||||
if (_state == WidgetState::Filtered && loadTill >= peerSearchOffset()) {
|
||||
@@ -2726,7 +2726,7 @@ void InnerWidget::refresh(bool toTop) {
|
||||
if (toTop) {
|
||||
stopReorderPinned();
|
||||
_mustScrollTo.fire({ 0, 0 });
|
||||
loadPeerPhotos();
|
||||
preloadRowsData();
|
||||
}
|
||||
_controller->setDialogsListDisplayForced(
|
||||
_searchInChat || !_filter.isEmpty());
|
||||
@@ -3115,8 +3115,10 @@ void InnerWidget::scrollToDefaultSelected() {
|
||||
}
|
||||
}
|
||||
|
||||
void InnerWidget::loadPeerPhotos() {
|
||||
if (!parentWidget()) return;
|
||||
void InnerWidget::preloadRowsData() {
|
||||
if (!parentWidget()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto yFrom = _visibleTop;
|
||||
auto yTo = _visibleTop + (_visibleBottom - _visibleTop) * (PreloadHeightsCount + 1);
|
||||
@@ -3129,7 +3131,7 @@ void InnerWidget::loadPeerPhotos() {
|
||||
if (((*i)->index() * _st->height) >= yTo) {
|
||||
break;
|
||||
}
|
||||
(*i)->entry()->loadUserpic();
|
||||
(*i)->entry()->chatListPreloadData();
|
||||
}
|
||||
yFrom = 0;
|
||||
} else {
|
||||
@@ -3144,7 +3146,7 @@ void InnerWidget::loadPeerPhotos() {
|
||||
if (to > _filterResults.size()) to = _filterResults.size();
|
||||
|
||||
for (; from < to; ++from) {
|
||||
_filterResults[from].key().entry()->loadUserpic();
|
||||
_filterResults[from].key().entry()->chatListPreloadData();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -243,7 +243,7 @@ private:
|
||||
Qt::KeyboardModifiers modifiers);
|
||||
void clearIrrelevantState();
|
||||
void selectByMouse(QPoint globalPosition);
|
||||
void loadPeerPhotos();
|
||||
void preloadRowsData();
|
||||
void scrollToItem(int top, int height);
|
||||
void scrollToDefaultSelected();
|
||||
void setCollapsedPressed(int pressed);
|
||||
|
||||
@@ -23,6 +23,10 @@ public:
|
||||
List &operator=(List &&other) = default;
|
||||
~List() = default;
|
||||
|
||||
void clear() {
|
||||
_rows.clear();
|
||||
_rowByKey.clear();
|
||||
}
|
||||
[[nodiscard]] int size() const {
|
||||
return _rows.size();
|
||||
}
|
||||
|
||||
@@ -81,6 +81,7 @@ void MainList::clear() {
|
||||
recomputeFullListSize();
|
||||
});
|
||||
const auto notifier = unreadStateChangeNotifier(true);
|
||||
_pinned.clear();
|
||||
_all.clear();
|
||||
_unreadState = UnreadState();
|
||||
_cloudUnreadState = UnreadState();
|
||||
|
||||
@@ -743,6 +743,7 @@ void RowPainter::Paint(
|
||||
const auto thread = row->thread();
|
||||
const auto peer = history ? history->peer.get() : nullptr;
|
||||
const auto badgesState = entry->chatListBadgesState();
|
||||
entry->chatListPreloadData(); // Allow chat list message resolve.
|
||||
const auto item = entry->chatListMessage();
|
||||
const auto cloudDraft = [&]() -> const Data::Draft*{
|
||||
if (!thread) {
|
||||
|
||||
@@ -14,7 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QDir>
|
||||
|
||||
#include <gsl/gsl_util>
|
||||
#include <gsl/util>
|
||||
|
||||
namespace Export {
|
||||
namespace Output {
|
||||
|
||||
@@ -607,16 +607,6 @@ not_null<HistoryItem*> History::addNewItem(
|
||||
} else {
|
||||
addNewToBack(item, unread);
|
||||
checkForLoadedAtTop(item);
|
||||
if (!unread) {
|
||||
// When we add just one last item, like we do while loading dialogs,
|
||||
// we want to remove a single added grouped media, otherwise it will
|
||||
// jump once we open the message history (first we show only that
|
||||
// media, then we load the rest of the group and show the group).
|
||||
//
|
||||
// That way when we open the message history we show nothing until a
|
||||
// whole history part is loaded, it certainly will contain the group.
|
||||
removeOrphanMediaGroupPart();
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
@@ -2241,6 +2231,44 @@ Dialogs::UnreadState History::computeUnreadState() const {
|
||||
return result;
|
||||
}
|
||||
|
||||
void History::allowChatListMessageResolve() {
|
||||
if (_flags & Flag::ResolveChatListMessage) {
|
||||
return;
|
||||
}
|
||||
_flags |= Flag::ResolveChatListMessage;
|
||||
if (!chatListMessageKnown()) {
|
||||
requestChatListMessage();
|
||||
} else {
|
||||
resolveChatListMessageGroup();
|
||||
}
|
||||
}
|
||||
|
||||
void History::resolveChatListMessageGroup() {
|
||||
const auto item = _chatListMessage.value_or(nullptr);
|
||||
if (!(_flags & Flag::ResolveChatListMessage)
|
||||
|| !item
|
||||
|| !hasOrphanMediaGroupPart()) {
|
||||
return;
|
||||
}
|
||||
// If we set a single album part, request the full album.
|
||||
const auto withImages = !item->toPreview({
|
||||
.hideSender = true,
|
||||
.hideCaption = true }).images.empty();
|
||||
if (withImages) {
|
||||
owner().histories().requestGroupAround(item);
|
||||
}
|
||||
if (unreadCountKnown() && !unreadCount()) {
|
||||
// When we add just one last item, like we do while loading dialogs,
|
||||
// we want to remove a single added grouped media, otherwise it will
|
||||
// jump once we open the message history (first we show only that
|
||||
// media, then we load the rest of the group and show the group).
|
||||
//
|
||||
// That way when we open the message history we show nothing until a
|
||||
// whole history part is loaded, it certainly will contain the group.
|
||||
clear(ClearType::Unload);
|
||||
}
|
||||
}
|
||||
|
||||
HistoryItem *History::chatListMessage() const {
|
||||
return _chatListMessage.value_or(nullptr);
|
||||
}
|
||||
@@ -2269,8 +2297,9 @@ const base::flat_set<QChar> &History::chatListFirstLetters() const {
|
||||
return peer->nameFirstLetters();
|
||||
}
|
||||
|
||||
void History::loadUserpic() {
|
||||
void History::chatListPreloadData() {
|
||||
peer->loadUserpic();
|
||||
allowChatListMessageResolve();
|
||||
}
|
||||
|
||||
void History::paintUserpic(
|
||||
@@ -2452,14 +2481,7 @@ void History::setChatListMessage(HistoryItem *item) {
|
||||
}
|
||||
_chatListMessage = item;
|
||||
setChatListTimeId(item->date());
|
||||
|
||||
// If we have a single message from a group, request the full album.
|
||||
if (hasOrphanMediaGroupPart()
|
||||
&& !item->toPreview({
|
||||
.hideSender = true,
|
||||
.hideCaption = true }).images.empty()) {
|
||||
owner().histories().requestGroupAround(item);
|
||||
}
|
||||
resolveChatListMessageGroup();
|
||||
} else if (!_chatListMessage || *_chatListMessage) {
|
||||
_chatListMessage = nullptr;
|
||||
updateChatListEntry();
|
||||
@@ -2560,13 +2582,21 @@ void History::requestChatListMessage() {
|
||||
}
|
||||
|
||||
void History::setFakeChatListMessage() {
|
||||
if (const auto chat = peer->asChat()) {
|
||||
if (!(_flags & Flag::ResolveChatListMessage)) {
|
||||
if (!chatListTimeId()) {
|
||||
if (const auto last = lastMessage()) {
|
||||
setChatListTimeId(last->date());
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else if (const auto chat = peer->asChat()) {
|
||||
// In chats we try to take the item before the 'last', which
|
||||
// is the empty-displayed migration message.
|
||||
owner().histories().requestFakeChatListMessage(this);
|
||||
} else if (const auto from = migrateFrom()) {
|
||||
// In megagroups we just try to use
|
||||
// the message from the original group.
|
||||
from->allowChatListMessageResolve();
|
||||
from->requestChatListMessage();
|
||||
}
|
||||
}
|
||||
@@ -3309,14 +3339,6 @@ bool History::hasOrphanMediaGroupPart() const {
|
||||
return last->groupId() != MessageGroupId();
|
||||
}
|
||||
|
||||
bool History::removeOrphanMediaGroupPart() {
|
||||
if (hasOrphanMediaGroupPart()) {
|
||||
clear(ClearType::Unload);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<MsgId> History::collectMessagesFromParticipantToDelete(
|
||||
not_null<PeerData*> participant) const {
|
||||
auto result = std::vector<MsgId>();
|
||||
|
||||
@@ -111,7 +111,6 @@ public:
|
||||
Element *findLastNonEmpty() const;
|
||||
Element *findLastDisplayed() const;
|
||||
bool hasOrphanMediaGroupPart() const;
|
||||
bool removeOrphanMediaGroupPart();
|
||||
[[nodiscard]] std::vector<MsgId> collectMessagesFromParticipantToDelete(
|
||||
not_null<PeerData*> participant) const;
|
||||
|
||||
@@ -387,7 +386,7 @@ public:
|
||||
const QString &chatListNameSortKey() const override;
|
||||
const base::flat_set<QString> &chatListNameWords() const override;
|
||||
const base::flat_set<QChar> &chatListFirstLetters() const override;
|
||||
void loadUserpic() override;
|
||||
void chatListPreloadData() override;
|
||||
void paintUserpic(
|
||||
Painter &p,
|
||||
Ui::PeerUserpicView &view,
|
||||
@@ -467,6 +466,7 @@ private:
|
||||
IsForum = (1 << 3),
|
||||
FakeUnreadWhileOpened = (1 << 4),
|
||||
HasPinnedMessages = (1 << 5),
|
||||
ResolveChatListMessage = (1 << 6),
|
||||
};
|
||||
using Flags = base::flags<Flag>;
|
||||
friend inline constexpr auto is_flag_type(Flag) {
|
||||
@@ -553,6 +553,8 @@ private:
|
||||
void setChatListMessageFromLast();
|
||||
void setChatListMessageUnknown();
|
||||
void setFakeChatListMessage();
|
||||
void allowChatListMessageResolve();
|
||||
void resolveChatListMessageGroup();
|
||||
|
||||
// Add all items to the unread mentions if we were not loaded at bottom and now are.
|
||||
void checkAddAllToUnreadMentions();
|
||||
|
||||
@@ -3946,8 +3946,17 @@ void HistoryInner::notifyIsBotChanged() {
|
||||
}
|
||||
|
||||
void HistoryInner::notifyMigrateUpdated() {
|
||||
_migrated = _history->migrateFrom();
|
||||
_migrated->translateTo(_history->translatedTo());
|
||||
const auto migrated = _history->migrateFrom();
|
||||
if (_migrated != migrated) {
|
||||
if (_migrated) {
|
||||
_migrated->delegateMixin()->setCurrent(nullptr);
|
||||
}
|
||||
_migrated = migrated;
|
||||
if (_migrated) {
|
||||
_migrated->delegateMixin()->setCurrent(this);
|
||||
_migrated->translateTo(_history->translatedTo());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryInner::applyDragSelection() {
|
||||
|
||||
@@ -491,7 +491,13 @@ HistoryWidget::HistoryWidget(
|
||||
_botCommandStart->hide();
|
||||
|
||||
session().attachWebView().requestBots();
|
||||
session().attachWebView().attachBotsUpdates(
|
||||
rpl::merge(
|
||||
session().attachWebView().attachBotsUpdates(),
|
||||
session().changes().peerUpdates(
|
||||
Data::PeerUpdate::Flag::Rights
|
||||
) | rpl::filter([=](const Data::PeerUpdate &update) {
|
||||
return update.peer == _peer;
|
||||
}) | rpl::to_empty
|
||||
) | rpl::start_with_next([=] {
|
||||
refreshAttachBotsMenu();
|
||||
}, lifetime());
|
||||
@@ -505,7 +511,16 @@ HistoryWidget::HistoryWidget(
|
||||
_attachDragAreas = DragArea::SetupDragAreaToContainer(
|
||||
this,
|
||||
crl::guard(this, [=](not_null<const QMimeData*> d) {
|
||||
return _history && _canSendMessages && !isRecording();
|
||||
if (!_peer || isRecording()) {
|
||||
return false;
|
||||
}
|
||||
const auto replyTo = (_replyToId && !_editMsgId)
|
||||
? _replyEditMsg
|
||||
: 0;
|
||||
const auto topic = replyTo ? replyTo->topic() : nullptr;
|
||||
return topic
|
||||
? Data::CanSendAnyOf(topic, Data::FilesSendRestrictions())
|
||||
: Data::CanSendAnyOf(_peer, Data::FilesSendRestrictions());
|
||||
}),
|
||||
crl::guard(this, [=](bool f) { _field->setAcceptDrops(f); }),
|
||||
crl::guard(this, [=] { updateControlsGeometry(); }));
|
||||
|
||||
@@ -523,9 +523,9 @@ void BottomInfo::layoutReactionsText() {
|
||||
_reactions.clear();
|
||||
return;
|
||||
}
|
||||
auto sorted = ranges::view::all(
|
||||
auto sorted = ranges::views::all(
|
||||
_data.reactions
|
||||
) | ranges::view::transform([](const MessageReaction &reaction) {
|
||||
) | ranges::views::transform([](const MessageReaction &reaction) {
|
||||
return not_null{ &reaction };
|
||||
}) | ranges::to_vector;
|
||||
ranges::sort(
|
||||
|
||||
@@ -355,6 +355,11 @@ protected:
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
|
||||
private:
|
||||
using ScrollTopState = ListMemento::ScrollTopState;
|
||||
using PointState = HistoryView::PointState;
|
||||
using CursorState = HistoryView::CursorState;
|
||||
using ChosenReaction = HistoryView::Reactions::ChosenReaction;
|
||||
|
||||
struct MouseState {
|
||||
MouseState();
|
||||
MouseState(
|
||||
@@ -405,10 +410,6 @@ private:
|
||||
Selecting,
|
||||
Deselecting,
|
||||
};
|
||||
using ScrollTopState = ListMemento::ScrollTopState;
|
||||
using PointState = HistoryView::PointState;
|
||||
using CursorState = HistoryView::CursorState;
|
||||
using ChosenReaction = HistoryView::Reactions::ChosenReaction;
|
||||
|
||||
void onTouchSelect();
|
||||
void onTouchScrollTimer();
|
||||
|
||||
@@ -2616,9 +2616,18 @@ void RepliesWidget::clearSelected() {
|
||||
}
|
||||
|
||||
void RepliesWidget::setupDragArea() {
|
||||
const auto filter = [=](const auto &d) {
|
||||
if (!_history || _composeControls->isRecording()) {
|
||||
return false;
|
||||
}
|
||||
const auto peer = _history->peer;
|
||||
return _topic
|
||||
? Data::CanSendAnyOf(_topic, Data::FilesSendRestrictions())
|
||||
: Data::CanSendAnyOf(peer, Data::FilesSendRestrictions());
|
||||
};
|
||||
const auto areas = DragArea::SetupDragAreaToContainer(
|
||||
this,
|
||||
[=](auto d) { return _history && !_composeControls->isRecording(); },
|
||||
filter,
|
||||
nullptr,
|
||||
[=] { updateControlsGeometry(); });
|
||||
|
||||
|
||||
@@ -124,7 +124,9 @@ TopBarWidget::TopBarWidget(
|
||||
_groupCall->setClickedCallback([=] { groupCall(); });
|
||||
_menuToggle->setClickedCallback([=] { showPeerMenu(); });
|
||||
_infoToggle->setClickedCallback([=] { toggleInfoSection(); });
|
||||
_back->addClickHandler([=] { backClicked(); });
|
||||
_back->setClickedCallback([=] {
|
||||
InvokeQueued(_back.data(), [=] { backClicked(); });
|
||||
});
|
||||
_cancelChoose->setClickedCallback(
|
||||
[=] { _cancelChooseForReport.fire({}); });
|
||||
|
||||
|
||||
@@ -111,9 +111,9 @@ void InlineList::layoutButtons() {
|
||||
_buttons.clear();
|
||||
return;
|
||||
}
|
||||
auto sorted = ranges::view::all(
|
||||
auto sorted = ranges::views::all(
|
||||
_data.reactions
|
||||
) | ranges::view::transform([](const MessageReaction &reaction) {
|
||||
) | ranges::views::transform([](const MessageReaction &reaction) {
|
||||
return not_null{ &reaction };
|
||||
}) | ranges::to_vector;
|
||||
const auto &list = _owner->list(::Data::Reactions::Type::All);
|
||||
@@ -643,7 +643,7 @@ InlineListData InlineListDataFromMessage(not_null<Message*> message) {
|
||||
result.recent.reserve(recent.size());
|
||||
for (const auto &[id, list] : recent) {
|
||||
result.recent.emplace(id).first->second = list
|
||||
| ranges::view::transform(&Data::RecentReaction::peer)
|
||||
| ranges::views::transform(&Data::RecentReaction::peer)
|
||||
| ranges::to_vector;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,9 +220,9 @@ void Controller::showReaction(const ReactionId &reaction) {
|
||||
appendRow(peer, reaction);
|
||||
}
|
||||
} else {
|
||||
_filtered = _all | ranges::view::filter([&](const AllEntry &entry) {
|
||||
_filtered = _all | ranges::views::filter([&](const AllEntry &entry) {
|
||||
return (entry.second == reaction);
|
||||
}) | ranges::view::transform(
|
||||
}) | ranges::views::transform(
|
||||
&AllEntry::first
|
||||
) | ranges::to_vector;
|
||||
for (const auto peer : _filtered) {
|
||||
|
||||
@@ -18,7 +18,7 @@ userpicBuilderEmojiSubtitle: FlatLabel(defaultFlatLabel) {
|
||||
textFg: windowSubTextFg;
|
||||
}
|
||||
userpicBuilderEmojiSubtitlePadding: margins(0px, 9px, 0px, 2px);
|
||||
userpicBuilderEmojiBubblePaletteSize: size(356px, 56px);
|
||||
userpicBuilderEmojiBubblePaletteWidth: 356px;
|
||||
userpicBuilderEmojiBubblePalettePadding: margins(12px, 8px, 12px, 8px);
|
||||
|
||||
userpicBuilderEmojiSelectorLeft: 5px;
|
||||
|
||||
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/random.h"
|
||||
#include "base/timer.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "info/userpic/info_userpic_emoji_builder.h"
|
||||
@@ -27,6 +28,128 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <random>
|
||||
|
||||
namespace UserpicBuilder {
|
||||
namespace {
|
||||
|
||||
constexpr auto kTimeout = crl::time(1500);
|
||||
|
||||
class StickerProvider final {
|
||||
public:
|
||||
StickerProvider(not_null<Data::Session*> owner);
|
||||
|
||||
void setDocuments(std::vector<DocumentId> documents);
|
||||
[[nodiscard]] DocumentId documentId() const;
|
||||
[[nodiscard]] auto documentChanged() const
|
||||
-> rpl::producer<not_null<DocumentData*>>;
|
||||
|
||||
private:
|
||||
void processDocumentIndex(int documentIndex);
|
||||
[[nodiscard]] DocumentData *lookupAndRememberSticker(int documentIndex);
|
||||
[[nodiscard]] std::pair<DocumentData*, int> lookupSticker(
|
||||
int documentIndex) const;
|
||||
|
||||
const not_null<Data::Session*> _owner;
|
||||
|
||||
int _documentIndex = 0;
|
||||
std::vector<DocumentId> _shuffledDocuments;
|
||||
|
||||
base::Timer _timer;
|
||||
|
||||
rpl::event_stream<not_null<DocumentData*>> _documentChanged;
|
||||
rpl::lifetime _resolvingLifetime;
|
||||
rpl::lifetime _downloadFinishedLifetime;
|
||||
|
||||
};
|
||||
|
||||
StickerProvider::StickerProvider(not_null<Data::Session*> owner)
|
||||
: _owner(owner) {
|
||||
_timer.setCallback([=] {
|
||||
_documentIndex++;
|
||||
if (_documentIndex >= _shuffledDocuments.size()) {
|
||||
_documentIndex = 0;
|
||||
}
|
||||
processDocumentIndex(_documentIndex);
|
||||
});
|
||||
}
|
||||
|
||||
DocumentId StickerProvider::documentId() const {
|
||||
const auto &[document, index] = lookupSticker(_documentIndex);
|
||||
return document ? document->id : DocumentId(0);
|
||||
}
|
||||
|
||||
void StickerProvider::setDocuments(std::vector<DocumentId> documents) {
|
||||
if (documents.empty()) {
|
||||
return;
|
||||
}
|
||||
auto rd = std::random_device();
|
||||
ranges::shuffle(documents, std::mt19937(rd()));
|
||||
_shuffledDocuments = std::move(documents);
|
||||
_documentIndex = 0;
|
||||
processDocumentIndex(_documentIndex);
|
||||
}
|
||||
|
||||
auto StickerProvider::documentChanged() const
|
||||
-> rpl::producer<not_null<DocumentData*>> {
|
||||
return _documentChanged.events();
|
||||
}
|
||||
|
||||
void StickerProvider::processDocumentIndex(int documentIndex) {
|
||||
if (const auto document = lookupAndRememberSticker(documentIndex)) {
|
||||
_resolvingLifetime.destroy();
|
||||
_owner->customEmojiManager().resolve(
|
||||
document->id
|
||||
) | rpl::start_with_next([=](not_null<DocumentData*> d) {
|
||||
_resolvingLifetime.destroy();
|
||||
_downloadFinishedLifetime.destroy();
|
||||
|
||||
const auto mediaView = d->createMediaView();
|
||||
_downloadFinishedLifetime.add([=] {
|
||||
[[maybe_unused]] const auto copy = mediaView;
|
||||
});
|
||||
mediaView->checkStickerLarge();
|
||||
mediaView->goodThumbnailWanted();
|
||||
rpl::single(
|
||||
rpl::empty_value()
|
||||
) | rpl::then(
|
||||
_owner->session().downloaderTaskFinished()
|
||||
) | rpl::start_with_next([=] {
|
||||
if (mediaView->loaded()) {
|
||||
_timer.callOnce(kTimeout);
|
||||
_documentChanged.fire_copy(mediaView->owner());
|
||||
_downloadFinishedLifetime.destroy();
|
||||
}
|
||||
}, _downloadFinishedLifetime);
|
||||
}, _resolvingLifetime);
|
||||
} else if (!_resolvingLifetime) {
|
||||
_timer.callOnce(kTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
DocumentData *StickerProvider::lookupAndRememberSticker(int documentIndex) {
|
||||
const auto &[document, index] = lookupSticker(documentIndex);
|
||||
if (document) {
|
||||
_documentIndex = index;
|
||||
}
|
||||
return document;
|
||||
}
|
||||
|
||||
std::pair<DocumentData*, int> StickerProvider::lookupSticker(
|
||||
int documentIndex) const {
|
||||
const auto size = _shuffledDocuments.size();
|
||||
for (auto i = 0; i < size; i++) {
|
||||
const auto unrestrictedIndex = documentIndex + i;
|
||||
const auto index = (unrestrictedIndex >= size)
|
||||
? (unrestrictedIndex - size)
|
||||
: unrestrictedIndex;
|
||||
const auto id = _shuffledDocuments[index];
|
||||
const auto document = _owner->document(id);
|
||||
if (document->sticker()) {
|
||||
return { document, index };
|
||||
}
|
||||
}
|
||||
return { nullptr, 0 };
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void AddEmojiBuilderAction(
|
||||
not_null<Window::SessionController*> controller,
|
||||
@@ -34,35 +157,23 @@ void AddEmojiBuilderAction(
|
||||
rpl::producer<std::vector<DocumentId>> documents,
|
||||
Fn<void(UserpicBuilder::Result)> &&done,
|
||||
bool isForum) {
|
||||
constexpr auto kTimeout = crl::time(1500);
|
||||
struct State final {
|
||||
State() {
|
||||
colorIndex = base::RandomIndex(std::numeric_limits<int>::max());
|
||||
}
|
||||
void next() {
|
||||
auto nextIndex = documentIndex.current() + 1;
|
||||
if (nextIndex >= shuffledDocuments.size()) {
|
||||
nextIndex = 0;
|
||||
}
|
||||
documentIndex = nextIndex;
|
||||
}
|
||||
void documentShown() {
|
||||
if (!firstDocumentShown) {
|
||||
firstDocumentShown = true;
|
||||
} else {
|
||||
colorIndex = base::RandomIndex(
|
||||
std::numeric_limits<int>::max());
|
||||
}
|
||||
timer.callOnce(kTimeout);
|
||||
}
|
||||
rpl::variable<int> documentIndex;
|
||||
rpl::variable<int> colorIndex;
|
||||
std::vector<DocumentId> shuffledDocuments;
|
||||
bool firstDocumentShown = false;
|
||||
|
||||
base::Timer timer;
|
||||
struct State final {
|
||||
State(not_null<Window::SessionController*> controller)
|
||||
: manager(&controller->session().data())
|
||||
, colorIndex(rpl::single(
|
||||
rpl::empty_value()
|
||||
) | rpl::then(
|
||||
manager.documentChanged() | rpl::skip(1) | rpl::to_empty
|
||||
) | rpl::map([] {
|
||||
return base::RandomIndex(std::numeric_limits<int>::max());
|
||||
})) {
|
||||
}
|
||||
|
||||
StickerProvider manager;
|
||||
rpl::variable<int> colorIndex;
|
||||
};
|
||||
const auto state = menu->lifetime().make_state<State>();
|
||||
const auto state = menu->lifetime().make_state<State>(controller);
|
||||
auto item = base::make_unique_q<Ui::Menu::Action>(
|
||||
menu.get(),
|
||||
menu->st().menu,
|
||||
@@ -70,10 +181,7 @@ void AddEmojiBuilderAction(
|
||||
menu.get(),
|
||||
tr::lng_attach_profile_emoji(tr::now),
|
||||
[=, done = std::move(done), docs = rpl::duplicate(documents)] {
|
||||
const auto index = state->documentIndex.current();
|
||||
const auto id = index < state->shuffledDocuments.size()
|
||||
? state->shuffledDocuments[index]
|
||||
: 0;
|
||||
const auto id = state->manager.documentId();
|
||||
UserpicBuilder::ShowLayer(
|
||||
controller,
|
||||
{ id, state->colorIndex.current(), docs, {}, isForum },
|
||||
@@ -81,29 +189,10 @@ void AddEmojiBuilderAction(
|
||||
}),
|
||||
nullptr,
|
||||
nullptr);
|
||||
state->timer.setCallback([=] { state->next(); });
|
||||
const auto icon = UserpicBuilder::CreateEmojiUserpic(
|
||||
item.get(),
|
||||
st::restoreUserpicIcon.size,
|
||||
state->documentIndex.value(
|
||||
) | rpl::filter([=](int index) {
|
||||
if (index >= state->shuffledDocuments.size()) {
|
||||
state->next();
|
||||
return false;
|
||||
}
|
||||
const auto id = state->shuffledDocuments[index];
|
||||
if (!controller->session().data().document(id)->sticker()) {
|
||||
state->next();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}) | rpl::map([=](int index) {
|
||||
return controller->session().data().customEmojiManager().resolve(
|
||||
state->shuffledDocuments[index]);
|
||||
}) | rpl::flatten_latest() | rpl::map([=](not_null<DocumentData*> d) {
|
||||
state->documentShown();
|
||||
return d;
|
||||
}),
|
||||
state->manager.documentChanged(),
|
||||
state->colorIndex.value(),
|
||||
isForum);
|
||||
icon->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
@@ -115,13 +204,7 @@ void AddEmojiBuilderAction(
|
||||
rpl::duplicate(
|
||||
documents
|
||||
) | rpl::start_with_next([=](std::vector<DocumentId> documents) {
|
||||
if (documents.empty()) {
|
||||
return;
|
||||
}
|
||||
auto rd = std::random_device();
|
||||
ranges::shuffle(documents, std::mt19937(rd()));
|
||||
state->shuffledDocuments = std::move(documents);
|
||||
state->documentIndex.force_assign(0);
|
||||
state->manager.setDocuments(std::move(documents));
|
||||
}, item->lifetime());
|
||||
|
||||
menu->addAction(std::move(item));
|
||||
|
||||
@@ -250,7 +250,7 @@ EmojiSelector::Selector EmojiSelector::createEmojiList(
|
||||
.customRecentFactory = [=](DocumentId id, Fn<void()> repaint) {
|
||||
return manager->create(id, std::move(repaint), tag);
|
||||
},
|
||||
.st = &st::reactPanelEmojiPan,
|
||||
.st = &st::userpicBuilderEmojiPan,
|
||||
};
|
||||
const auto list = scroll->setOwnedWidget(
|
||||
object_ptr<ChatHelpers::EmojiListWidget>(scroll, std::move(args)));
|
||||
@@ -274,7 +274,8 @@ EmojiSelector::Selector EmojiSelector::createStickersList(
|
||||
object_ptr<ChatHelpers::StickersListWidget>(
|
||||
scroll,
|
||||
_controller,
|
||||
Window::GifPauseReason::Any));
|
||||
Window::GifPauseReason::Any,
|
||||
ChatHelpers::StickersListMode::UserpicBuilder));
|
||||
const auto footer = list->createFooter().data();
|
||||
list->refreshRecent();
|
||||
list->chosen(
|
||||
@@ -418,7 +419,8 @@ not_null<Ui::VerticalLayout*> CreateUserpicBuilder(
|
||||
data.isForum)),
|
||||
st::userpicBuilderEmojiPreviewPadding)->entity();
|
||||
if (const auto id = data.documentId) {
|
||||
if (const auto document = controller->session().data().document(id)) {
|
||||
const auto document = controller->session().data().document(id);
|
||||
if (document && document->sticker()) {
|
||||
preview->setDocument(document);
|
||||
}
|
||||
}
|
||||
@@ -434,8 +436,13 @@ not_null<Ui::VerticalLayout*> CreateUserpicBuilder(
|
||||
|
||||
const auto paletteBg = Ui::AddBubbleWrap(
|
||||
container,
|
||||
st::userpicBuilderEmojiBubblePaletteSize);
|
||||
const auto palette = Ui::CreateChild<Ui::RpWidget>(paletteBg.get());
|
||||
QSize(
|
||||
st::userpicBuilderEmojiBubblePaletteWidth,
|
||||
std::abs(Ui::BubbleWrapInnerRect(QRect(0, 0, 0, 0)).height())
|
||||
+ st::userpicBuilderEmojiAccentColorSize
|
||||
+ rect::m::sum::v(
|
||||
st::userpicBuilderEmojiBubblePalettePadding)));
|
||||
const auto palette = Ui::CreateChild<Ui::VerticalLayout>(paletteBg.get());
|
||||
{
|
||||
constexpr auto kColorsCount = int(7);
|
||||
const auto checkIsSpecial = [=](int i) {
|
||||
@@ -522,7 +529,7 @@ not_null<Ui::VerticalLayout*> CreateUserpicBuilder(
|
||||
const auto selectorBg = Ui::AddBubbleWrap(
|
||||
container,
|
||||
QSize(
|
||||
st::userpicBuilderEmojiBubblePaletteSize.width(),
|
||||
st::userpicBuilderEmojiBubblePaletteWidth,
|
||||
st::userpicBuilderEmojiSelectorMinHeight));
|
||||
const auto selector = Ui::CreateChild<EmojiSelector>(
|
||||
selectorBg.get(),
|
||||
|
||||
@@ -1044,17 +1044,32 @@ std::unique_ptr<Ui::DropdownMenu> MakeAttachBotsMenu(
|
||||
not_null<PeerData*> peer,
|
||||
Fn<Api::SendAction()> actionFactory,
|
||||
Fn<void(bool)> attach) {
|
||||
if (!Data::CanSend(peer, ChatRestriction::SendInline)) {
|
||||
return nullptr;
|
||||
}
|
||||
auto result = std::make_unique<Ui::DropdownMenu>(
|
||||
parent,
|
||||
st::dropdownMenuWithIcons);
|
||||
const auto bots = &peer->session().attachWebView();
|
||||
const auto raw = result.get();
|
||||
raw->addAction(tr::lng_attach_photo_or_video(tr::now), [=] {
|
||||
attach(true);
|
||||
}, &st::menuIconPhoto);
|
||||
raw->addAction(tr::lng_attach_document(tr::now), [=] {
|
||||
attach(false);
|
||||
}, &st::menuIconFile);
|
||||
auto minimal = 0;
|
||||
if (Data::CanSend(peer, ChatRestriction::SendPhotos, false)) {
|
||||
++minimal;
|
||||
raw->addAction(tr::lng_attach_photo_or_video(tr::now), [=] {
|
||||
attach(true);
|
||||
}, &st::menuIconPhoto);
|
||||
}
|
||||
const auto fileTypes = ChatRestriction::SendVideos
|
||||
| ChatRestriction::SendGifs
|
||||
| ChatRestriction::SendStickers
|
||||
| ChatRestriction::SendMusic
|
||||
| ChatRestriction::SendFiles;
|
||||
if (Data::CanSendAnyOf(peer, fileTypes)) {
|
||||
++minimal;
|
||||
raw->addAction(tr::lng_attach_document(tr::now), [=] {
|
||||
attach(false);
|
||||
}, &st::menuIconFile);
|
||||
}
|
||||
for (const auto &bot : bots->attachBots()) {
|
||||
if (!PeerMatchesTypes(peer, bot.user, bot.types)) {
|
||||
continue;
|
||||
@@ -1082,7 +1097,7 @@ std::unique_ptr<Ui::DropdownMenu> MakeAttachBotsMenu(
|
||||
}, action->lifetime());
|
||||
raw->addAction(std::move(action));
|
||||
}
|
||||
if (raw->actions().size() < 3) {
|
||||
if (raw->actions().size() <= minimal) {
|
||||
return nullptr;
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -158,18 +158,18 @@ Language ParseLanguage(const MTPLangPackLanguage &data) {
|
||||
|
||||
CloudManager::CloudManager(Instance &langpack)
|
||||
: _langpack(langpack) {
|
||||
const auto mtpLifetime = _lifetime.make_state<rpl::lifetime>();
|
||||
Core::App().domain().activeValue(
|
||||
) | rpl::map([=](Main::Account *account) {
|
||||
if (!account) {
|
||||
_api.reset();
|
||||
}
|
||||
return account
|
||||
? account->mtpMainSessionValue()
|
||||
: rpl::never<not_null<MTP::Instance*>>();
|
||||
}) | rpl::flatten_latest(
|
||||
) | rpl::start_with_next([=](not_null<MTP::Instance*> instance) {
|
||||
_api.emplace(instance);
|
||||
resendRequests();
|
||||
) | rpl::filter([=](Main::Account *account) {
|
||||
return (account != nullptr);
|
||||
}) | rpl::start_with_next_done([=](Main::Account *account) {
|
||||
*mtpLifetime = account->mtpMainSessionValue(
|
||||
) | rpl::start_with_next([=](not_null<MTP::Instance*> instance) {
|
||||
_api.emplace(instance);
|
||||
resendRequests();
|
||||
});
|
||||
}, [=] {
|
||||
_api.reset();
|
||||
}, _lifetime);
|
||||
}
|
||||
|
||||
|
||||
@@ -202,8 +202,6 @@ Account &Domain::active() const {
|
||||
return *_active.current();
|
||||
}
|
||||
|
||||
|
||||
|
||||
rpl::producer<not_null<Account*>> Domain::activeChanges() const {
|
||||
return _active.changes() | rpl::map([](Account *value) {
|
||||
return not_null{ value };
|
||||
|
||||
@@ -79,6 +79,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "boxes/download_path_box.h"
|
||||
#include "boxes/connection_box.h"
|
||||
#include "storage/storage_account.h"
|
||||
#include "main/main_domain.h"
|
||||
#include "media/audio/media_audio.h"
|
||||
#include "media/player/media_player_panel.h"
|
||||
#include "media/player/media_player_widget.h"
|
||||
@@ -1265,6 +1266,8 @@ bool MainWidget::showHistoryInDifferentWindow(
|
||||
const SectionShow ¶ms,
|
||||
MsgId showAtMsgId) {
|
||||
const auto peer = session().data().peer(peerId);
|
||||
const auto account = &session().account();
|
||||
auto primary = Core::App().separateWindowForAccount(account);
|
||||
if (const auto separate = Core::App().separateWindowForPeer(peer)) {
|
||||
if (separate == &_controller->window()) {
|
||||
return false;
|
||||
@@ -1276,8 +1279,6 @@ bool MainWidget::showHistoryInDifferentWindow(
|
||||
separate->activate();
|
||||
return true;
|
||||
} else if (isPrimary()) {
|
||||
const auto primary = Core::App().separateWindowForAccount(
|
||||
&peer->account());
|
||||
if (primary && primary != &_controller->window()) {
|
||||
primary->sessionController()->showPeerHistory(
|
||||
peerId,
|
||||
@@ -1291,18 +1292,17 @@ bool MainWidget::showHistoryInDifferentWindow(
|
||||
return true;
|
||||
} else if (singlePeer()->id == peerId) {
|
||||
return false;
|
||||
} else if (!primary) {
|
||||
Core::App().domain().activate(account);
|
||||
primary = Core::App().separateWindowForAccount(account);
|
||||
}
|
||||
const auto primary = Core::App().activePrimaryWindow();
|
||||
if (&primary->account() != &session().account()) {
|
||||
primary->showAccount(&session().account());
|
||||
}
|
||||
if (&primary->account() == &session().account()) {
|
||||
if (primary && &primary->account() == account) {
|
||||
primary->sessionController()->showPeerHistory(
|
||||
peerId,
|
||||
params,
|
||||
showAtMsgId);
|
||||
primary->activate();
|
||||
}
|
||||
primary->activate();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -194,7 +194,6 @@ void MainWindow::setupPasscodeLock() {
|
||||
_passcodeLock.create(bodyWidget(), &controller());
|
||||
updateControlsGeometry();
|
||||
|
||||
Core::App().hideMediaView();
|
||||
ui_hideSettingsAndLayer(anim::type::instant);
|
||||
if (_main) {
|
||||
_main->hide();
|
||||
|
||||
@@ -3380,6 +3380,13 @@ void OverlayWidget::switchToPip() {
|
||||
}) | rpl::start_with_next([=] {
|
||||
_pip = nullptr;
|
||||
}, _pip->lifetime);
|
||||
|
||||
Core::App().passcodeLockChanges(
|
||||
) | rpl::filter(
|
||||
rpl::mappers::_1
|
||||
) | rpl::start_with_next([=] {
|
||||
_pip = nullptr;
|
||||
}, _pip->lifetime);
|
||||
}
|
||||
|
||||
if (isHidden()) {
|
||||
|
||||
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "stripe/stripe_card.h"
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
|
||||
class QDate;
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ public:
|
||||
|
||||
private:
|
||||
void initHook() override;
|
||||
void initHighDpi() override;
|
||||
|
||||
bool launchUpdater(UpdaterLaunch action) override;
|
||||
|
||||
|
||||
@@ -27,11 +27,6 @@ void Launcher::initHook() {
|
||||
base::RegisterBundledResources(u"Telegram.rcc"_q);
|
||||
}
|
||||
|
||||
void Launcher::initHighDpi() {
|
||||
// macOS Retina display support is working fine.
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);
|
||||
}
|
||||
|
||||
bool Launcher::launchUpdater(UpdaterLaunch action) {
|
||||
if (cExeName().isEmpty()) {
|
||||
return false;
|
||||
|
||||
@@ -226,7 +226,7 @@ MainWindow::MainWindow(not_null<Window::Controller*> controller)
|
||||
void MainWindow::closeWithoutDestroy() {
|
||||
NSWindow *nsWindow = [reinterpret_cast<NSView*>(winId()) window];
|
||||
|
||||
auto isFullScreen = (([nsWindow styleMask] & NSFullScreenWindowMask) == NSFullScreenWindowMask);
|
||||
auto isFullScreen = (([nsWindow styleMask] & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen);
|
||||
if (isFullScreen) {
|
||||
_hideAfterFullScreenTimer.callOnce(kHideAfterFullscreenTimeoutMs);
|
||||
[nsWindow toggleFullScreen:nsWindow];
|
||||
@@ -266,7 +266,7 @@ bool MainWindow::preventsQuit(Core::QuitReason reason) {
|
||||
// chromium.org/developers/design-documents/confirm-to-quit-experiment
|
||||
return (reason == Core::QuitReason::QtQuitEvent)
|
||||
&& Core::App().settings().macWarnBeforeQuit()
|
||||
&& ([[NSApp currentEvent] type] == NSKeyDown)
|
||||
&& ([[NSApp currentEvent] type] == NSEventTypeKeyDown)
|
||||
&& !Platform::ConfirmQuit::RunModal(
|
||||
tr::lng_mac_hold_to_quit(
|
||||
tr::now,
|
||||
|
||||
@@ -266,7 +266,10 @@ void SetApplicationIcon(const QIcon &icon) {
|
||||
void objc_debugShowAlert(const QString &str) {
|
||||
@autoreleasepool {
|
||||
|
||||
[[NSAlert alertWithMessageText:@"Debug Message" defaultButton:@"OK" alternateButton:nil otherButton:nil informativeTextWithFormat:@"%@", Q2NSString(str)] runModal];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
alert.messageText = @"Debug Message";
|
||||
alert.informativeText = Q2NSString(str);
|
||||
[alert runModal];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -513,6 +513,12 @@ settingsPremiumUserAbout: FlatLabel(boxDividerLabel) {
|
||||
settingsPremiumLock: icon{{ "emoji/premium_lock", windowActiveTextFg, point(0px, 1px) }};
|
||||
settingsPremiumLockSkip: 3px;
|
||||
|
||||
settingsBlockedListSubtitleAddPadding: margins(0px, 1px, 0px, -4px);
|
||||
settingsBlockedListIconPadding: margins(0px, 34px, 0px, 5px);
|
||||
settingsBlockedList: PeerList(peerListBox) {
|
||||
padding: margins(0px, 0px, 0px, membersMarginBottom);
|
||||
}
|
||||
|
||||
requestPeerRestriction: FlatLabel(defaultFlatLabel) {
|
||||
minWidth: 240px;
|
||||
textFg: membersAboutLimitFg;
|
||||
|
||||
@@ -98,7 +98,7 @@ QPointer<Ui::RpWidget> Blocked::createPinnedToTop(not_null<QWidget*> parent) {
|
||||
AddSubsectionTitle(
|
||||
subtitle->entity(),
|
||||
rpl::duplicate(subtitleText),
|
||||
st::blockedUsersListSubtitleAddPadding);
|
||||
st::settingsBlockedListSubtitleAddPadding);
|
||||
subtitle->toggleOn(
|
||||
rpl::merge(
|
||||
_emptinessChanges.events() | rpl::map(!rpl::mappers::_1),
|
||||
@@ -134,6 +134,7 @@ void Blocked::setupContent() {
|
||||
};
|
||||
|
||||
auto controller = std::make_unique<BlockedBoxController>(_controller);
|
||||
controller->setStyleOverrides(&st::settingsBlockedList);
|
||||
const auto content = listWrap->entity()->add(
|
||||
object_ptr<PeerListContent>(this, controller.get()));
|
||||
|
||||
@@ -171,7 +172,7 @@ void Blocked::setupContent() {
|
||||
st::changePhoneIconSize,
|
||||
},
|
||||
},
|
||||
st::blockedUsersListIconPadding);
|
||||
st::settingsBlockedListIconPadding);
|
||||
content->add(std::move(icon.widget));
|
||||
|
||||
_showFinished.events(
|
||||
@@ -197,7 +198,7 @@ void Blocked::setupContent() {
|
||||
st::changePhoneDescription)),
|
||||
st::changePhoneDescriptionPadding);
|
||||
|
||||
AddSkip(content, st::blockedUsersListIconPadding.top());
|
||||
AddSkip(content, st::settingsBlockedListIconPadding.top());
|
||||
}
|
||||
|
||||
Ui::ResizeFitChild(this, _container);
|
||||
|
||||
@@ -689,7 +689,7 @@ void SetupAccountsWrap(
|
||||
|
||||
if (!locked) {
|
||||
addAction(tr::lng_menu_activate(tr::now), [=] {
|
||||
Core::App().domain().activate(&session->account());
|
||||
callback({});
|
||||
}, &st::menuIconProfile);
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtGui/QWindow>
|
||||
|
||||
namespace Settings {
|
||||
namespace {
|
||||
@@ -474,8 +475,9 @@ void SetupInterfaceScale(
|
||||
if constexpr (Platform::IsMac()) {
|
||||
return QString::number(scale) + '%';
|
||||
} else {
|
||||
const auto ratio = window->widget()->devicePixelRatioF();
|
||||
return QString::number(int(scale * ratio)) + '%';
|
||||
const auto handle = window->widget()->windowHandle();
|
||||
const auto ratio = handle->devicePixelRatio();
|
||||
return QString::number(base::SafeRound(scale * ratio)) + '%';
|
||||
}
|
||||
};
|
||||
label->setText(labelText(cEvalScale(scale)));
|
||||
|
||||
@@ -1053,7 +1053,7 @@ void FileLoadTask::process(Args &&args) {
|
||||
if (image->modifications.paint) {
|
||||
const auto documents = ExtractStickersFromScene(image);
|
||||
_result->attachedStickers = documents
|
||||
| ranges::view::transform(&DocumentData::mtpInput)
|
||||
| ranges::views::transform(&DocumentData::mtpInput)
|
||||
| ranges::to_vector;
|
||||
}
|
||||
}
|
||||
|
||||
2
Telegram/ThirdParty/GSL
vendored
2
Telegram/ThirdParty/GSL
vendored
Submodule Telegram/ThirdParty/GSL updated: 0f6dbc9e29...a353456718
2
Telegram/ThirdParty/kimageformats
vendored
2
Telegram/ThirdParty/kimageformats
vendored
Submodule Telegram/ThirdParty/kimageformats updated: 05bd9397b3...63056c52f9
@@ -95,12 +95,12 @@ if %Build64% neq 0 (
|
||||
set "UpdateFile=tx64upd%AppVersion%"
|
||||
set "SetupFile=tsetup-x64.%AppVersionStrFull%.exe"
|
||||
set "PortableFile=tportable-x64.%AppVersionStrFull%.zip"
|
||||
set "DumpSymsPath=%SolutionPath%\..\..\Libraries\win64\breakpad\src\out\Release_x64\dump_syms.exe"
|
||||
set "DumpSymsPath=%SolutionPath%\..\..\Libraries\win64\breakpad\src\tools\windows\dump_syms\Release\dump_syms.exe"
|
||||
) else (
|
||||
set "UpdateFile=tupdate%AppVersion%"
|
||||
set "SetupFile=tsetup.%AppVersionStrFull%.exe"
|
||||
set "PortableFile=tportable.%AppVersionStrFull%.zip"
|
||||
set "DumpSymsPath=%SolutionPath%\..\..\Libraries\breakpad\src\out\Release\dump_syms.exe"
|
||||
set "DumpSymsPath=%SolutionPath%\..\..\Libraries\breakpad\src\tools\windows\dump_syms\Release\dump_syms.exe"
|
||||
)
|
||||
set "ReleasePath=%SolutionPath%\Release"
|
||||
set "DeployPath=%ReleasePath%\deploy\%AppVersionStrMajor%\%AppVersionStrFull%"
|
||||
|
||||
@@ -710,9 +710,8 @@ release:
|
||||
|
||||
stage('libde265', """
|
||||
win:
|
||||
git clone https://github.com/strukturag/libde265.git
|
||||
git clone --depth 1 -b v1.0.11 https://github.com/strukturag/libde265.git
|
||||
cd libde265
|
||||
git checkout c96962cf6a0259f1678e9a0e1566eb9b5516093a
|
||||
cmake . ^
|
||||
-A %WIN32X64% ^
|
||||
-DCMAKE_INSTALL_PREFIX=%LIBS_DIR%/local ^
|
||||
@@ -735,7 +734,7 @@ release:
|
||||
|
||||
stage('libheif', """
|
||||
win:
|
||||
git clone --depth 1 -b v1.14.0 https://github.com/strukturag/libheif.git
|
||||
git clone --depth 1 -b v1.14.2 https://github.com/strukturag/libheif.git
|
||||
cd libheif
|
||||
%THIRDPARTY_DIR%\\msys64\\usr\\bin\\sed.exe -i 's/LIBHEIF_EXPORTS/LIBDE265_STATIC_BUILD/g' libheif/CMakeLists.txt
|
||||
%THIRDPARTY_DIR%\\msys64\\usr\\bin\\sed.exe -i 's/HAVE_VISIBILITY/LIBHEIF_STATIC_BUILD/g' libheif/CMakeLists.txt
|
||||
@@ -761,7 +760,7 @@ release:
|
||||
|
||||
stage('libjxl', """
|
||||
win:
|
||||
git clone -b v0.7.0 --depth 1 --recursive --shallow-submodules https://github.com/libjxl/libjxl.git
|
||||
git clone -b v0.8.1 --depth 1 --recursive --shallow-submodules https://github.com/libjxl/libjxl.git
|
||||
cd libjxl
|
||||
cmake . ^
|
||||
-A %WIN32X64% ^
|
||||
@@ -781,6 +780,7 @@ win:
|
||||
-DJPEGXL_ENABLE_MANPAGES=OFF ^
|
||||
-DJPEGXL_ENABLE_EXAMPLES=OFF ^
|
||||
-DJPEGXL_ENABLE_JNI=OFF ^
|
||||
-DJPEGXL_ENABLE_JPEGLI_LIBJPEG=OFF ^
|
||||
-DJPEGXL_ENABLE_SJPEG=OFF ^
|
||||
-DJPEGXL_ENABLE_OPENEXR=OFF ^
|
||||
-DJPEGXL_ENABLE_SKCMS=ON ^
|
||||
@@ -1105,9 +1105,8 @@ depends:python/Scripts/activate.bat
|
||||
release:
|
||||
ninja -C out/Release%FolderPostfix% common crash_generation_client exception_handler
|
||||
cd tools\\windows\\dump_syms
|
||||
gyp dump_syms.gyp --format=ninja
|
||||
cd ..\\..\\..
|
||||
ninja -C out/Release%FolderPostfix% dump_syms
|
||||
gyp dump_syms.gyp --format=msvs
|
||||
msbuild dump_syms.vcxproj /property:Configuration=Release /property:Platform="x64"
|
||||
win:
|
||||
deactivate
|
||||
mac:
|
||||
|
||||
@@ -163,6 +163,12 @@ if not os.path.isdir(local_folder):
|
||||
local_folder = local_folder + '/'
|
||||
|
||||
files = []
|
||||
files.append({
|
||||
'local': 'sources',
|
||||
'remote': 'tdesktop-' + version + '-full.tar.gz',
|
||||
'mime': 'application/x-gzip',
|
||||
'label': 'Source code (tar.gz, full)',
|
||||
})
|
||||
files.append({
|
||||
'local': 'tsetup.' + version_full + '.exe',
|
||||
'remote': 'tsetup.' + version_full + '.exe',
|
||||
@@ -205,12 +211,6 @@ files.append({
|
||||
'mime': 'application/octet-stream',
|
||||
'label': 'Linux 64 bit: Binary',
|
||||
})
|
||||
files.append({
|
||||
'local': 'sources',
|
||||
'remote': 'tdesktop-' + version + '-full.tar.gz',
|
||||
'mime': 'application/x-gzip',
|
||||
'label': 'Source code (tar.gz, full)',
|
||||
})
|
||||
|
||||
r = requests.get(url + 'repos/telegramdesktop/tdesktop/releases/tags/v' + version)
|
||||
if r.status_code == 404:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
AppVersion 4006002
|
||||
AppVersion 4006003
|
||||
AppVersionStrMajor 4.6
|
||||
AppVersionStrSmall 4.6.2
|
||||
AppVersionStr 4.6.2
|
||||
AppVersionStrSmall 4.6.3
|
||||
AppVersionStr 4.6.3
|
||||
BetaChannel 0
|
||||
AlphaVersion 0
|
||||
AppVersionOriginal 4.6.2
|
||||
AppVersionOriginal 4.6.3
|
||||
|
||||
@@ -241,13 +241,12 @@ elseif (APPLE)
|
||||
)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
target_compile_options(lib_tgcalls
|
||||
PRIVATE
|
||||
-Wno-deprecated-volatile
|
||||
-Wno-ambiguous-reversed-operator
|
||||
)
|
||||
endif()
|
||||
target_compile_options_if_exists(lib_tgcalls
|
||||
PRIVATE
|
||||
-Wno-deprecated-volatile
|
||||
-Wno-ambiguous-reversed-operator
|
||||
-Wno-deprecated-declarations
|
||||
)
|
||||
|
||||
remove_target_sources(lib_tgcalls ${tgcalls_loc}
|
||||
platform/android/AndroidContext.cpp
|
||||
|
||||
Submodule Telegram/lib_base updated: 33d846fc2d...2e306a7245
Submodule Telegram/lib_rpl updated: fd31f5bf38...bc7b4cae2e
Submodule Telegram/lib_ui updated: 66e47a0240...a56831e8d0
@@ -1,3 +1,8 @@
|
||||
4.6.3 (15.02.23)
|
||||
|
||||
- Optimize chats list initial loading.
|
||||
- Various crash fixes.
|
||||
|
||||
4.6.2 (07.02.23)
|
||||
|
||||
- One more attempt to fix fonts on Windows.
|
||||
|
||||
2
cmake
2
cmake
Submodule cmake updated: 17951fb650...86270a961e
Reference in New Issue
Block a user