Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b03fd0f23 | ||
|
|
9f117cd680 | ||
|
|
f6d29991d6 | ||
|
|
1a0d430291 | ||
|
|
e3b9927faa | ||
|
|
d199e16a6e | ||
|
|
01c2be3f01 | ||
|
|
6db537d1ec | ||
|
|
e708b2d39c | ||
|
|
ebd9587821 | ||
|
|
9e5117d336 | ||
|
|
1c2ea8d84a | ||
|
|
235484b719 | ||
|
|
b9ea5718a2 | ||
|
|
db0c57a186 | ||
|
|
0fa458737a | ||
|
|
caaeff32c5 | ||
|
|
c4c234f0d3 | ||
|
|
894e7c5828 | ||
|
|
afcebb136c | ||
|
|
8592326a3c |
@@ -1526,8 +1526,8 @@ endif()
|
||||
|
||||
if (LINUX AND DESKTOP_APP_USE_PACKAGED)
|
||||
include(GNUInstallDirs)
|
||||
configure_file("../lib/xdg/telegramdesktop.appdata.xml.in" "${CMAKE_CURRENT_BINARY_DIR}/telegramdesktop.appdata.xml" @ONLY)
|
||||
generate_appdata_changelog(Telegram "${CMAKE_SOURCE_DIR}/changelog.txt" "${CMAKE_CURRENT_BINARY_DIR}/telegramdesktop.appdata.xml")
|
||||
configure_file("../lib/xdg/telegramdesktop.metainfo.xml.in" "${CMAKE_CURRENT_BINARY_DIR}/telegramdesktop.metainfo.xml" @ONLY)
|
||||
generate_appdata_changelog(Telegram "${CMAKE_SOURCE_DIR}/changelog.txt" "${CMAKE_CURRENT_BINARY_DIR}/telegramdesktop.metainfo.xml")
|
||||
install(TARGETS Telegram RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" BUNDLE DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
||||
install(FILES "Resources/art/icon16.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/16x16/apps" RENAME "telegram.png")
|
||||
install(FILES "Resources/art/icon32.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/32x32/apps" RENAME "telegram.png")
|
||||
@@ -1537,5 +1537,5 @@ if (LINUX AND DESKTOP_APP_USE_PACKAGED)
|
||||
install(FILES "Resources/art/icon256.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/256x256/apps" RENAME "telegram.png")
|
||||
install(FILES "Resources/art/icon512.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/512x512/apps" RENAME "telegram.png")
|
||||
install(FILES "../lib/xdg/telegramdesktop.desktop" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications" RENAME "${TDESKTOP_LAUNCHER_BASENAME}.desktop")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/telegramdesktop.appdata.xml" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/metainfo" RENAME "${TDESKTOP_LAUNCHER_BASENAME}.appdata.xml")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/telegramdesktop.metainfo.xml" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/metainfo" RENAME "${TDESKTOP_LAUNCHER_BASENAME}.metainfo.xml")
|
||||
endif()
|
||||
|
||||
|
Before Width: | Height: | Size: 277 B After Width: | Height: | Size: 277 B |
|
Before Width: | Height: | Size: 482 B After Width: | Height: | Size: 482 B |
|
Before Width: | Height: | Size: 715 B After Width: | Height: | Size: 715 B |
|
Before Width: | Height: | Size: 173 B After Width: | Height: | Size: 173 B |
|
Before Width: | Height: | Size: 255 B After Width: | Height: | Size: 255 B |
|
Before Width: | Height: | Size: 344 B After Width: | Height: | Size: 344 B |
|
Before Width: | Height: | Size: 197 B After Width: | Height: | Size: 197 B |
|
Before Width: | Height: | Size: 273 B After Width: | Height: | Size: 273 B |
|
Before Width: | Height: | Size: 393 B After Width: | Height: | Size: 393 B |
|
Before Width: | Height: | Size: 253 B After Width: | Height: | Size: 253 B |
|
Before Width: | Height: | Size: 433 B After Width: | Height: | Size: 433 B |
|
Before Width: | Height: | Size: 494 B After Width: | Height: | Size: 494 B |
|
Before Width: | Height: | Size: 265 B After Width: | Height: | Size: 265 B |
|
Before Width: | Height: | Size: 490 B After Width: | Height: | Size: 490 B |
|
Before Width: | Height: | Size: 578 B After Width: | Height: | Size: 578 B |
|
Before Width: | Height: | Size: 285 B After Width: | Height: | Size: 285 B |
|
Before Width: | Height: | Size: 444 B After Width: | Height: | Size: 444 B |
|
Before Width: | Height: | Size: 598 B After Width: | Height: | Size: 598 B |
|
Before Width: | Height: | Size: 128 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 247 B After Width: | Height: | Size: 247 B |
|
Before Width: | Height: | Size: 350 B After Width: | Height: | Size: 350 B |
|
Before Width: | Height: | Size: 146 B After Width: | Height: | Size: 146 B |
|
Before Width: | Height: | Size: 289 B After Width: | Height: | Size: 289 B |
|
Before Width: | Height: | Size: 386 B After Width: | Height: | Size: 386 B |
|
Before Width: | Height: | Size: 170 B After Width: | Height: | Size: 170 B |
|
Before Width: | Height: | Size: 362 B After Width: | Height: | Size: 362 B |
|
Before Width: | Height: | Size: 488 B After Width: | Height: | Size: 488 B |
|
Before Width: | Height: | Size: 387 B After Width: | Height: | Size: 387 B |
|
Before Width: | Height: | Size: 638 B After Width: | Height: | Size: 638 B |
|
Before Width: | Height: | Size: 907 B After Width: | Height: | Size: 907 B |
|
Before Width: | Height: | Size: 158 B After Width: | Height: | Size: 158 B |
|
Before Width: | Height: | Size: 309 B After Width: | Height: | Size: 309 B |
|
Before Width: | Height: | Size: 321 B After Width: | Height: | Size: 321 B |
|
Before Width: | Height: | Size: 367 B After Width: | Height: | Size: 367 B |
|
Before Width: | Height: | Size: 1013 B After Width: | Height: | Size: 1013 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 223 B After Width: | Height: | Size: 223 B |
|
Before Width: | Height: | Size: 432 B After Width: | Height: | Size: 432 B |
|
Before Width: | Height: | Size: 512 B After Width: | Height: | Size: 512 B |
|
Before Width: | Height: | Size: 145 B After Width: | Height: | Size: 145 B |
|
Before Width: | Height: | Size: 261 B After Width: | Height: | Size: 261 B |
|
Before Width: | Height: | Size: 272 B After Width: | Height: | Size: 272 B |
|
Before Width: | Height: | Size: 287 B After Width: | Height: | Size: 287 B |
|
Before Width: | Height: | Size: 450 B After Width: | Height: | Size: 450 B |
|
Before Width: | Height: | Size: 578 B After Width: | Height: | Size: 578 B |
BIN
Telegram/Resources/icons/dialogs/dialogs_verified_check.png
Normal file
|
After Width: | Height: | Size: 233 B |
BIN
Telegram/Resources/icons/dialogs/dialogs_verified_check@2x.png
Normal file
|
After Width: | Height: | Size: 365 B |
BIN
Telegram/Resources/icons/dialogs/dialogs_verified_check@3x.png
Normal file
|
After Width: | Height: | Size: 425 B |
BIN
Telegram/Resources/icons/dialogs/dialogs_verified_star.png
Normal file
|
After Width: | Height: | Size: 371 B |
BIN
Telegram/Resources/icons/dialogs/dialogs_verified_star@2x.png
Normal file
|
After Width: | Height: | Size: 714 B |
BIN
Telegram/Resources/icons/dialogs/dialogs_verified_star@3x.png
Normal file
|
After Width: | Height: | Size: 803 B |
|
Before Width: | Height: | Size: 180 B |
|
Before Width: | Height: | Size: 281 B |
|
Before Width: | Height: | Size: 404 B |
|
Before Width: | Height: | Size: 342 B |
|
Before Width: | Height: | Size: 660 B |
|
Before Width: | Height: | Size: 694 B |
@@ -10,7 +10,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="3.2.8.0" />
|
||||
Version="3.3.0.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||
|
||||
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,2,8,0
|
||||
PRODUCTVERSION 3,2,8,0
|
||||
FILEVERSION 3,3,0,0
|
||||
PRODUCTVERSION 3,3,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -62,10 +62,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "3.2.8.0"
|
||||
VALUE "FileVersion", "3.3.0.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2021"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "3.2.8.0"
|
||||
VALUE "ProductVersion", "3.3.0.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,2,8,0
|
||||
PRODUCTVERSION 3,2,8,0
|
||||
FILEVERSION 3,3,0,0
|
||||
PRODUCTVERSION 3,3,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -53,10 +53,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop Updater"
|
||||
VALUE "FileVersion", "3.2.8.0"
|
||||
VALUE "FileVersion", "3.3.0.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2021"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "3.2.8.0"
|
||||
VALUE "ProductVersion", "3.3.0.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -8,7 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <cstdio>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include <cstdlib>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
@@ -98,6 +97,11 @@ bool copyFile(const char *from, const char *to, bool writeprotected) {
|
||||
fclose(ffrom);
|
||||
return false;
|
||||
}
|
||||
static const int BufSize = 65536;
|
||||
char buf[BufSize];
|
||||
while (size_t size = fread(buf, 1, BufSize, ffrom)) {
|
||||
fwrite(buf, 1, size, fto);
|
||||
}
|
||||
|
||||
struct stat fst; // from http://stackoverflow.com/questions/5486774/keeping-fileowner-and-permissions-after-copying-file-in-c
|
||||
//let's say this wont fail since you already worked OK on that fp
|
||||
@@ -106,33 +110,6 @@ bool copyFile(const char *from, const char *to, bool writeprotected) {
|
||||
fclose(fto);
|
||||
return false;
|
||||
}
|
||||
|
||||
ssize_t copied = sendfile(
|
||||
fileno(fto),
|
||||
fileno(ffrom),
|
||||
nullptr,
|
||||
fst.st_size);
|
||||
|
||||
if (copied == -1) {
|
||||
writeLog(
|
||||
"Copy by sendfile '%s' to '%s' failed, error: %d, fallback now.",
|
||||
from,
|
||||
to,
|
||||
int(errno));
|
||||
static const int BufSize = 65536;
|
||||
char buf[BufSize];
|
||||
while (size_t size = fread(buf, 1, BufSize, ffrom)) {
|
||||
fwrite(buf, 1, size, fto);
|
||||
}
|
||||
} else {
|
||||
writeLog(
|
||||
"Copy by sendfile '%s' to '%s' done, size: %d, result: %d.",
|
||||
from,
|
||||
to,
|
||||
int(fst.st_size),
|
||||
int(copied));
|
||||
}
|
||||
|
||||
//update to the same uid/gid
|
||||
if (!writeprotected && fchown(fileno(fto), fst.st_uid, fst.st_gid) != 0) {
|
||||
fclose(ffrom);
|
||||
|
||||
@@ -662,7 +662,7 @@ UserData *ParticipantsAdditionalData::applyCreator(
|
||||
} else {
|
||||
_adminCanEdit.erase(user);
|
||||
}
|
||||
if (data.rank().isEmpty()) {
|
||||
if (!data.rank().isEmpty()) {
|
||||
_adminRanks[user] = data.rank();
|
||||
} else {
|
||||
_adminRanks.remove(user);
|
||||
@@ -693,7 +693,7 @@ UserData *ParticipantsAdditionalData::applyAdmin(
|
||||
} else {
|
||||
_adminCanEdit.erase(user);
|
||||
}
|
||||
if (data.rank().isEmpty()) {
|
||||
if (!data.rank().isEmpty()) {
|
||||
_adminRanks[user] = data.rank();
|
||||
} else {
|
||||
_adminRanks.remove(user);
|
||||
|
||||
@@ -78,8 +78,8 @@ public:
|
||||
: tr::lng_manage_peer_channel_type();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isAllowSave() {
|
||||
return _isAllowSave;
|
||||
[[nodiscard]] bool goodUsername() const {
|
||||
return _goodUsername;
|
||||
}
|
||||
|
||||
[[nodiscard]] Privacy getPrivacy() const {
|
||||
@@ -144,7 +144,7 @@ private:
|
||||
|
||||
bool _useLocationPhrases = false;
|
||||
bool _isGroup = false;
|
||||
bool _isAllowSave = false;
|
||||
bool _goodUsername = false;
|
||||
|
||||
base::unique_qptr<Ui::VerticalLayout> _wrap;
|
||||
base::Timer _checkUsernameTimer;
|
||||
@@ -171,7 +171,8 @@ Controller::Controller(
|
||||
, _noForwardsSavedValue(noForwardsSavedValue)
|
||||
, _useLocationPhrases(useLocationPhrases)
|
||||
, _isGroup(_peer->isChat() || _peer->isMegagroup())
|
||||
, _isAllowSave(!_usernameSavedValue.value_or(QString()).isEmpty())
|
||||
, _goodUsername(!_usernameSavedValue.value_or(
|
||||
_peer->isChannel() ? _peer->asChannel()->username : QString()).isEmpty())
|
||||
, _wrap(container)
|
||||
, _checkUsernameTimer([=] { checkUsernameAvailability(); }) {
|
||||
_peer->updateFull();
|
||||
@@ -236,7 +237,8 @@ void Controller::createContent() {
|
||||
if (_controls.privacy->value() == Privacy::NoUsername) {
|
||||
checkUsernameAvailability();
|
||||
}
|
||||
const auto forShowing = _privacySavedValue.value_or(Privacy::NoUsername);
|
||||
const auto forShowing = _privacySavedValue.value_or(
|
||||
Privacy::NoUsername);
|
||||
_controls.inviteLinkWrap->toggle(
|
||||
(forShowing != Privacy::HasUsername),
|
||||
anim::type::instant);
|
||||
@@ -333,8 +335,8 @@ object_ptr<Ui::RpWidget> Controller::createUsernameEdit() {
|
||||
Expects(_wrap != nullptr);
|
||||
|
||||
const auto channel = _peer->asChannel();
|
||||
const auto username =
|
||||
_usernameSavedValue.value_or(channel ? channel->username : QString());
|
||||
const auto username = _usernameSavedValue.value_or(
|
||||
channel ? channel->username : QString());
|
||||
|
||||
auto result = object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||
_wrap,
|
||||
@@ -505,7 +507,7 @@ void Controller::askUsernameRevoke() {
|
||||
}
|
||||
|
||||
void Controller::usernameChanged() {
|
||||
_isAllowSave = false;
|
||||
_goodUsername = false;
|
||||
const auto username = getUsernameInput();
|
||||
if (username.isEmpty()) {
|
||||
_controls.usernameResult = nullptr;
|
||||
@@ -529,12 +531,12 @@ void Controller::usernameChanged() {
|
||||
}
|
||||
|
||||
void Controller::showUsernameError(rpl::producer<QString> &&error) {
|
||||
_isAllowSave = false;
|
||||
_goodUsername = false;
|
||||
showUsernameResult(std::move(error), &st::editPeerUsernameError);
|
||||
}
|
||||
|
||||
void Controller::showUsernameGood() {
|
||||
_isAllowSave = true;
|
||||
_goodUsername = true;
|
||||
showUsernameResult(
|
||||
tr::lng_create_channel_link_available(),
|
||||
&st::editPeerUsernameGood);
|
||||
@@ -655,7 +657,7 @@ void EditPeerTypeBox::prepare() {
|
||||
if (_savedCallback.has_value()) {
|
||||
addButton(tr::lng_settings_save(), [=] {
|
||||
const auto v = controller->getPrivacy();
|
||||
if (!controller->isAllowSave() && (v == Privacy::HasUsername)) {
|
||||
if ((v == Privacy::HasUsername) && !controller->goodUsername()) {
|
||||
controller->setFocusUsername();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -550,11 +550,6 @@ QRect Row::elementGeometry(int element, int outerWidth) const {
|
||||
const auto size = QSize(
|
||||
st::sessionTerminate.width,
|
||||
st::sessionTerminate.height);
|
||||
const auto margins = QMargins(
|
||||
0,
|
||||
(st::sessionListItem.height - size.height()) / 2,
|
||||
st::sessionListThreeDotsSkip,
|
||||
0);
|
||||
const auto right = st::sessionTerminateSkip;
|
||||
const auto top = st::sessionTerminateTop;
|
||||
const auto left = outerWidth - right - size.width();
|
||||
|
||||
@@ -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 = 3002008;
|
||||
constexpr auto AppVersionStr = "3.2.8";
|
||||
constexpr auto AppBetaVersion = true;
|
||||
constexpr auto AppVersion = 3003000;
|
||||
constexpr auto AppVersionStr = "3.3";
|
||||
constexpr auto AppBetaVersion = false;
|
||||
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
|
||||
|
||||
@@ -99,13 +99,19 @@ bool CloudImage::failed() const {
|
||||
return (_file.flags & CloudFile::Flag::Failed);
|
||||
}
|
||||
|
||||
bool CloudImage::loadedOnce() const {
|
||||
return (_file.flags & CloudFile::Flag::Loaded);
|
||||
}
|
||||
|
||||
void CloudImage::load(not_null<Main::Session*> session, FileOrigin origin) {
|
||||
const auto autoLoading = false;
|
||||
const auto finalCheck = [=] {
|
||||
if (const auto active = activeView()) {
|
||||
return !active->image();
|
||||
} else if (_file.flags & CloudFile::Flag::Loaded) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return !(_file.flags & CloudFile::Flag::Loaded);
|
||||
};
|
||||
const auto done = [=](QImage result) {
|
||||
if (const auto active = activeView()) {
|
||||
@@ -247,6 +253,7 @@ void LoadCloudFile(
|
||||
if (!file.loader || file.loader->cancelled()) {
|
||||
file.flags |= CloudFile::Flag::Cancelled;
|
||||
} else {
|
||||
file.flags |= CloudFile::Flag::Loaded;
|
||||
done(file);
|
||||
}
|
||||
// NB! file.loader may be in ~FileLoader() already.
|
||||
|
||||
@@ -31,6 +31,7 @@ struct CloudFile final {
|
||||
enum class Flag : uchar {
|
||||
Cancelled = 0x01,
|
||||
Failed = 0x02,
|
||||
Loaded = 0x04,
|
||||
};
|
||||
friend inline constexpr bool is_flag_type(Flag) { return true; };
|
||||
|
||||
@@ -73,6 +74,7 @@ public:
|
||||
[[nodiscard]] bool empty() const;
|
||||
[[nodiscard]] bool loading() const;
|
||||
[[nodiscard]] bool failed() const;
|
||||
[[nodiscard]] bool loadedOnce() const;
|
||||
void load(not_null<Main::Session*> session, FileOrigin origin);
|
||||
[[nodiscard]] const ImageLocation &location() const;
|
||||
[[nodiscard]] int byteSize() const;
|
||||
|
||||
@@ -1084,13 +1084,19 @@ bool DocumentData::isStickerSetInstalled() const {
|
||||
}
|
||||
}
|
||||
|
||||
Image *DocumentData::getReplyPreview(Data::FileOrigin origin) {
|
||||
Image *DocumentData::getReplyPreview(
|
||||
Data::FileOrigin origin,
|
||||
not_null<PeerData*> context) {
|
||||
if (!hasThumbnail()) {
|
||||
return nullptr;
|
||||
} else if (!_replyPreview) {
|
||||
_replyPreview = std::make_unique<Data::ReplyPreview>(this);
|
||||
}
|
||||
return _replyPreview->image(origin);
|
||||
return _replyPreview->image(origin, context);
|
||||
}
|
||||
|
||||
Image *DocumentData::getReplyPreview(not_null<HistoryItem*> item) {
|
||||
return getReplyPreview(item->fullId(), item->history()->peer);
|
||||
}
|
||||
|
||||
bool DocumentData::replyPreviewLoaded() const {
|
||||
|
||||
@@ -115,7 +115,8 @@ public:
|
||||
void setWaitingForAlbum();
|
||||
[[nodiscard]] bool waitingForAlbum() const;
|
||||
|
||||
[[nodiscard]] const Core::FileLocation &location(bool check = false) const;
|
||||
[[nodiscard]] const Core::FileLocation &location(
|
||||
bool check = false) const;
|
||||
void setLocation(const Core::FileLocation &loc);
|
||||
|
||||
bool saveFromData();
|
||||
@@ -124,7 +125,10 @@ public:
|
||||
|
||||
[[nodiscard]] bool saveToCache() const;
|
||||
|
||||
[[nodiscard]] Image *getReplyPreview(Data::FileOrigin origin);
|
||||
[[nodiscard]] Image *getReplyPreview(
|
||||
Data::FileOrigin origin,
|
||||
not_null<PeerData*> context);
|
||||
[[nodiscard]] Image *getReplyPreview(not_null<HistoryItem*> item);
|
||||
[[nodiscard]] bool replyPreviewLoaded() const;
|
||||
|
||||
[[nodiscard]] StickerData *sticker() const;
|
||||
|
||||
@@ -164,18 +164,8 @@ using ItemPreviewImage = HistoryView::ItemPreviewImage;
|
||||
} else if (const auto large = media->image(PhotoSize::Large)) {
|
||||
return { PreparePreviewImage(large, radius), readyCacheKey };
|
||||
}
|
||||
const auto allowedToDownload = [&] {
|
||||
const auto photo = media->owner();
|
||||
if (media->loaded() || photo->cancelled()) {
|
||||
return false;
|
||||
}
|
||||
return photo->hasExact(PhotoSize::Small)
|
||||
|| photo->hasExact(PhotoSize::Thumbnail)
|
||||
|| AutoDownload::Should(
|
||||
photo->session().settings().autoDownload(),
|
||||
item->history()->peer,
|
||||
photo);
|
||||
}();
|
||||
const auto allowedToDownload = media->autoLoadThumbnailAllowed(
|
||||
item->history()->peer);
|
||||
const auto cacheKey = allowedToDownload ? 0 : readyCacheKey;
|
||||
if (allowedToDownload) {
|
||||
media->owner()->load(PhotoSize::Small, item->fullId());
|
||||
@@ -533,7 +523,7 @@ bool MediaPhoto::hasReplyPreview() const {
|
||||
}
|
||||
|
||||
Image *MediaPhoto::replyPreview() const {
|
||||
return _photo->getReplyPreview(parent()->fullId());
|
||||
return _photo->getReplyPreview(parent());
|
||||
}
|
||||
|
||||
bool MediaPhoto::replyPreviewLoaded() const {
|
||||
@@ -738,7 +728,7 @@ bool MediaFile::hasReplyPreview() const {
|
||||
}
|
||||
|
||||
Image *MediaFile::replyPreview() const {
|
||||
return _document->getReplyPreview(parent()->fullId());
|
||||
return _document->getReplyPreview(parent());
|
||||
}
|
||||
|
||||
bool MediaFile::replyPreviewLoaded() const {
|
||||
@@ -1295,9 +1285,9 @@ bool MediaWebPage::hasReplyPreview() const {
|
||||
|
||||
Image *MediaWebPage::replyPreview() const {
|
||||
if (const auto document = MediaWebPage::document()) {
|
||||
return document->getReplyPreview(parent()->fullId());
|
||||
return document->getReplyPreview(parent());
|
||||
} else if (const auto photo = MediaWebPage::photo()) {
|
||||
return photo->getReplyPreview(parent()->fullId());
|
||||
return photo->getReplyPreview(parent());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1368,9 +1358,9 @@ bool MediaGame::hasReplyPreview() const {
|
||||
|
||||
Image *MediaGame::replyPreview() const {
|
||||
if (const auto document = _game->document) {
|
||||
return document->getReplyPreview(parent()->fullId());
|
||||
return document->getReplyPreview(parent());
|
||||
} else if (const auto photo = _game->photo) {
|
||||
return photo->getReplyPreview(parent()->fullId());
|
||||
return photo->getReplyPreview(parent());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1478,7 +1468,7 @@ bool MediaInvoice::hasReplyPreview() const {
|
||||
|
||||
Image *MediaInvoice::replyPreview() const {
|
||||
if (const auto photo = _invoice.photo) {
|
||||
return photo->getReplyPreview(parent()->fullId());
|
||||
return photo->getReplyPreview(parent());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -795,6 +795,13 @@ QString PeerData::userName() const {
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool PeerData::isSelf() const {
|
||||
if (const auto user = asUser()) {
|
||||
return (user->flags() & UserDataFlag::Self);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PeerData::isVerified() const {
|
||||
if (const auto user = asUser()) {
|
||||
return user->isVerified();
|
||||
|
||||
@@ -164,9 +164,7 @@ public:
|
||||
[[nodiscard]] bool isChannel() const {
|
||||
return peerIsChannel(id);
|
||||
}
|
||||
[[nodiscard]] bool isSelf() const {
|
||||
return (input.type() == mtpc_inputPeerSelf);
|
||||
}
|
||||
[[nodiscard]] bool isSelf() const;
|
||||
[[nodiscard]] bool isVerified() const;
|
||||
[[nodiscard]] bool isScam() const;
|
||||
[[nodiscard]] bool isFake() const;
|
||||
|
||||
@@ -13,6 +13,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_photo_media.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "main/main_session.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "media/streaming/media_streaming_loader_local.h"
|
||||
#include "media/streaming/media_streaming_loader_mtproto.h"
|
||||
#include "mainwidget.h"
|
||||
@@ -206,11 +208,17 @@ bool PhotoData::uploading() const {
|
||||
return (uploadingData != nullptr);
|
||||
}
|
||||
|
||||
Image *PhotoData::getReplyPreview(Data::FileOrigin origin) {
|
||||
Image *PhotoData::getReplyPreview(
|
||||
Data::FileOrigin origin,
|
||||
not_null<PeerData*> context) {
|
||||
if (!_replyPreview) {
|
||||
_replyPreview = std::make_unique<Data::ReplyPreview>(this);
|
||||
}
|
||||
return _replyPreview->image(origin);
|
||||
return _replyPreview->image(origin, context);
|
||||
}
|
||||
|
||||
Image *PhotoData::getReplyPreview(not_null<HistoryItem*> item) {
|
||||
return getReplyPreview(item->fullId(), item->history()->peer);
|
||||
}
|
||||
|
||||
bool PhotoData::replyPreviewLoaded() const {
|
||||
|
||||
@@ -64,7 +64,10 @@ public:
|
||||
void setWaitingForAlbum();
|
||||
[[nodiscard]] bool waitingForAlbum() const;
|
||||
|
||||
[[nodiscard]] Image *getReplyPreview(Data::FileOrigin origin);
|
||||
[[nodiscard]] Image *getReplyPreview(
|
||||
Data::FileOrigin origin,
|
||||
not_null<PeerData*> context);
|
||||
[[nodiscard]] Image *getReplyPreview(not_null<HistoryItem*> item);
|
||||
[[nodiscard]] bool replyPreviewLoaded() const;
|
||||
|
||||
void setRemoteLocation(
|
||||
|
||||
@@ -128,6 +128,18 @@ float64 PhotoMedia::progress() const {
|
||||
: (loaded() ? 1. : 0.);
|
||||
}
|
||||
|
||||
bool PhotoMedia::autoLoadThumbnailAllowed(not_null<PeerData*> peer) const {
|
||||
if (loaded() || _owner->cancelled()) {
|
||||
return false;
|
||||
}
|
||||
return _owner->hasExact(PhotoSize::Small)
|
||||
|| _owner->hasExact(PhotoSize::Thumbnail)
|
||||
|| AutoDownload::Should(
|
||||
_owner->session().settings().autoDownload(),
|
||||
peer,
|
||||
_owner);
|
||||
}
|
||||
|
||||
void PhotoMedia::automaticLoad(
|
||||
Data::FileOrigin origin,
|
||||
const HistoryItem *item) {
|
||||
|
||||
@@ -36,6 +36,8 @@ public:
|
||||
[[nodiscard]] bool loaded() const;
|
||||
[[nodiscard]] float64 progress() const;
|
||||
|
||||
[[nodiscard]] bool autoLoadThumbnailAllowed(
|
||||
not_null<PeerData*> peer) const;
|
||||
void automaticLoad(Data::FileOrigin origin, const HistoryItem *item);
|
||||
|
||||
void collectLocalData(not_null<PhotoMedia*> local);
|
||||
|
||||
@@ -55,7 +55,9 @@ void ReplyPreview::prepare(not_null<Image*> image, Images::Options options) {
|
||||
_good = ((options & Images::Option::Blurred) == 0);
|
||||
}
|
||||
|
||||
Image *ReplyPreview::image(Data::FileOrigin origin) {
|
||||
Image *ReplyPreview::image(
|
||||
Data::FileOrigin origin,
|
||||
not_null<PeerData*> context) {
|
||||
if (_checked) {
|
||||
return _image.get();
|
||||
}
|
||||
@@ -84,8 +86,13 @@ Image *ReplyPreview::image(Data::FileOrigin origin) {
|
||||
} else {
|
||||
Assert(_photo != nullptr);
|
||||
if (!_image || !_good) {
|
||||
const auto inlineThumbnailBytes = _photo->inlineThumbnailBytes();
|
||||
if (!_photoMedia) {
|
||||
_photoMedia = _photo->createMediaView();
|
||||
}
|
||||
const auto loadThumbnail = inlineThumbnailBytes.isEmpty()
|
||||
|| _photoMedia->autoLoadThumbnailAllowed(context);
|
||||
if (loadThumbnail) {
|
||||
_photoMedia->wanted(PhotoSize::Small, origin);
|
||||
}
|
||||
if (const auto small = _photoMedia->image(PhotoSize::Small)) {
|
||||
|
||||
@@ -23,7 +23,9 @@ public:
|
||||
explicit ReplyPreview(not_null<PhotoData*> photo);
|
||||
~ReplyPreview();
|
||||
|
||||
[[nodiscard]] Image *image(Data::FileOrigin origin);
|
||||
[[nodiscard]] Image *image(
|
||||
Data::FileOrigin origin,
|
||||
not_null<PeerData*> context);
|
||||
[[nodiscard]] bool loaded() const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -85,6 +85,10 @@ std::optional<MTPmessages_Search> PrepareSearchRequest(
|
||||
}();
|
||||
const auto hash = uint64(0);
|
||||
|
||||
const auto mtpOffsetId = int(std::clamp(
|
||||
offsetId.bare,
|
||||
int64(0),
|
||||
int64(0x3FFFFFFF)));
|
||||
return MTPmessages_Search(
|
||||
MTP_flags(0),
|
||||
peer->input,
|
||||
@@ -94,7 +98,7 @@ std::optional<MTPmessages_Search> PrepareSearchRequest(
|
||||
filter,
|
||||
MTP_int(0), // min_date
|
||||
MTP_int(0), // max_date
|
||||
MTP_int(offsetId),
|
||||
MTP_int(mtpOffsetId),
|
||||
MTP_int(addOffset),
|
||||
MTP_int(limit),
|
||||
MTP_int(maxId),
|
||||
|
||||
@@ -782,10 +782,6 @@ private:
|
||||
PhotoData *photo,
|
||||
DocumentData *document);
|
||||
|
||||
void folderApplyFields(
|
||||
not_null<Folder*> folder,
|
||||
const MTPDfolder &data);
|
||||
|
||||
void setPinnedFromDialog(const Dialogs::Key &key, bool pinned);
|
||||
|
||||
NotifySettings &defaultNotifySettings(not_null<const PeerData*> peer);
|
||||
|
||||
@@ -25,7 +25,8 @@ using UpdateFlag = Data::PeerUpdate::Flag;
|
||||
} // namespace
|
||||
|
||||
UserData::UserData(not_null<Data::Session*> owner, PeerId id)
|
||||
: PeerData(owner, id) {
|
||||
: PeerData(owner, id)
|
||||
, _flags((id == owner->session().userPeerId()) ? Flag::Self : Flag(0)) {
|
||||
}
|
||||
|
||||
bool UserData::canShareThisContact() const {
|
||||
@@ -173,6 +174,19 @@ void UserData::setAccessHash(uint64 accessHash) {
|
||||
}
|
||||
}
|
||||
|
||||
void UserData::setFlags(UserDataFlags which) {
|
||||
_flags.set((flags() & UserDataFlag::Self)
|
||||
| (which & ~UserDataFlag::Self));
|
||||
}
|
||||
|
||||
void UserData::addFlags(UserDataFlags which) {
|
||||
_flags.add(which & ~UserDataFlag::Self);
|
||||
}
|
||||
|
||||
void UserData::removeFlags(UserDataFlags which) {
|
||||
_flags.remove(which & ~UserDataFlag::Self);
|
||||
}
|
||||
|
||||
void UserData::setCallsStatus(CallsStatus callsStatus) {
|
||||
if (callsStatus != _callsStatus) {
|
||||
_callsStatus = callsStatus;
|
||||
|
||||
@@ -37,6 +37,7 @@ enum class UserDataFlag {
|
||||
Support = (1 << 10),
|
||||
CanPinMessages = (1 << 11),
|
||||
DiscardMinPhoto = (1 << 12),
|
||||
Self = (1 << 13),
|
||||
};
|
||||
inline constexpr bool is_flag_type(UserDataFlag) { return true; };
|
||||
using UserDataFlags = base::flags<UserDataFlag>;
|
||||
@@ -68,21 +69,15 @@ public:
|
||||
}
|
||||
void setAccessHash(uint64 accessHash);
|
||||
|
||||
void setFlags(UserDataFlags which) {
|
||||
_flags.set(which);
|
||||
}
|
||||
void addFlags(UserDataFlags which) {
|
||||
_flags.add(which);
|
||||
}
|
||||
void removeFlags(UserDataFlags which) {
|
||||
_flags.remove(which);
|
||||
}
|
||||
auto flags() const {
|
||||
return _flags.current();
|
||||
}
|
||||
auto flagsValue() const {
|
||||
return _flags.value();
|
||||
}
|
||||
void setFlags(UserDataFlags which);
|
||||
void addFlags(UserDataFlags which);
|
||||
void removeFlags(UserDataFlags which);
|
||||
|
||||
[[nodiscard]] bool isVerified() const {
|
||||
return flags() & UserDataFlag::Verified;
|
||||
|
||||
@@ -101,8 +101,8 @@ dialogsMenuToggle: IconButton {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
|
||||
icon: icon {{ "dialogs_menu", dialogsMenuIconFg }};
|
||||
iconOver: icon {{ "dialogs_menu", dialogsMenuIconFgOver }};
|
||||
icon: icon {{ "dialogs/dialogs_menu", dialogsMenuIconFg }};
|
||||
iconOver: icon {{ "dialogs/dialogs_menu", dialogsMenuIconFgOver }};
|
||||
iconPosition: point(-1px, -1px);
|
||||
|
||||
rippleAreaPosition: point(0px, 0px);
|
||||
@@ -112,32 +112,32 @@ dialogsMenuToggle: IconButton {
|
||||
}
|
||||
}
|
||||
dialogsMenuToggleUnread: icon {
|
||||
{ "dialogs_menu_unread", dialogsMenuIconFg },
|
||||
{ "dialogs_menu_unread_dot", dialogsUnreadBg },
|
||||
{ "dialogs/dialogs_menu_unread", dialogsMenuIconFg },
|
||||
{ "dialogs/dialogs_menu_unread_dot", dialogsUnreadBg },
|
||||
};
|
||||
dialogsMenuToggleUnreadMuted: icon {
|
||||
{ "dialogs_menu_unread", dialogsMenuIconFg },
|
||||
{ "dialogs_menu_unread_dot", dialogsMenuIconFg },
|
||||
{ "dialogs/dialogs_menu_unread", dialogsMenuIconFg },
|
||||
{ "dialogs/dialogs_menu_unread_dot", dialogsMenuIconFg },
|
||||
};
|
||||
|
||||
dialogsLock: IconButton(dialogsMenuToggle) {
|
||||
icon: icon {{ "dialogs_lock", dialogsMenuIconFg }};
|
||||
iconOver: icon {{ "dialogs_lock", dialogsMenuIconFgOver }};
|
||||
icon: icon {{ "dialogs/dialogs_lock", dialogsMenuIconFg }};
|
||||
iconOver: icon {{ "dialogs/dialogs_lock", dialogsMenuIconFgOver }};
|
||||
}
|
||||
dialogsUnlockIcon: icon {{ "dialogs_unlock", dialogsMenuIconFg }};
|
||||
dialogsUnlockIconOver: icon {{ "dialogs_unlock", dialogsMenuIconFgOver }};
|
||||
dialogsUnlockIcon: icon {{ "dialogs/dialogs_unlock", dialogsMenuIconFg }};
|
||||
dialogsUnlockIconOver: icon {{ "dialogs/dialogs_unlock", dialogsMenuIconFgOver }};
|
||||
dialogsCalendar: IconButton {
|
||||
width: 29px;
|
||||
height: 32px;
|
||||
|
||||
icon: icon {{ "dialogs_calendar", dialogsMenuIconFg }};
|
||||
iconOver: icon {{ "dialogs_calendar", dialogsMenuIconFgOver }};
|
||||
icon: icon {{ "dialogs/dialogs_calendar", dialogsMenuIconFg }};
|
||||
iconOver: icon {{ "dialogs/dialogs_calendar", dialogsMenuIconFgOver }};
|
||||
iconPosition: point(0px, 5px);
|
||||
}
|
||||
dialogsSearchFrom: IconButton(dialogsCalendar) {
|
||||
width: 26px;
|
||||
icon: icon {{ "dialogs_search_from", dialogsMenuIconFg }};
|
||||
iconOver: icon {{ "dialogs_search_from", dialogsMenuIconFgOver }};
|
||||
icon: icon {{ "dialogs/dialogs_search_from", dialogsMenuIconFg }};
|
||||
iconOver: icon {{ "dialogs/dialogs_search_from", dialogsMenuIconFgOver }};
|
||||
}
|
||||
dialogsSearchForNarrowFilters: IconButton(dialogsMenuToggle) {
|
||||
icon: icon {{ "top_bar_search", menuIconFg }};
|
||||
@@ -154,8 +154,8 @@ dialogsFilter: FlatInput(defaultFlatInput) {
|
||||
textMrg: margins(12px, 3px, 30px, 3px);
|
||||
}
|
||||
dialogsCancelSearchInPeer: IconButton(dialogsMenuToggle) {
|
||||
icon: icon {{ "dialogs_cancel_search", dialogsMenuIconFg }};
|
||||
iconOver: icon {{ "dialogs_cancel_search", dialogsMenuIconFgOver }};
|
||||
icon: icon {{ "dialogs/dialogs_cancel_search", dialogsMenuIconFg }};
|
||||
iconOver: icon {{ "dialogs/dialogs_cancel_search", dialogsMenuIconFgOver }};
|
||||
iconPosition: point(11px, 11px);
|
||||
rippleAreaPosition: point(3px, 3px);
|
||||
rippleAreaSize: 34px;
|
||||
@@ -180,49 +180,49 @@ dialogsCancelSearch: CrossButton {
|
||||
}
|
||||
|
||||
dialogsChatTypeSkip: 22px;
|
||||
dialogsChatIcon: icon {{ "dialogs_chat", dialogsChatIconFg, point(1px, 4px) }};
|
||||
dialogsChatIconOver: icon {{ "dialogs_chat", dialogsChatIconFgOver, point(1px, 4px) }};
|
||||
dialogsChatIconActive: icon {{ "dialogs_chat", dialogsChatIconFgActive, point(1px, 4px) }};
|
||||
dialogsChannelIcon: icon {{ "dialogs_channel", dialogsChatIconFg, point(3px, 4px) }};
|
||||
dialogsChannelIconOver: icon {{ "dialogs_channel", dialogsChatIconFgOver, point(3px, 4px) }};
|
||||
dialogsChannelIconActive: icon {{ "dialogs_channel", dialogsChatIconFgActive, point(3px, 4px) }};
|
||||
dialogsBotIcon: icon {{ "dialogs_bot", dialogsChatIconFg, point(1px, 3px) }};
|
||||
dialogsBotIconOver: icon {{ "dialogs_bot", dialogsChatIconFgOver, point(1px, 3px) }};
|
||||
dialogsBotIconActive: icon {{ "dialogs_bot", dialogsChatIconFgActive, point(1px, 3px) }};
|
||||
dialogsChatIcon: icon {{ "dialogs/dialogs_chat", dialogsChatIconFg, point(1px, 4px) }};
|
||||
dialogsChatIconOver: icon {{ "dialogs/dialogs_chat", dialogsChatIconFgOver, point(1px, 4px) }};
|
||||
dialogsChatIconActive: icon {{ "dialogs/dialogs_chat", dialogsChatIconFgActive, point(1px, 4px) }};
|
||||
dialogsChannelIcon: icon {{ "dialogs/dialogs_channel", dialogsChatIconFg, point(3px, 4px) }};
|
||||
dialogsChannelIconOver: icon {{ "dialogs/dialogs_channel", dialogsChatIconFgOver, point(3px, 4px) }};
|
||||
dialogsChannelIconActive: icon {{ "dialogs/dialogs_channel", dialogsChatIconFgActive, point(3px, 4px) }};
|
||||
dialogsBotIcon: icon {{ "dialogs/dialogs_bot", dialogsChatIconFg, point(1px, 3px) }};
|
||||
dialogsBotIconOver: icon {{ "dialogs/dialogs_bot", dialogsChatIconFgOver, point(1px, 3px) }};
|
||||
dialogsBotIconActive: icon {{ "dialogs/dialogs_bot", dialogsChatIconFgActive, point(1px, 3px) }};
|
||||
dialogsArchiveUserpic: icon {{ "archive_userpic", historyPeerUserpicFg }};
|
||||
dialogsRepliesUserpic: icon {{ "replies_userpic", historyPeerUserpicFg }};
|
||||
|
||||
dialogsSendStateSkip: 20px;
|
||||
dialogsSendingIcon: icon {{ "dialogs_sending", dialogsSendingIconFg, point(8px, 4px) }};
|
||||
dialogsSendingIconOver: icon {{ "dialogs_sending", dialogsSendingIconFgOver, point(8px, 4px) }};
|
||||
dialogsSendingIconActive: icon {{ "dialogs_sending", dialogsSendingIconFgActive, point(8px, 4px) }};
|
||||
dialogsSentIcon: icon {{ "dialogs_sent", dialogsSentIconFg, point(10px, 4px) }};
|
||||
dialogsSentIconOver: icon {{ "dialogs_sent", dialogsSentIconFgOver, point(10px, 4px) }};
|
||||
dialogsSentIconActive: icon {{ "dialogs_sent", dialogsSentIconFgActive, point(10px, 4px) }};
|
||||
dialogsReceivedIcon: icon {{ "dialogs_received", dialogsSentIconFg, point(5px, 4px) }};
|
||||
dialogsReceivedIconOver: icon {{ "dialogs_received", dialogsSentIconFgOver, point(5px, 4px) }};
|
||||
dialogsReceivedIconActive: icon {{ "dialogs_received", dialogsSentIconFgActive, point(5px, 4px) }};
|
||||
dialogsPinnedIcon: icon {{ "dialogs_pinned", dialogsUnreadBgMuted }};
|
||||
dialogsPinnedIconOver: icon {{ "dialogs_pinned", dialogsUnreadBgMutedOver }};
|
||||
dialogsPinnedIconActive: icon {{ "dialogs_pinned", dialogsUnreadBgMutedActive }};
|
||||
dialogsSendingIcon: icon {{ "dialogs/dialogs_sending", dialogsSendingIconFg, point(8px, 4px) }};
|
||||
dialogsSendingIconOver: icon {{ "dialogs/dialogs_sending", dialogsSendingIconFgOver, point(8px, 4px) }};
|
||||
dialogsSendingIconActive: icon {{ "dialogs/dialogs_sending", dialogsSendingIconFgActive, point(8px, 4px) }};
|
||||
dialogsSentIcon: icon {{ "dialogs/dialogs_sent", dialogsSentIconFg, point(10px, 4px) }};
|
||||
dialogsSentIconOver: icon {{ "dialogs/dialogs_sent", dialogsSentIconFgOver, point(10px, 4px) }};
|
||||
dialogsSentIconActive: icon {{ "dialogs/dialogs_sent", dialogsSentIconFgActive, point(10px, 4px) }};
|
||||
dialogsReceivedIcon: icon {{ "dialogs/dialogs_received", dialogsSentIconFg, point(5px, 4px) }};
|
||||
dialogsReceivedIconOver: icon {{ "dialogs/dialogs_received", dialogsSentIconFgOver, point(5px, 4px) }};
|
||||
dialogsReceivedIconActive: icon {{ "dialogs/dialogs_received", dialogsSentIconFgActive, point(5px, 4px) }};
|
||||
dialogsPinnedIcon: icon {{ "dialogs/dialogs_pinned", dialogsUnreadBgMuted }};
|
||||
dialogsPinnedIconOver: icon {{ "dialogs/dialogs_pinned", dialogsUnreadBgMutedOver }};
|
||||
dialogsPinnedIconActive: icon {{ "dialogs/dialogs_pinned", dialogsUnreadBgMutedActive }};
|
||||
|
||||
dialogsVerifiedIcon: icon {
|
||||
{ "dialogs_verified_star", dialogsVerifiedIconBg, point(4px, 2px) },
|
||||
{ "dialogs_verified_check", dialogsVerifiedIconFg, point(7px, 7px) },
|
||||
{ "dialogs/dialogs_verified_star", dialogsVerifiedIconBg },
|
||||
{ "dialogs/dialogs_verified_check", dialogsVerifiedIconFg },
|
||||
};
|
||||
dialogsVerifiedIconOver: icon {
|
||||
{ "dialogs_verified_star", dialogsVerifiedIconBgOver, point(4px, 2px) },
|
||||
{ "dialogs_verified_check", dialogsVerifiedIconFgOver, point(7px, 7px) },
|
||||
{ "dialogs/dialogs_verified_star", dialogsVerifiedIconBgOver },
|
||||
{ "dialogs/dialogs_verified_check", dialogsVerifiedIconFgOver },
|
||||
};
|
||||
dialogsVerifiedIconActive: icon {
|
||||
{ "dialogs_verified_star", dialogsVerifiedIconBgActive, point(4px, 2px) },
|
||||
{ "dialogs_verified_check", dialogsVerifiedIconFgActive, point(7px, 7px) },
|
||||
{ "dialogs/dialogs_verified_star", dialogsVerifiedIconBgActive },
|
||||
{ "dialogs/dialogs_verified_check", dialogsVerifiedIconFgActive },
|
||||
};
|
||||
|
||||
historySendingIcon: icon {{ "dialogs_sending", historySendingOutIconFg, point(5px, 5px) }};
|
||||
historySendingInvertedIcon: icon {{ "dialogs_sending", historySendingInvertedIconFg, point(5px, 5px) }};
|
||||
historyViewsSendingIcon: icon {{ "dialogs_sending", historySendingInIconFg, point(3px, 0px) }};
|
||||
historyViewsSendingInvertedIcon: icon {{ "dialogs_sending", historySendingInvertedIconFg, point(3px, 0px) }};
|
||||
historySendingIcon: icon {{ "dialogs/dialogs_sending", historySendingOutIconFg, point(5px, 5px) }};
|
||||
historySendingInvertedIcon: icon {{ "dialogs/dialogs_sending", historySendingInvertedIconFg, point(5px, 5px) }};
|
||||
historyViewsSendingIcon: icon {{ "dialogs/dialogs_sending", historySendingInIconFg, point(3px, 0px) }};
|
||||
historyViewsSendingInvertedIcon: icon {{ "dialogs/dialogs_sending", historySendingInvertedIconFg, point(3px, 0px) }};
|
||||
|
||||
dialogsUpdateButton: FlatButton {
|
||||
color: activeButtonFg;
|
||||
|
||||
@@ -63,8 +63,8 @@ Data::Folder *Entry::asFolder() {
|
||||
return _isFolder ? static_cast<Data::Folder*>(this) : nullptr;
|
||||
}
|
||||
|
||||
void Entry::pinnedIndexChanged(int was, int now) {
|
||||
if (session().supportMode()) {
|
||||
void Entry::pinnedIndexChanged(FilterId filterId, int was, int now) {
|
||||
if (!filterId && session().supportMode()) {
|
||||
// Force reorder in support mode.
|
||||
_sortKeyInChatList = 0;
|
||||
}
|
||||
@@ -83,15 +83,12 @@ void Entry::cachePinnedIndex(FilterId filterId, int index) {
|
||||
}
|
||||
if (!index) {
|
||||
_pinnedIndex.erase(i);
|
||||
pinnedIndexChanged(was, index);
|
||||
} else if (!was) {
|
||||
_pinnedIndex.emplace(filterId, index);
|
||||
} else {
|
||||
if (!was) {
|
||||
_pinnedIndex.emplace(filterId, index);
|
||||
} else {
|
||||
i->second = index;
|
||||
}
|
||||
pinnedIndexChanged(was, index);
|
||||
i->second = index;
|
||||
}
|
||||
pinnedIndexChanged(filterId, was, index);
|
||||
}
|
||||
|
||||
void Entry::cacheTopPromoted(bool promoted) {
|
||||
|
||||
@@ -205,7 +205,7 @@ protected:
|
||||
|
||||
private:
|
||||
virtual void changedChatListPinHook();
|
||||
void pinnedIndexChanged(int was, int now);
|
||||
void pinnedIndexChanged(FilterId filterId, int was, int now);
|
||||
[[nodiscard]] uint64 computeSortPosition(FilterId filterId) const;
|
||||
|
||||
void setChatListExistence(bool exists);
|
||||
|
||||
@@ -42,6 +42,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_session_settings.h"
|
||||
#include "window/notifications_manager.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "window/window_peer_menu.h"
|
||||
#include "ui/widgets/multi_select.h"
|
||||
@@ -3011,7 +3012,9 @@ void InnerWidget::updateRowCornerStatusShown(
|
||||
void InnerWidget::setupShortcuts() {
|
||||
Shortcuts::Requests(
|
||||
) | rpl::filter([=] {
|
||||
return isActiveWindow() && !Ui::isLayerShown();
|
||||
return isActiveWindow()
|
||||
&& !Ui::isLayerShown()
|
||||
&& !_controller->window().locked();
|
||||
}) | rpl::start_with_next([=](not_null<Shortcuts::Request*> request) {
|
||||
using Command = Shortcuts::Command;
|
||||
|
||||
|
||||
@@ -1160,8 +1160,9 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||
auto lnkIsVideo = lnkDocument ? lnkDocument->document()->isVideoFile() : false;
|
||||
auto lnkIsVoice = lnkDocument ? lnkDocument->document()->isVoiceMessage() : false;
|
||||
auto lnkIsAudio = lnkDocument ? lnkDocument->document()->isAudioFile() : false;
|
||||
const auto fromId = PeerId(
|
||||
link->property(kPeerLinkPeerIdProperty).toULongLong());
|
||||
const auto fromId = PeerId(link
|
||||
? link->property(kPeerLinkPeerIdProperty).toULongLong()
|
||||
: 0);
|
||||
if (lnkPhoto || lnkDocument) {
|
||||
if (isUponSelected > 0) {
|
||||
_menu->addAction(tr::lng_context_copy_selected(tr::now), [=] {
|
||||
|
||||
@@ -343,6 +343,10 @@ public:
|
||||
[[nodiscard]] virtual TextWithEntities originalText() const {
|
||||
return TextWithEntities();
|
||||
}
|
||||
[[nodiscard]] virtual auto originalTextWithLocalEntities() const
|
||||
-> TextWithEntities {
|
||||
return TextWithEntities();
|
||||
}
|
||||
[[nodiscard]] virtual TextForMimeData clipboardText() const {
|
||||
return TextForMimeData();
|
||||
}
|
||||
|
||||
@@ -135,6 +135,8 @@ HiddenSenderInfo::HiddenSenderInfo(const QString &name, bool external)
|
||||
(external
|
||||
? Ui::EmptyUserpic::ExternalName()
|
||||
: name)) {
|
||||
Expects(!name.isEmpty());
|
||||
|
||||
nameText.setText(st::msgNameStyle, name, Ui::NameTextOptions());
|
||||
const auto parts = name.trimmed().split(' ', Qt::SkipEmptyParts);
|
||||
firstName = parts[0];
|
||||
|
||||
@@ -1176,8 +1176,13 @@ void HistoryMessage::setupForwardedComponent(const CreateConfig &config) {
|
||||
return;
|
||||
}
|
||||
forwarded->originalDate = config.originalDate;
|
||||
forwarded->originalSender = config.senderOriginal
|
||||
? history()->owner().peer(config.senderOriginal).get()
|
||||
const auto originalSender = config.senderOriginal
|
||||
? config.senderOriginal
|
||||
: !config.senderNameOriginal.isEmpty()
|
||||
? PeerId()
|
||||
: from()->id;
|
||||
forwarded->originalSender = originalSender
|
||||
? history()->owner().peer(originalSender).get()
|
||||
: nullptr;
|
||||
if (!forwarded->originalSender) {
|
||||
forwarded->hiddenSenderInfo = std::make_unique<HiddenSenderInfo>(
|
||||
@@ -1531,19 +1536,31 @@ Storage::SharedMediaTypesMask HistoryMessage::sharedMediaTypes() const {
|
||||
}
|
||||
|
||||
bool HistoryMessage::generateLocalEntitiesByReply() const {
|
||||
using namespace HistoryView;
|
||||
if (!_media) {
|
||||
return true;
|
||||
} else if (const auto document = _media->document()) {
|
||||
return !DurationForTimestampLinks(document);
|
||||
} else if (const auto webpage = _media->webpage()) {
|
||||
return !webpage->document && webpage->type != WebPageType::Video;
|
||||
return (webpage->type != WebPageType::Video)
|
||||
&& !DurationForTimestampLinks(webpage);
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
TextWithEntities HistoryMessage::withLocalEntities(
|
||||
const TextWithEntities &textWithEntities) const {
|
||||
using namespace HistoryView;
|
||||
if (!generateLocalEntitiesByReply()) {
|
||||
if (const auto webpage = _media ? _media->webpage() : nullptr) {
|
||||
if (!_media) {
|
||||
} else if (const auto document = _media->document()) {
|
||||
if (const auto duration = DurationForTimestampLinks(document)) {
|
||||
return AddTimestampLinks(
|
||||
textWithEntities,
|
||||
duration,
|
||||
TimestampLinkBase(document, fullId()));
|
||||
}
|
||||
} else if (const auto webpage = _media->webpage()) {
|
||||
if (const auto duration = DurationForTimestampLinks(webpage)) {
|
||||
return AddTimestampLinks(
|
||||
textWithEntities,
|
||||
@@ -1707,6 +1724,10 @@ TextWithEntities HistoryMessage::originalText() const {
|
||||
return _text.toTextWithEntities();
|
||||
}
|
||||
|
||||
TextWithEntities HistoryMessage::originalTextWithLocalEntities() const {
|
||||
return withLocalEntities(originalText());
|
||||
}
|
||||
|
||||
TextForMimeData HistoryMessage::clipboardText() const {
|
||||
if (emptyText()) {
|
||||
return TextForMimeData();
|
||||
|
||||
@@ -173,6 +173,8 @@ public:
|
||||
void setText(const TextWithEntities &textWithEntities) override;
|
||||
[[nodiscard]] Ui::Text::IsolatedEmoji isolatedEmoji() const override;
|
||||
[[nodiscard]] TextWithEntities originalText() const override;
|
||||
[[nodiscard]] auto originalTextWithLocalEntities() const
|
||||
-> TextWithEntities override;
|
||||
[[nodiscard]] TextForMimeData clipboardText() const override;
|
||||
[[nodiscard]] bool textHasLinks() const override;
|
||||
|
||||
|
||||
@@ -7162,7 +7162,7 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
||||
textTop,
|
||||
st::msgReplyBarSize.height(),
|
||||
st::msgReplyBarSize.height());
|
||||
if (HistoryView::DrawWebPageDataPreview(p, _previewData, to)) {
|
||||
if (HistoryView::DrawWebPageDataPreview(p, _previewData, _peer, to)) {
|
||||
previewLeft += st::msgReplyBarSize.height()
|
||||
+ st::msgReplyBarSkip
|
||||
- st::msgReplyBarSize.width()
|
||||
|
||||
@@ -105,6 +105,7 @@ class FieldHeader final : public Ui::RpWidget {
|
||||
public:
|
||||
FieldHeader(QWidget *parent, not_null<Data::Session*> data);
|
||||
|
||||
void setHistory(const SetHistoryArgs &args);
|
||||
void init();
|
||||
|
||||
void editMessage(FullMsgId id);
|
||||
@@ -142,7 +143,7 @@ private:
|
||||
void resolveMessageData();
|
||||
void updateShownMessageText();
|
||||
|
||||
void paintWebPage(Painter &p);
|
||||
void paintWebPage(Painter &p, not_null<PeerData*> peer);
|
||||
void paintEditOrReplyToMessage(Painter &p);
|
||||
|
||||
struct Preview {
|
||||
@@ -152,6 +153,7 @@ private:
|
||||
bool cancelled = false;
|
||||
};
|
||||
|
||||
History *_history = nullptr;
|
||||
rpl::variable<QString> _title;
|
||||
rpl::variable<QString> _description;
|
||||
|
||||
@@ -188,6 +190,10 @@ FieldHeader::FieldHeader(QWidget *parent, not_null<Data::Session*> data)
|
||||
init();
|
||||
}
|
||||
|
||||
void FieldHeader::setHistory(const SetHistoryArgs &args) {
|
||||
_history = *args.history;
|
||||
}
|
||||
|
||||
void FieldHeader::init() {
|
||||
sizeValue(
|
||||
) | rpl::start_with_next([=](QSize size) {
|
||||
@@ -209,7 +215,9 @@ void FieldHeader::init() {
|
||||
|
||||
(!ShowWebPagePreview(_preview.data) || *leftIconPressed)
|
||||
? paintEditOrReplyToMessage(p)
|
||||
: paintWebPage(p);
|
||||
: paintWebPage(
|
||||
p,
|
||||
_history ? _history->peer : _data->session().user());
|
||||
}, lifetime());
|
||||
|
||||
_editMsgId.value(
|
||||
@@ -415,7 +423,7 @@ void FieldHeader::previewRequested(
|
||||
|
||||
}
|
||||
|
||||
void FieldHeader::paintWebPage(Painter &p) {
|
||||
void FieldHeader::paintWebPage(Painter &p, not_null<PeerData*> context) {
|
||||
Expects(ShowWebPagePreview(_preview.data));
|
||||
|
||||
const auto textTop = st::msgReplyPadding.top();
|
||||
@@ -432,7 +440,7 @@ void FieldHeader::paintWebPage(Painter &p) {
|
||||
textTop,
|
||||
st::msgReplyBarSize.height(),
|
||||
st::msgReplyBarSize.height());
|
||||
if (HistoryView::DrawWebPageDataPreview(p, _preview.data, to)) {
|
||||
if (HistoryView::DrawWebPageDataPreview(p, _preview.data, context, to)) {
|
||||
previewLeft += st::msgReplyBarSize.height()
|
||||
+ st::msgReplyBarSkip
|
||||
- st::msgReplyBarSize.width()
|
||||
@@ -655,6 +663,7 @@ void ComposeControls::setHistory(SetHistoryArgs &&args) {
|
||||
//}
|
||||
unregisterDraftSources();
|
||||
_history = history;
|
||||
_header->setHistory(args);
|
||||
registerDraftSource();
|
||||
_window->tabbedSelector()->setCurrentPeer(
|
||||
history ? history->peer.get() : nullptr);
|
||||
|
||||
@@ -564,6 +564,7 @@ void ContactStatus::setupRequestInfoHandler(not_null<PeerData*> peer) {
|
||||
*request = peer->session().api().request(
|
||||
MTPmessages_HidePeerSettingsBar(peer->input)
|
||||
).send();
|
||||
box->closeBox();
|
||||
});
|
||||
}));
|
||||
}, _bar.lifetime());
|
||||
|
||||
@@ -56,9 +56,13 @@ WebPageText TitleAndDescriptionFromWebPage(not_null<WebPageData*> d) {
|
||||
return { resultTitle, resultDescription };
|
||||
}
|
||||
|
||||
bool DrawWebPageDataPreview(Painter &p, not_null<WebPageData*> d, QRect to) {
|
||||
const auto document = d->document;
|
||||
const auto photo = d->photo;
|
||||
bool DrawWebPageDataPreview(
|
||||
Painter &p,
|
||||
not_null<WebPageData*> webpage,
|
||||
not_null<PeerData*> context,
|
||||
QRect to) {
|
||||
const auto document = webpage->document;
|
||||
const auto photo = webpage->photo;
|
||||
if ((!photo || photo->isNull())
|
||||
&& (!document
|
||||
|| !document->hasThumbnail()
|
||||
@@ -67,8 +71,8 @@ bool DrawWebPageDataPreview(Painter &p, not_null<WebPageData*> d, QRect to) {
|
||||
}
|
||||
|
||||
const auto preview = photo
|
||||
? photo->getReplyPreview(Data::FileOrigin())
|
||||
: document->getReplyPreview(Data::FileOrigin());
|
||||
? photo->getReplyPreview(Data::FileOrigin(), context)
|
||||
: document->getReplyPreview(Data::FileOrigin(), context);
|
||||
if (preview) {
|
||||
const auto w = preview->width();
|
||||
const auto h = preview->height();
|
||||
|
||||
@@ -15,6 +15,10 @@ struct WebPageText {
|
||||
};
|
||||
|
||||
WebPageText TitleAndDescriptionFromWebPage(not_null<WebPageData*> d);
|
||||
bool DrawWebPageDataPreview(Painter &p, not_null<WebPageData*> d, QRect to);
|
||||
bool DrawWebPageDataPreview(
|
||||
Painter &p,
|
||||
not_null<WebPageData*> webpage,
|
||||
not_null<PeerData*> context,
|
||||
QRect to);
|
||||
|
||||
} // namespace HistoryView
|
||||
|
||||
@@ -1084,14 +1084,7 @@ TextWithEntities Document::getCaption() const {
|
||||
}
|
||||
|
||||
Ui::Text::String Document::createCaption() {
|
||||
const auto timestampLinksDuration = DurationForTimestampLinks(_data);
|
||||
const auto timestampLinkBase = timestampLinksDuration
|
||||
? TimestampLinkBase(_data, _realParent->fullId())
|
||||
: QString();
|
||||
return File::createCaption(
|
||||
_realParent,
|
||||
timestampLinksDuration,
|
||||
timestampLinkBase);
|
||||
return File::createCaption(_realParent);
|
||||
}
|
||||
|
||||
bool DrawThumbnailAsSongCover(
|
||||
|
||||
@@ -1322,14 +1322,7 @@ void Gif::refreshParentId(not_null<HistoryItem*> realParent) {
|
||||
}
|
||||
|
||||
void Gif::refreshCaption() {
|
||||
const auto timestampLinksDuration = DurationForTimestampLinks(_data);
|
||||
const auto timestampLinkBase = timestampLinksDuration
|
||||
? TimestampLinkBase(_data, _realParent->fullId())
|
||||
: QString();
|
||||
_caption = createCaption(
|
||||
_parent->data(),
|
||||
timestampLinksDuration,
|
||||
timestampLinkBase);
|
||||
_caption = createCaption(_parent->data());
|
||||
}
|
||||
|
||||
int Gif::additionalWidth(const HistoryMessageVia *via, const HistoryMessageReply *reply, const HistoryMessageForwarded *forwarded) const {
|
||||
|
||||
@@ -64,7 +64,7 @@ QString TimestampLinkBase(
|
||||
|
||||
TimeId DurationForTimestampLinks(not_null<WebPageData*> webpage) {
|
||||
if (!webpage->collage.items.empty()) {
|
||||
return false;
|
||||
return 0;
|
||||
} else if (const auto document = webpage->document) {
|
||||
return DurationForTimestampLinks(document);
|
||||
} else if (webpage->type != WebPageType::Video
|
||||
@@ -185,12 +185,7 @@ QSize Media::countCurrentSize(int newWidth) {
|
||||
return QSize(qMin(newWidth, maxWidth()), minHeight());
|
||||
}
|
||||
|
||||
Ui::Text::String Media::createCaption(
|
||||
not_null<HistoryItem*> item,
|
||||
TimeId timestampLinksDuration,
|
||||
const QString ×tampLinkBase) const {
|
||||
Expects(timestampLinksDuration >= 0);
|
||||
|
||||
Ui::Text::String Media::createCaption(not_null<HistoryItem*> item) const {
|
||||
if (item->emptyText()) {
|
||||
return {};
|
||||
}
|
||||
@@ -203,12 +198,7 @@ Ui::Text::String Media::createCaption(
|
||||
};
|
||||
result.setMarkedText(
|
||||
st::messageTextStyle,
|
||||
(timestampLinksDuration
|
||||
? AddTimestampLinks(
|
||||
item->originalText(),
|
||||
timestampLinksDuration,
|
||||
timestampLinkBase)
|
||||
: item->originalText()),
|
||||
item->originalTextWithLocalEntities(),
|
||||
Ui::ItemTextOptions(item),
|
||||
context);
|
||||
if (const auto width = _parent->skipBlockWidth()) {
|
||||
|
||||