mirror of https://github.com/procxx/kepka.git
Closed beta 10019013: Groups in common now are opened in a section.
This commit is contained in:
parent
47977009b8
commit
4692fdeb5f
|
@ -309,12 +309,6 @@ simpleCloseIcon: icon {{ "simple_close", #c7c7c7 }};
|
||||||
simpleCloseIconOver: icon {{ "simple_close", #a3a3a3 }};
|
simpleCloseIconOver: icon {{ "simple_close", #a3a3a3 }};
|
||||||
dialogsForwardCancelIcon: icon {{ "simple_close", dialogsForwardFg }};
|
dialogsForwardCancelIcon: icon {{ "simple_close", dialogsForwardFg }};
|
||||||
|
|
||||||
profileMaxWidth: 410px;
|
|
||||||
profilePadding: margins(28px, 30px, 28px, 0px);
|
|
||||||
|
|
||||||
profileOnlineFg: statusFgActive;
|
|
||||||
profileOfflineFg: statusFg;
|
|
||||||
|
|
||||||
membersPadding: margins(0px, 10px, 0px, 10px);
|
membersPadding: margins(0px, 10px, 0px, 10px);
|
||||||
|
|
||||||
forwardMargins: margins(30px, 10px, 30px, 10px);
|
forwardMargins: margins(30px, 10px, 30px, 10px);
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
Before Width: | Height: | Size: 4.9 KiB |
|
@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 0,10,19,12
|
FILEVERSION 0,10,19,13
|
||||||
PRODUCTVERSION 0,10,19,12
|
PRODUCTVERSION 0,10,19,13
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -51,10 +51,10 @@ BEGIN
|
||||||
BLOCK "040904b0"
|
BLOCK "040904b0"
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Telegram Messenger LLP"
|
VALUE "CompanyName", "Telegram Messenger LLP"
|
||||||
VALUE "FileVersion", "0.10.19.12"
|
VALUE "FileVersion", "0.10.19.13"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2014-2016"
|
VALUE "LegalCopyright", "Copyright (C) 2014-2016"
|
||||||
VALUE "ProductName", "Telegram Desktop"
|
VALUE "ProductName", "Telegram Desktop"
|
||||||
VALUE "ProductVersion", "0.10.19.12"
|
VALUE "ProductVersion", "0.10.19.13"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
|
@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 0,10,19,12
|
FILEVERSION 0,10,19,13
|
||||||
PRODUCTVERSION 0,10,19,12
|
PRODUCTVERSION 0,10,19,13
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -43,10 +43,10 @@ BEGIN
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Telegram Messenger LLP"
|
VALUE "CompanyName", "Telegram Messenger LLP"
|
||||||
VALUE "FileDescription", "Telegram Updater"
|
VALUE "FileDescription", "Telegram Updater"
|
||||||
VALUE "FileVersion", "0.10.19.12"
|
VALUE "FileVersion", "0.10.19.13"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2014-2016"
|
VALUE "LegalCopyright", "Copyright (C) 2014-2016"
|
||||||
VALUE "ProductName", "Telegram Desktop"
|
VALUE "ProductName", "Telegram Desktop"
|
||||||
VALUE "ProductVersion", "0.10.19.12"
|
VALUE "ProductVersion", "0.10.19.13"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
|
@ -2511,26 +2511,26 @@ namespace {
|
||||||
if (!fmt.isEmpty()) *format = fmt;
|
if (!fmt.isEmpty()) *format = fmt;
|
||||||
}
|
}
|
||||||
buffer.seek(0);
|
buffer.seek(0);
|
||||||
QString fmt = QString::fromUtf8(*format).toLower();
|
auto fmt = QString::fromUtf8(*format).toLower();
|
||||||
if (fmt == "jpg" || fmt == "jpeg") {
|
if (fmt == "jpg" || fmt == "jpeg") {
|
||||||
#ifdef OS_MAC_OLD
|
#ifdef OS_MAC_OLD
|
||||||
ExifData *exifData = exif_data_new_from_data((const uchar*)(data.constData()), data.size());
|
if (auto exifData = exif_data_new_from_data((const uchar*)(data.constData()), data.size())) {
|
||||||
if (exifData) {
|
auto byteOrder = exif_data_get_byte_order(exifData);
|
||||||
ExifByteOrder byteOrder = exif_data_get_byte_order(exifData);
|
if (auto exifEntry = exif_data_get_entry(exifData, EXIF_TAG_ORIENTATION)) {
|
||||||
ExifEntry *exifEntry = exif_data_get_entry(exifData, EXIF_TAG_ORIENTATION);
|
auto orientationFix = [exifEntry, byteOrder] {
|
||||||
if (exifEntry) {
|
auto orientation = exif_get_short(exifEntry->data, byteOrder);
|
||||||
QTransform orientationFix;
|
switch (orientation) {
|
||||||
int orientation = exif_get_short(exifEntry->data, byteOrder);
|
case 2: return QTransform(-1, 0, 0, 1, 0, 0);
|
||||||
switch (orientation) {
|
case 3: return QTransform(-1, 0, 0, -1, 0, 0);
|
||||||
case 2: orientationFix = QTransform(-1, 0, 0, 1, 0, 0); break;
|
case 4: return QTransform(1, 0, 0, -1, 0, 0);
|
||||||
case 3: orientationFix = QTransform(-1, 0, 0, -1, 0, 0); break;
|
case 5: return QTransform(0, -1, -1, 0, 0, 0);
|
||||||
case 4: orientationFix = QTransform(1, 0, 0, -1, 0, 0); break;
|
case 6: return QTransform(0, 1, -1, 0, 0, 0);
|
||||||
case 5: orientationFix = QTransform(0, -1, -1, 0, 0, 0); break;
|
case 7: return QTransform(0, 1, 1, 0, 0, 0);
|
||||||
case 6: orientationFix = QTransform(0, 1, -1, 0, 0, 0); break;
|
case 8: return QTransform(0, -1, 1, 0, 0, 0);
|
||||||
case 7: orientationFix = QTransform(0, 1, 1, 0, 0, 0); break;
|
}
|
||||||
case 8: orientationFix = QTransform(0, -1, 1, 0, 0, 0); break;
|
return QTransform();
|
||||||
}
|
};
|
||||||
result = result.transformed(orientationFix);
|
result = result.transformed(orientationFix());
|
||||||
}
|
}
|
||||||
exif_data_free(exifData);
|
exif_data_free(exifData);
|
||||||
}
|
}
|
||||||
|
@ -2547,9 +2547,11 @@ namespace {
|
||||||
if (animated) *animated = false;
|
if (animated) *animated = false;
|
||||||
return QImage();
|
return QImage();
|
||||||
}
|
}
|
||||||
QByteArray img = f.readAll();
|
auto imageBytes = f.readAll();
|
||||||
QImage result = readImage(img, format, opaque, animated);
|
auto result = readImage(imageBytes, format, opaque, animated);
|
||||||
if (content && !result.isNull()) *content = img;
|
if (content && !result.isNull()) {
|
||||||
|
*content = imageBytes;
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -391,23 +391,24 @@ inline const QRegularExpression &cRussianLetters() {
|
||||||
return regexp;
|
return regexp;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline QStringList cImgExtensions() {
|
inline const QStringList &cImgExtensions() {
|
||||||
static QStringList imgExtensions;
|
static QStringList result;
|
||||||
if (imgExtensions.isEmpty()) {
|
if (result.isEmpty()) {
|
||||||
imgExtensions.reserve(4);
|
result.reserve(4);
|
||||||
imgExtensions.push_back(qsl(".jpg"));
|
result.push_back(qsl(".jpg"));
|
||||||
imgExtensions.push_back(qsl(".jpeg"));
|
result.push_back(qsl(".jpeg"));
|
||||||
imgExtensions.push_back(qsl(".png"));
|
result.push_back(qsl(".png"));
|
||||||
imgExtensions.push_back(qsl(".gif"));
|
result.push_back(qsl(".gif"));
|
||||||
}
|
}
|
||||||
return imgExtensions;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline QStringList cPhotoExtensions() {
|
inline const QStringList &cExtensionsForCompress() {
|
||||||
static QStringList photoExtensions;
|
static QStringList result;
|
||||||
if (photoExtensions.isEmpty()) {
|
if (result.isEmpty()) {
|
||||||
photoExtensions.push_back(qsl(".jpg"));
|
result.push_back(qsl(".jpg"));
|
||||||
photoExtensions.push_back(qsl(".jpeg"));
|
result.push_back(qsl(".jpeg"));
|
||||||
|
result.push_back(qsl(".png"));
|
||||||
}
|
}
|
||||||
return photoExtensions;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "core/utils.h"
|
#include "core/utils.h"
|
||||||
|
|
||||||
#define BETA_VERSION_MACRO (10019012ULL)
|
#define BETA_VERSION_MACRO (10019013ULL)
|
||||||
|
|
||||||
constexpr int AppVersion = 10020;
|
constexpr int AppVersion = 10020;
|
||||||
constexpr str_const AppVersionStr = "0.10.20";
|
constexpr str_const AppVersionStr = "0.10.20";
|
||||||
|
|
|
@ -67,9 +67,6 @@ historyToDownBadgeSize: 22px;
|
||||||
historyToDownShownAfter: 480px;
|
historyToDownShownAfter: 480px;
|
||||||
historyToDownDuration: 150;
|
historyToDownDuration: 150;
|
||||||
|
|
||||||
historyEmptyDog: icon {{ "history_empty_dog", #ffffff }};
|
|
||||||
historyEmptySize: 128px;
|
|
||||||
|
|
||||||
membersInnerWidth: 310px;
|
membersInnerWidth: 310px;
|
||||||
membersInnerHeightMax: 360px;
|
membersInnerHeightMax: 360px;
|
||||||
membersInnerDropdown: InnerDropdown(defaultInnerDropdown) {
|
membersInnerDropdown: InnerDropdown(defaultInnerDropdown) {
|
||||||
|
|
|
@ -335,14 +335,6 @@ QVector<int> ServiceMessagePainter::countLineWidths(const Text &text, const QRec
|
||||||
}
|
}
|
||||||
|
|
||||||
void paintEmpty(Painter &p, int width, int height) {
|
void paintEmpty(Painter &p, int width, int height) {
|
||||||
auto position = QPoint((width - st::historyEmptySize) / 2, ((height - st::historyEmptySize) * 4) / 9);
|
|
||||||
p.setPen(Qt::NoPen);
|
|
||||||
p.setBrush(st::msgServiceBg);
|
|
||||||
{
|
|
||||||
PainterHighQualityEnabler hq(p);
|
|
||||||
p.drawEllipse(rtlrect(position.x(), position.y(), st::historyEmptySize, st::historyEmptySize, width));
|
|
||||||
}
|
|
||||||
st::historyEmptyDog.paint(p, position.x() + (st::historyEmptySize - st::historyEmptyDog.width()) / 2, position.y() + (st::historyEmptySize - st::historyEmptyDog.height()) / 2, width);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void serviceColorsUpdated() {
|
void serviceColorsUpdated() {
|
||||||
|
|
|
@ -5551,9 +5551,7 @@ void HistoryWidget::step_recording(float64 ms, bool timer) {
|
||||||
void HistoryWidget::chooseAttach() {
|
void HistoryWidget::chooseAttach() {
|
||||||
if (!_history) return;
|
if (!_history) return;
|
||||||
|
|
||||||
auto photoExtensions = cPhotoExtensions();
|
auto filter = filedialogAllFilesFilter() + qsl(";;Image files (*") + cImgExtensions().join(qsl(" *")) + qsl(")");
|
||||||
auto imageExtensions = cImgExtensions();
|
|
||||||
auto filter = filedialogAllFilesFilter() + qsl(";;Image files (*") + imageExtensions.join(qsl(" *")) + qsl(");;Photo files (*") + photoExtensions.join(qsl(" *")) + qsl(")");
|
|
||||||
|
|
||||||
_attachFilesQueryId = FileDialog::queryReadFiles(lang(lng_choose_files), filter);
|
_attachFilesQueryId = FileDialog::queryReadFiles(lang(lng_choose_files), filter);
|
||||||
}
|
}
|
||||||
|
@ -5578,7 +5576,7 @@ void HistoryWidget::notifyFileQueryUpdated(const FileDialog::QueryUpdate &update
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto lists = getSendingFilesLists(update.filePaths);
|
auto lists = getSendingFilesLists(update.filePaths);
|
||||||
if (lists.allFilesArePhotos) {
|
if (lists.allFilesForCompress) {
|
||||||
confirmSendingFiles(lists);
|
confirmSendingFiles(lists);
|
||||||
} else {
|
} else {
|
||||||
validateSendingFiles(lists, [this](const QStringList &files) {
|
validateSendingFiles(lists, [this](const QStringList &files) {
|
||||||
|
@ -6525,7 +6523,7 @@ bool HistoryWidget::confirmSendingFiles(const SendingFilesLists &lists, Compress
|
||||||
auto insertTextOnCancel = QString();
|
auto insertTextOnCancel = QString();
|
||||||
auto prepareBox = [this, &files, &lists, compressed, &image] {
|
auto prepareBox = [this, &files, &lists, compressed, &image] {
|
||||||
if (files.size() > 1) {
|
if (files.size() > 1) {
|
||||||
return new SendFilesBox(files, lists.allFilesArePhotos ? compressed : CompressConfirm::None);
|
return new SendFilesBox(files, lists.allFilesForCompress ? compressed : CompressConfirm::None);
|
||||||
}
|
}
|
||||||
auto filepath = files.front();
|
auto filepath = files.front();
|
||||||
auto animated = false;
|
auto animated = false;
|
||||||
|
@ -6610,8 +6608,8 @@ HistoryWidget::SendingFilesLists HistoryWidget::getSendingFilesLists(const QStri
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::getSendingLocalFileInfo(SendingFilesLists &result, const QString &filepath) {
|
void HistoryWidget::getSendingLocalFileInfo(SendingFilesLists &result, const QString &filepath) {
|
||||||
auto hasPhotoExtension = [](const QString &filepath) {
|
auto hasExtensionForCompress = [](const QString &filepath) {
|
||||||
for_const (auto extension, cPhotoExtensions()) {
|
for_const (auto extension, cExtensionsForCompress()) {
|
||||||
if (filepath.right(extension.size()).compare(extension, Qt::CaseInsensitive) == 0) {
|
if (filepath.right(extension.size()).compare(extension, Qt::CaseInsensitive) == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -6629,9 +6627,9 @@ void HistoryWidget::getSendingLocalFileInfo(SendingFilesLists &result, const QSt
|
||||||
result.tooLargeFiles.push_back(filepath);
|
result.tooLargeFiles.push_back(filepath);
|
||||||
} else {
|
} else {
|
||||||
result.filesToSend.push_back(filepath);
|
result.filesToSend.push_back(filepath);
|
||||||
if (result.allFilesArePhotos) {
|
if (result.allFilesForCompress) {
|
||||||
if (filesize > App::kImageSizeLimit || !hasPhotoExtension(filepath)) {
|
if (filesize > App::kImageSizeLimit || !hasExtensionForCompress(filepath)) {
|
||||||
result.allFilesArePhotos = false;
|
result.allFilesForCompress = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -858,7 +858,7 @@ private:
|
||||||
QStringList emptyFiles;
|
QStringList emptyFiles;
|
||||||
QStringList tooLargeFiles;
|
QStringList tooLargeFiles;
|
||||||
QStringList filesToSend;
|
QStringList filesToSend;
|
||||||
bool allFilesArePhotos = true;
|
bool allFilesForCompress = true;
|
||||||
};
|
};
|
||||||
SendingFilesLists getSendingFilesLists(const QList<QUrl> &files);
|
SendingFilesLists getSendingFilesLists(const QList<QUrl> &files);
|
||||||
SendingFilesLists getSendingFilesLists(const QStringList &files);
|
SendingFilesLists getSendingFilesLists(const QStringList &files);
|
||||||
|
|
|
@ -4546,15 +4546,14 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
|
||||||
case mtpc_updateWebPage: {
|
case mtpc_updateWebPage: {
|
||||||
auto &d = update.c_updateWebPage();
|
auto &d = update.c_updateWebPage();
|
||||||
|
|
||||||
if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) {
|
// update web page anyway
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update before applying skipped
|
|
||||||
App::feedWebPage(d.vwebpage);
|
App::feedWebPage(d.vwebpage);
|
||||||
_history->updatePreview();
|
_history->updatePreview();
|
||||||
webPagesOrGamesUpdate();
|
webPagesOrGamesUpdate();
|
||||||
|
|
||||||
|
if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
ptsApplySkippedUpdates();
|
ptsApplySkippedUpdates();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -4893,8 +4892,13 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
|
||||||
|
|
||||||
case mtpc_updateChannelWebPage: {
|
case mtpc_updateChannelWebPage: {
|
||||||
auto &d = update.c_updateChannelWebPage();
|
auto &d = update.c_updateChannelWebPage();
|
||||||
auto channel = App::channelLoaded(d.vchannel_id.v);
|
|
||||||
|
|
||||||
|
// update web page anyway
|
||||||
|
App::feedWebPage(d.vwebpage);
|
||||||
|
_history->updatePreview();
|
||||||
|
webPagesOrGamesUpdate();
|
||||||
|
|
||||||
|
auto channel = App::channelLoaded(d.vchannel_id.v);
|
||||||
if (channel && !_handlingChannelDifference) {
|
if (channel && !_handlingChannelDifference) {
|
||||||
if (channel->ptsRequesting()) { // skip global updates while getting channel difference
|
if (channel->ptsRequesting()) { // skip global updates while getting channel difference
|
||||||
return;
|
return;
|
||||||
|
@ -4903,12 +4907,6 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// update before applying skipped
|
|
||||||
App::feedWebPage(d.vwebpage);
|
|
||||||
_history->updatePreview();
|
|
||||||
webPagesOrGamesUpdate();
|
|
||||||
|
|
||||||
if (channel && !_handlingChannelDifference) {
|
if (channel && !_handlingChannelDifference) {
|
||||||
channel->ptsApplySkippedUpdates();
|
channel->ptsApplySkippedUpdates();
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,17 +238,8 @@ mediaPlayerListMarginBottom: 10px;
|
||||||
mediaPlayerScrollShadow: icon {{ "playlist_shadow", windowShadowFg }};
|
mediaPlayerScrollShadow: icon {{ "playlist_shadow", windowShadowFg }};
|
||||||
|
|
||||||
mediaPlayerListMarginTop: 8px;
|
mediaPlayerListMarginTop: 8px;
|
||||||
mediaPlayerListIconFg: #ffffff;
|
|
||||||
mediaPlayerFileLayout: OverviewFileLayout(overviewFileLayout) {
|
mediaPlayerFileLayout: OverviewFileLayout(overviewFileLayout) {
|
||||||
maxWidth: 344px;
|
maxWidth: 344px;
|
||||||
songPadding: margins(17px, 7px, 10px, 6px);
|
|
||||||
songThumbSize: 36px;
|
|
||||||
songNameTop: 7px;
|
|
||||||
songStatusTop: 25px;
|
|
||||||
songIconBg: mediaPlayerActiveFg;
|
songIconBg: mediaPlayerActiveFg;
|
||||||
songOverBg: mediaPlayerActiveFg;
|
songOverBg: mediaPlayerActiveFg;
|
||||||
songPause: icon {{ "playlist_pause", mediaPlayerListIconFg }};
|
|
||||||
songPlay: icon {{ "playlist_play", mediaPlayerListIconFg }};
|
|
||||||
songCancel: icon {{ "playlist_cancel", mediaPlayerListIconFg }};
|
|
||||||
songDownload: icon {{ "playlist_download", mediaPlayerListIconFg }};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2827,7 +2827,7 @@ void ConnectionPrivate::clearAuthKeyData() {
|
||||||
if (!_authKeyStrings->dh_prime.isEmpty()) SecureZeroMemory(_authKeyStrings->dh_prime.data(), _authKeyStrings->dh_prime.size());
|
if (!_authKeyStrings->dh_prime.isEmpty()) SecureZeroMemory(_authKeyStrings->dh_prime.data(), _authKeyStrings->dh_prime.size());
|
||||||
if (!_authKeyStrings->g_a.isEmpty()) SecureZeroMemory(_authKeyStrings->g_a.data(), _authKeyStrings->g_a.size());
|
if (!_authKeyStrings->g_a.isEmpty()) SecureZeroMemory(_authKeyStrings->g_a.data(), _authKeyStrings->g_a.size());
|
||||||
#else
|
#else
|
||||||
memset(authKeyData, 0, sizeof(AuthKeyCreateData));
|
memset(_authKeyData.get(), 0, sizeof(AuthKeyCreateData));
|
||||||
if (!_authKeyStrings->dh_prime.isEmpty()) memset(_authKeyStrings->dh_prime.data(), 0, _authKeyStrings->dh_prime.size());
|
if (!_authKeyStrings->dh_prime.isEmpty()) memset(_authKeyStrings->dh_prime.data(), 0, _authKeyStrings->dh_prime.size());
|
||||||
if (!_authKeyStrings->g_a.isEmpty()) memset(_authKeyStrings->g_a.data(), 0, _authKeyStrings->g_a.size());
|
if (!_authKeyStrings->g_a.isEmpty()) memset(_authKeyStrings->g_a.data(), 0, _authKeyStrings->g_a.size());
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -32,9 +32,13 @@ OverviewFileLayout {
|
||||||
songIconBg: color;
|
songIconBg: color;
|
||||||
songOverBg: color;
|
songOverBg: color;
|
||||||
songPause: icon;
|
songPause: icon;
|
||||||
|
songPauseSelected: icon;
|
||||||
songPlay: icon;
|
songPlay: icon;
|
||||||
|
songPlaySelected: icon;
|
||||||
songCancel: icon;
|
songCancel: icon;
|
||||||
|
songCancelSelected: icon;
|
||||||
songDownload: icon;
|
songDownload: icon;
|
||||||
|
songDownloadSelected: icon;
|
||||||
|
|
||||||
filePadding: margins;
|
filePadding: margins;
|
||||||
fileThumbSize: pixels;
|
fileThumbSize: pixels;
|
||||||
|
@ -43,6 +47,9 @@ OverviewFileLayout {
|
||||||
fileDateTop: pixels;
|
fileDateTop: pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overviewLeftMin: 28px;
|
||||||
|
overviewLeftMax: 42px;
|
||||||
|
|
||||||
overviewCheckBg: #00000040;
|
overviewCheckBg: #00000040;
|
||||||
overviewCheckFg: windowBg;
|
overviewCheckFg: windowBg;
|
||||||
overviewCheckFgActive: windowBg;
|
overviewCheckFgActive: windowBg;
|
||||||
|
@ -70,18 +77,30 @@ overviewFileExtTop: 24px;
|
||||||
overviewFileExtFg: #ffffff;
|
overviewFileExtFg: #ffffff;
|
||||||
overviewFileExtFont: font(18px semibold);
|
overviewFileExtFont: font(18px semibold);
|
||||||
|
|
||||||
|
overviewSongPause: icon {{ "playlist_pause", msgInBg }};
|
||||||
|
overviewSongPauseSelected: icon {{ "playlist_pause", msgInBgSelected }};
|
||||||
|
overviewSongPlay: icon {{ "playlist_play", msgInBg }};
|
||||||
|
overviewSongPlaySelected: icon {{ "playlist_play", msgInBgSelected }};
|
||||||
|
overviewSongCancel: icon {{ "playlist_cancel", msgInBg }};
|
||||||
|
overviewSongCancelSelected: icon {{ "playlist_cancel", msgInBgSelected }};
|
||||||
|
overviewSongDownload: icon {{ "playlist_download", msgInBg }};
|
||||||
|
overviewSongDownloadSelected: icon {{ "playlist_download", msgInBgSelected }};
|
||||||
overviewFileLayout: OverviewFileLayout {
|
overviewFileLayout: OverviewFileLayout {
|
||||||
maxWidth: 410px;
|
maxWidth: 520px;
|
||||||
songPadding: msgFilePadding;
|
songPadding: margins(17px, 7px, 10px, 6px);
|
||||||
songThumbSize: msgFileSize;
|
songThumbSize: 36px;
|
||||||
songNameTop: msgFileNameTop;
|
songNameTop: 7px;
|
||||||
songStatusTop: msgFileStatusTop;
|
songStatusTop: 25px;
|
||||||
songIconBg: msgFileInBg;
|
songIconBg: msgFileInBg;
|
||||||
songOverBg: msgFileInBgOver;
|
songOverBg: msgFileInBgOver;
|
||||||
songPause: historyFileInPause;
|
songPause: overviewSongPause;
|
||||||
songPlay: historyFileInPlay;
|
songPauseSelected: overviewSongPauseSelected;
|
||||||
songCancel: historyFileInCancel;
|
songPlay: overviewSongPlay;
|
||||||
songDownload: historyFileInDownload;
|
songPlaySelected: overviewSongPlaySelected;
|
||||||
|
songCancel: overviewSongCancel;
|
||||||
|
songCancelSelected: overviewSongCancelSelected;
|
||||||
|
songDownload: overviewSongDownload;
|
||||||
|
songDownloadSelected: overviewSongDownloadSelected;
|
||||||
|
|
||||||
filePadding: margins(0px, 3px, 16px, 3px);
|
filePadding: margins(0px, 3px, 16px, 3px);
|
||||||
fileThumbSize: 70px;
|
fileThumbSize: 70px;
|
||||||
|
@ -97,7 +116,7 @@ overviewLoaderSkip: 4px;
|
||||||
playlistHoverBg: windowBgOver;
|
playlistHoverBg: windowBgOver;
|
||||||
playlistPadding: 10px;
|
playlistPadding: 10px;
|
||||||
|
|
||||||
linksSearchMargin: margins(20px, 20px, 20px, 0px);
|
linksSearchTop: 30px;
|
||||||
linksMaxWidth: 520px;
|
linksMaxWidth: 520px;
|
||||||
linksLetterFg: #ffffff;
|
linksLetterFg: #ffffff;
|
||||||
linksLetterFont: font(24px);
|
linksLetterFont: font(24px);
|
||||||
|
|
|
@ -466,9 +466,10 @@ void Video::updateStatusText() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Voice::Voice(DocumentData *voice, HistoryItem *parent) : RadialProgressItem(parent)
|
Voice::Voice(DocumentData *voice, HistoryItem *parent, const style::OverviewFileLayout &st) : RadialProgressItem(parent)
|
||||||
, _data(voice)
|
, _data(voice)
|
||||||
, _namel(new DocumentOpenClickHandler(_data)) {
|
, _namel(new DocumentOpenClickHandler(_data))
|
||||||
|
, _st(st) {
|
||||||
AddComponents(Info::Bit());
|
AddComponents(Info::Bit());
|
||||||
|
|
||||||
t_assert(_data->voice() != 0);
|
t_assert(_data->voice() != 0);
|
||||||
|
@ -483,8 +484,8 @@ Voice::Voice(DocumentData *voice, HistoryItem *parent) : RadialProgressItem(pare
|
||||||
}
|
}
|
||||||
|
|
||||||
void Voice::initDimensions() {
|
void Voice::initDimensions() {
|
||||||
_maxw = st::overviewFileLayout.maxWidth;
|
_maxw = _st.maxWidth;
|
||||||
_minh = st::overviewFileLayout.songPadding.top() + st::overviewFileLayout.songThumbSize + st::overviewFileLayout.songPadding.bottom() + st::lineWidth;
|
_minh = _st.songPadding.top() + _st.songThumbSize + _st.songPadding.bottom() + st::lineWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) {
|
void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) {
|
||||||
|
@ -508,16 +509,16 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const
|
||||||
|
|
||||||
int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = -1;
|
int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = -1;
|
||||||
|
|
||||||
nameleft = st::overviewFileLayout.songPadding.left() + st::overviewFileLayout.songThumbSize + st::overviewFileLayout.songPadding.right();
|
nameleft = _st.songPadding.left() + _st.songThumbSize + _st.songPadding.right();
|
||||||
nameright = st::overviewFileLayout.songPadding.left();
|
nameright = _st.songPadding.left();
|
||||||
nametop = st::overviewFileLayout.songNameTop;
|
nametop = _st.songNameTop;
|
||||||
statustop = st::overviewFileLayout.songStatusTop;
|
statustop = _st.songStatusTop;
|
||||||
|
|
||||||
if (selected) {
|
if (selected) {
|
||||||
p.fillRect(clip.intersected(QRect(0, 0, _width, _height)), st::msgInBgSelected);
|
p.fillRect(clip.intersected(QRect(0, 0, _width, _height)), st::msgInBgSelected);
|
||||||
}
|
}
|
||||||
|
|
||||||
QRect inner(rtlrect(st::overviewFileLayout.songPadding.left(), st::overviewFileLayout.songPadding.top(), st::overviewFileLayout.songThumbSize, st::overviewFileLayout.songThumbSize, _width));
|
QRect inner(rtlrect(_st.songPadding.left(), _st.songPadding.top(), _st.songThumbSize, _st.songThumbSize, _width));
|
||||||
if (clip.intersects(inner)) {
|
if (clip.intersects(inner)) {
|
||||||
p.setPen(Qt::NoPen);
|
p.setPen(Qt::NoPen);
|
||||||
if (selected) {
|
if (selected) {
|
||||||
|
@ -540,13 +541,13 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const
|
||||||
|
|
||||||
auto icon = ([showPause, this, selected] {
|
auto icon = ([showPause, this, selected] {
|
||||||
if (showPause) {
|
if (showPause) {
|
||||||
return &(selected ? st::historyFileInPauseSelected : st::historyFileInPause);
|
return &(selected ? _st.songPauseSelected : _st.songPause);
|
||||||
} else if (_status.size() < 0 || _status.size() == FileStatusSizeLoaded) {
|
} else if (_status.size() < 0 || _status.size() == FileStatusSizeLoaded) {
|
||||||
return &(selected ? st::historyFileInPlaySelected : st::historyFileInPlay);
|
return &(selected ? _st.songPlaySelected : _st.songPlay);
|
||||||
} else if (_data->loading()) {
|
} else if (_data->loading()) {
|
||||||
return &(selected ? st::historyFileInCancelSelected : st::historyFileInCancel);
|
return &(selected ? _st.songCancelSelected : _st.songCancel);
|
||||||
}
|
}
|
||||||
return &(selected ? st::historyFileInDownloadSelected : st::historyFileInDownload);
|
return &(selected ? _st.songDownloadSelected : _st.songDownload);
|
||||||
})();
|
})();
|
||||||
icon->paintInCenter(p, inner);
|
icon->paintInCenter(p, inner);
|
||||||
}
|
}
|
||||||
|
@ -589,12 +590,12 @@ void Voice::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, i
|
||||||
|
|
||||||
int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = 0;
|
int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = 0;
|
||||||
|
|
||||||
nameleft = st::overviewFileLayout.songPadding.left() + st::overviewFileLayout.songThumbSize + st::overviewFileLayout.songPadding.right();
|
nameleft = _st.songPadding.left() + _st.songThumbSize + _st.songPadding.right();
|
||||||
nameright = st::overviewFileLayout.songPadding.left();
|
nameright = _st.songPadding.left();
|
||||||
nametop = st::overviewFileLayout.songNameTop;
|
nametop = _st.songNameTop;
|
||||||
statustop = st::overviewFileLayout.songStatusTop;
|
statustop = _st.songStatusTop;
|
||||||
|
|
||||||
auto inner = rtlrect(st::overviewFileLayout.songPadding.left(), st::overviewFileLayout.songPadding.top(), st::overviewFileLayout.songThumbSize, st::overviewFileLayout.songThumbSize, _width);
|
auto inner = rtlrect(_st.songPadding.left(), _st.songPadding.top(), _st.songThumbSize, _st.songThumbSize, _width);
|
||||||
if (inner.contains(x, y)) {
|
if (inner.contains(x, y)) {
|
||||||
link = loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _openl);
|
link = loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _openl);
|
||||||
return;
|
return;
|
||||||
|
@ -747,13 +748,13 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con
|
||||||
|
|
||||||
auto icon = ([showPause, loaded, this, selected] {
|
auto icon = ([showPause, loaded, this, selected] {
|
||||||
if (showPause) {
|
if (showPause) {
|
||||||
return &(selected ? st::historyFileInPauseSelected : _st.songPause);
|
return &(selected ? _st.songPauseSelected : _st.songPause);
|
||||||
} else if (loaded) {
|
} else if (loaded) {
|
||||||
return &(selected ? st::historyFileInPlaySelected : _st.songPlay);
|
return &(selected ? _st.songPlaySelected : _st.songPlay);
|
||||||
} else if (_data->loading()) {
|
} else if (_data->loading()) {
|
||||||
return &(selected ? st::historyFileInCancelSelected : _st.songCancel);
|
return &(selected ? _st.songCancelSelected : _st.songCancel);
|
||||||
}
|
}
|
||||||
return &(selected ? st::historyFileInDownloadSelected : _st.songDownload);
|
return &(selected ? _st.songDownloadSelected : _st.songDownload);
|
||||||
})();
|
})();
|
||||||
icon->paintInCenter(p, inner);
|
icon->paintInCenter(p, inner);
|
||||||
}
|
}
|
||||||
|
|
|
@ -244,7 +244,7 @@ private:
|
||||||
|
|
||||||
class Voice : public RadialProgressItem {
|
class Voice : public RadialProgressItem {
|
||||||
public:
|
public:
|
||||||
Voice(DocumentData *voice, HistoryItem *parent);
|
Voice(DocumentData *voice, HistoryItem *parent, const style::OverviewFileLayout &st);
|
||||||
|
|
||||||
void initDimensions() override;
|
void initDimensions() override;
|
||||||
void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override;
|
void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override;
|
||||||
|
@ -269,6 +269,8 @@ private:
|
||||||
StatusText _status;
|
StatusText _status;
|
||||||
ClickHandlerPtr _namel;
|
ClickHandlerPtr _namel;
|
||||||
|
|
||||||
|
const style::OverviewFileLayout &_st;
|
||||||
|
|
||||||
Text _name, _details;
|
Text _name, _details;
|
||||||
int _nameVersion;
|
int _nameVersion;
|
||||||
|
|
||||||
|
|
|
@ -1276,14 +1276,21 @@ int32 OverviewInner::resizeToWidth(int32 nwidth, int32 scrollTop, int32 minHeigh
|
||||||
if (_type == OverviewPhotos || _type == OverviewVideos) {
|
if (_type == OverviewPhotos || _type == OverviewVideos) {
|
||||||
_photosInRow = int32(_width - st::overviewPhotoSkip) / int32(st::overviewPhotoMinSize + st::overviewPhotoSkip);
|
_photosInRow = int32(_width - st::overviewPhotoSkip) / int32(st::overviewPhotoMinSize + st::overviewPhotoSkip);
|
||||||
_rowWidth = (int32(_width - st::overviewPhotoSkip) / _photosInRow) - st::overviewPhotoSkip;
|
_rowWidth = (int32(_width - st::overviewPhotoSkip) / _photosInRow) - st::overviewPhotoSkip;
|
||||||
} else if (_type == OverviewLinks) {
|
_rowsLeft = st::overviewPhotoSkip;
|
||||||
_rowWidth = qMin(_width - st::linksSearchMargin.left() - st::linksSearchMargin.right(), int32(st::linksMaxWidth));
|
|
||||||
} else {
|
} else {
|
||||||
_rowWidth = qMin(_width - st::profilePadding.left() - st::profilePadding.right(), st::overviewFileLayout.maxWidth);
|
auto contentLeftMin = st::overviewLeftMin;
|
||||||
|
auto contentLeftMax = st::overviewLeftMax;
|
||||||
|
if (_type == OverviewMusicFiles || _type == OverviewVoiceFiles) {
|
||||||
|
contentLeftMin -= st::overviewFileLayout.songPadding.left();
|
||||||
|
contentLeftMax -= st::overviewFileLayout.songPadding.left();
|
||||||
|
}
|
||||||
|
auto widthWithMin = st::windowMinWidth;
|
||||||
|
auto widthWithMax = st::overviewFileLayout.maxWidth + 2 * contentLeftMax;
|
||||||
|
_rowsLeft = anim::interpolate(contentLeftMax, contentLeftMin, qMax(widthWithMax - _width, 0) / float64(widthWithMax - widthWithMin));
|
||||||
|
_rowWidth = qMin(_width - 2 * _rowsLeft, st::overviewFileLayout.maxWidth);
|
||||||
}
|
}
|
||||||
_rowsLeft = (_width - _rowWidth) / 2;
|
|
||||||
|
|
||||||
_search->setGeometry(_rowsLeft, st::linksSearchMargin.top(), _rowWidth, _search->height());
|
_search->setGeometry(_rowsLeft, st::linksSearchTop, _rowWidth, _search->height());
|
||||||
_cancelSearch->moveToLeft(_rowsLeft + _rowWidth - _cancelSearch->width(), _search->y());
|
_cancelSearch->moveToLeft(_rowsLeft + _rowWidth - _cancelSearch->width(), _search->y());
|
||||||
|
|
||||||
if (_type == OverviewPhotos || _type == OverviewVideos) {
|
if (_type == OverviewPhotos || _type == OverviewVideos) {
|
||||||
|
@ -1797,7 +1804,7 @@ void OverviewInner::recountMargins() {
|
||||||
_marginTop = st::playlistPadding;
|
_marginTop = st::playlistPadding;
|
||||||
_marginBottom = qMax(_minHeight - _height - _marginTop, int32(st::playlistPadding));
|
_marginBottom = qMax(_minHeight - _height - _marginTop, int32(st::playlistPadding));
|
||||||
} else if (_type == OverviewLinks || _type == OverviewFiles) {
|
} else if (_type == OverviewLinks || _type == OverviewFiles) {
|
||||||
_marginTop = st::linksSearchMargin.top() + _search->height() + st::linksSearchMargin.bottom();
|
_marginTop = st::linksSearchTop + _search->height();
|
||||||
_marginBottom = qMax(_minHeight - _height - _marginTop, int32(st::playlistPadding));
|
_marginBottom = qMax(_minHeight - _height - _marginTop, int32(st::playlistPadding));
|
||||||
} else {
|
} else {
|
||||||
_marginBottom = st::playlistPadding;
|
_marginBottom = st::playlistPadding;
|
||||||
|
@ -1827,7 +1834,7 @@ Overview::Layout::ItemBase *OverviewInner::layoutPrepare(HistoryItem *item) {
|
||||||
} else if (_type == OverviewVoiceFiles) {
|
} else if (_type == OverviewVoiceFiles) {
|
||||||
if (media && (media->type() == MediaTypeVoiceFile)) {
|
if (media && (media->type() == MediaTypeVoiceFile)) {
|
||||||
if ((i = _layoutItems.constFind(item)) == _layoutItems.cend()) {
|
if ((i = _layoutItems.constFind(item)) == _layoutItems.cend()) {
|
||||||
i = _layoutItems.insert(item, new Overview::Layout::Voice(media->getDocument(), item));
|
i = _layoutItems.insert(item, new Overview::Layout::Voice(media->getDocument(), item, st::overviewFileLayout));
|
||||||
i.value()->initDimensions();
|
i.value()->initDimensions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,3 +144,14 @@ profileVerifiedCheck: icon {
|
||||||
{ "profile_verified_star", windowBgActive, point(0px, 7px) },
|
{ "profile_verified_star", windowBgActive, point(0px, 7px) },
|
||||||
{ "profile_verified_check", windowFgActive, point(4px, 11px) }
|
{ "profile_verified_check", windowFgActive, point(4px, 11px) }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
profileCommonGroupsSkip: 24px;
|
||||||
|
profileCommonGroupsLeftMin: 24px;
|
||||||
|
profileCommonGroupsLeftMax: 36px;
|
||||||
|
profileCommonGroupsWidthMax: 480px;
|
||||||
|
profileCommonGroupsPadding: margins(7px, 7px, 7px, 7px);
|
||||||
|
profileCommonGroupsPhotoSize: 42px;
|
||||||
|
profileCommonGroupsNameTop: 12px;
|
||||||
|
profileCommonGroupsNameLeft: 16px;
|
||||||
|
profileCommonGroupsBgOver: windowBgOver;
|
||||||
|
profileCommonGroupsRipple: defaultRippleAnimation;
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "profile/profile_back_button.h"
|
||||||
|
|
||||||
|
#include "window/top_bar_widget.h"
|
||||||
|
#include "styles/style_widgets.h"
|
||||||
|
#include "styles/style_window.h"
|
||||||
|
#include "styles/style_profile.h"
|
||||||
|
|
||||||
|
namespace Profile {
|
||||||
|
|
||||||
|
BackButton::BackButton(QWidget *parent, const QString &text) : Ui::AbstractButton(parent)
|
||||||
|
, _text(text.toUpper()) {
|
||||||
|
setCursor(style::cur_pointer);
|
||||||
|
|
||||||
|
subscribe(Adaptive::Changed(), [this] { updateAdaptiveLayout(); });
|
||||||
|
updateAdaptiveLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
int BackButton::resizeGetHeight(int newWidth) {
|
||||||
|
return st::profileTopBarHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackButton::paintEvent(QPaintEvent *e) {
|
||||||
|
Painter p(this);
|
||||||
|
|
||||||
|
p.fillRect(e->rect(), st::profileBg);
|
||||||
|
st::topBarBack.paint(p, (st::topBarArrowPadding.left() - st::topBarBack.width()) / 2, (st::topBarHeight - st::topBarBack.height()) / 2, width());
|
||||||
|
|
||||||
|
p.setFont(st::topBarButton.font);
|
||||||
|
p.setPen(st::topBarButton.textFg);
|
||||||
|
p.drawTextLeft(st::topBarArrowPadding.left(), st::topBarButton.padding.top() + st::topBarButton.textTop, width(), _text);
|
||||||
|
|
||||||
|
Window::TopBarWidget::paintUnreadCounter(p, width());
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackButton::onStateChanged(State was, StateChangeSource source) {
|
||||||
|
if (isDown() && !(was & StateFlag::Down)) {
|
||||||
|
emit clicked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackButton::updateAdaptiveLayout() {
|
||||||
|
if (!Adaptive::OneColumn()) {
|
||||||
|
unsubscribe(base::take(_unreadCounterSubscription));
|
||||||
|
} else if (!_unreadCounterSubscription) {
|
||||||
|
_unreadCounterSubscription = subscribe(Global::RefUnreadCounterUpdate(), [this] {
|
||||||
|
rtlupdate(0, 0, st::titleUnreadCounterRight, st::titleUnreadCounterTop);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Profile
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ui/abstract_button.h"
|
||||||
|
|
||||||
|
namespace Profile {
|
||||||
|
|
||||||
|
class BackButton final : public Ui::AbstractButton, private base::Subscriber {
|
||||||
|
public:
|
||||||
|
BackButton(QWidget *parent, const QString &text);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
|
||||||
|
int resizeGetHeight(int newWidth) override;
|
||||||
|
void onStateChanged(State was, StateChangeSource source) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateAdaptiveLayout();
|
||||||
|
|
||||||
|
int _unreadCounterSubscription = 0;
|
||||||
|
QString _text;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Profile
|
|
@ -1,175 +0,0 @@
|
||||||
/*
|
|
||||||
This file is part of Telegram Desktop,
|
|
||||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
|
||||||
|
|
||||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
It is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
In addition, as a special exception, the copyright holders give permission
|
|
||||||
to link the code of portions of this program with the OpenSSL library.
|
|
||||||
|
|
||||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
|
||||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|
||||||
*/
|
|
||||||
#include "stdafx.h"
|
|
||||||
#include "profile/profile_block_common_groups.h"
|
|
||||||
|
|
||||||
#include "profile/profile_section_memento.h"
|
|
||||||
#include "styles/style_widgets.h"
|
|
||||||
#include "observer_peer.h"
|
|
||||||
#include "apiwrap.h"
|
|
||||||
#include "lang.h"
|
|
||||||
|
|
||||||
namespace Profile {
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
constexpr int kCommonGroupsPerPage = 20;
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
CommonGroupsWidget::CommonGroupsWidget(QWidget *parent, PeerData *peer)
|
|
||||||
: PeerListWidget(parent, peer, lang(lng_profile_common_groups_section)) {
|
|
||||||
refreshVisibility();
|
|
||||||
|
|
||||||
auto observeEvents = Notify::PeerUpdate::Flag::MembersChanged;
|
|
||||||
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
|
|
||||||
notifyPeerUpdated(update);
|
|
||||||
}));
|
|
||||||
|
|
||||||
setSelectedCallback([this](PeerData *selectedPeer) {
|
|
||||||
Ui::showPeerHistory(selectedPeer, ShowAtUnreadMsgId, Ui::ShowWay::Forward);
|
|
||||||
});
|
|
||||||
setPreloadMoreCallback([this] {
|
|
||||||
preloadMore();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommonGroupsWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) {
|
|
||||||
for_const (auto item, items()) {
|
|
||||||
if (item->peer == update.peer) {
|
|
||||||
updateStatusText(item);
|
|
||||||
this->update();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int CommonGroupsWidget::resizeGetHeight(int newWidth) {
|
|
||||||
auto result = PeerListWidget::resizeGetHeight(newWidth);
|
|
||||||
return qRound(_height.current(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommonGroupsWidget::paintContents(Painter &p) {
|
|
||||||
_height.animating(getms());
|
|
||||||
return PeerListWidget::paintContents(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommonGroupsWidget::saveState(SectionMemento *memento) const {
|
|
||||||
if (auto count = itemsCount()) {
|
|
||||||
QList<PeerData*> groups;
|
|
||||||
groups.reserve(count);
|
|
||||||
for_const (auto item, items()) {
|
|
||||||
groups.push_back(item->peer);
|
|
||||||
}
|
|
||||||
memento->setCommonGroups(groups);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommonGroupsWidget::restoreState(const SectionMemento *memento) {
|
|
||||||
CommonGroupsEvent event;
|
|
||||||
event.groups = memento->getCommonGroups();
|
|
||||||
if (!event.groups.empty()) {
|
|
||||||
onShowCommonGroups(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommonGroupsWidget::onShowCommonGroups(const CommonGroupsEvent &event) {
|
|
||||||
for_const (auto group, event.groups) {
|
|
||||||
addItem(computeItem(group));
|
|
||||||
_preloadGroupId = group->bareId();
|
|
||||||
}
|
|
||||||
refreshVisibility();
|
|
||||||
if (event.initialHeight >= 0) {
|
|
||||||
_height.start([this] { contentSizeUpdated(); }, event.initialHeight, resizeGetHeight(width()), st::widgetSlideDuration);
|
|
||||||
}
|
|
||||||
contentSizeUpdated();
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommonGroupsWidget::preloadMore() {
|
|
||||||
if (_preloadRequestId || !_preloadGroupId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto user = peer()->asUser();
|
|
||||||
t_assert(user != nullptr);
|
|
||||||
auto request = MTPmessages_GetCommonChats(user->inputUser, MTP_int(_preloadGroupId), MTP_int(kCommonGroupsPerPage));
|
|
||||||
_preloadRequestId = MTP::send(request, ::rpcDone(base::lambda_guarded(this, [this](const MTPmessages_Chats &result) {
|
|
||||||
_preloadRequestId = 0;
|
|
||||||
_preloadGroupId = 0;
|
|
||||||
|
|
||||||
if (auto chats = Api::getChatsFromMessagesChats(result)) {
|
|
||||||
auto &list = chats->c_vector().v;
|
|
||||||
if (!list.empty()) {
|
|
||||||
reserveItemsForSize(itemsCount() + list.size());
|
|
||||||
for_const (auto &chatData, list) {
|
|
||||||
if (auto chat = App::feedChat(chatData)) {
|
|
||||||
addItem(computeItem(chat));
|
|
||||||
_preloadGroupId = chat->bareId();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
contentSizeUpdated();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommonGroupsWidget::updateStatusText(Item *item) {
|
|
||||||
auto group = item->peer;
|
|
||||||
if (auto chat = group->asChat()) {
|
|
||||||
auto count = qMax(chat->count, chat->participants.size());
|
|
||||||
item->statusText = count ? lng_chat_status_members(lt_count, count) : lang(lng_group_status);
|
|
||||||
} else if (auto megagroup = group->asMegagroup()) {
|
|
||||||
auto count = megagroup->membersCount();
|
|
||||||
item->statusText = (count > 0) ? lng_chat_status_members(lt_count, count) : lang(lng_group_status);
|
|
||||||
|
|
||||||
// Request members count.
|
|
||||||
if (!megagroup->wasFullUpdated()) App::api()->requestFullPeer(megagroup);
|
|
||||||
} else if (auto channel = group->asChannel()) {
|
|
||||||
auto count = channel->membersCount();
|
|
||||||
item->statusText = (count > 0) ? lng_chat_status_members(lt_count, count) : lang(lng_channel_status);
|
|
||||||
|
|
||||||
// Request members count.
|
|
||||||
if (!channel->wasFullUpdated()) App::api()->requestFullPeer(channel);
|
|
||||||
} else {
|
|
||||||
t_assert(!"Users should not get to CommonGroupsWidget::updateStatusText()");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CommonGroupsWidget::Item *CommonGroupsWidget::computeItem(PeerData *group) {
|
|
||||||
// Skip groups that migrated to supergroups.
|
|
||||||
if (group->migrateTo()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto it = _dataMap.constFind(group);
|
|
||||||
if (it == _dataMap.cend()) {
|
|
||||||
it = _dataMap.insert(group, new Item(group));
|
|
||||||
updateStatusText(it.value());
|
|
||||||
}
|
|
||||||
return it.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
CommonGroupsWidget::~CommonGroupsWidget() {
|
|
||||||
for (auto item : base::take(_dataMap)) {
|
|
||||||
delete item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Profile
|
|
|
@ -1,75 +0,0 @@
|
||||||
/*
|
|
||||||
This file is part of Telegram Desktop,
|
|
||||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
|
||||||
|
|
||||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
It is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
In addition, as a special exception, the copyright holders give permission
|
|
||||||
to link the code of portions of this program with the OpenSSL library.
|
|
||||||
|
|
||||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
|
||||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "profile/profile_block_peer_list.h"
|
|
||||||
|
|
||||||
namespace Notify {
|
|
||||||
struct PeerUpdate;
|
|
||||||
} // namespace Notify
|
|
||||||
|
|
||||||
namespace Profile {
|
|
||||||
|
|
||||||
struct CommonGroupsEvent {
|
|
||||||
QList<PeerData*> groups;
|
|
||||||
|
|
||||||
// If initialHeight >= 0 the common groups widget will
|
|
||||||
// slide down starting from height() == initialHeight.
|
|
||||||
// Otherwise it will just show instantly.
|
|
||||||
int initialHeight = -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CommonGroupsWidget : public PeerListWidget {
|
|
||||||
public:
|
|
||||||
CommonGroupsWidget(QWidget *parent, PeerData *peer);
|
|
||||||
|
|
||||||
void setShowCommonGroupsObservable(base::Observable<CommonGroupsEvent> *observable) {
|
|
||||||
subscribe(observable, [this](const CommonGroupsEvent &event) { onShowCommonGroups(event); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void saveState(SectionMemento *memento) const override;
|
|
||||||
void restoreState(const SectionMemento *memento) override;
|
|
||||||
|
|
||||||
~CommonGroupsWidget();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
int resizeGetHeight(int newWidth) override;
|
|
||||||
void paintContents(Painter &p) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Observed notifications.
|
|
||||||
void notifyPeerUpdated(const Notify::PeerUpdate &update);
|
|
||||||
|
|
||||||
void updateStatusText(Item *item);
|
|
||||||
void onShowCommonGroups(const CommonGroupsEvent &event);
|
|
||||||
void preloadMore();
|
|
||||||
|
|
||||||
Item *computeItem(PeerData *group);
|
|
||||||
QMap<PeerData*, Item*> _dataMap;
|
|
||||||
|
|
||||||
Animation _height;
|
|
||||||
|
|
||||||
int32 _preloadGroupId = 0;
|
|
||||||
mtpRequestId _preloadRequestId = 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Profile
|
|
|
@ -21,13 +21,14 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "profile/profile_block_info.h"
|
#include "profile/profile_block_info.h"
|
||||||
|
|
||||||
#include "profile/profile_block_common_groups.h"
|
#include "profile/profile_common_groups_section.h"
|
||||||
#include "profile/profile_section_memento.h"
|
#include "profile/profile_section_memento.h"
|
||||||
#include "styles/style_profile.h"
|
#include "styles/style_profile.h"
|
||||||
#include "ui/widgets/labels.h"
|
#include "ui/widgets/labels.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/effects/widget_slide_wrap.h"
|
#include "ui/effects/widget_slide_wrap.h"
|
||||||
#include "core/click_handler_types.h"
|
#include "core/click_handler_types.h"
|
||||||
|
#include "mainwidget.h"
|
||||||
#include "observer_peer.h"
|
#include "observer_peer.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
|
@ -69,12 +70,6 @@ void InfoWidget::slideCommonGroupsDown() {
|
||||||
contentSizeUpdated();
|
contentSizeUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InfoWidget::restoreState(const SectionMemento *memento) {
|
|
||||||
if (!memento->getCommonGroups().isEmpty()) {
|
|
||||||
onForceHideCommonGroups();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InfoWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) {
|
void InfoWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) {
|
||||||
if (update.peer != peer()) {
|
if (update.peer != peer()) {
|
||||||
return;
|
return;
|
||||||
|
@ -253,7 +248,7 @@ int InfoWidget::getCommonGroupsCount() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void InfoWidget::refreshCommonGroups() {
|
void InfoWidget::refreshCommonGroups() {
|
||||||
if (auto count = (_forceHiddenCommonGroups ? 0 : getCommonGroupsCount())) {
|
if (auto count = getCommonGroupsCount()) {
|
||||||
auto text = lng_profile_common_groups(lt_count, count);
|
auto text = lng_profile_common_groups(lt_count, count);
|
||||||
if (_commonGroups) {
|
if (_commonGroups) {
|
||||||
_commonGroups->setText(text);
|
_commonGroups->setText(text);
|
||||||
|
@ -270,56 +265,15 @@ void InfoWidget::refreshCommonGroups() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InfoWidget::setShowCommonGroupsObservable(base::Observable<CommonGroupsEvent> *observable) {
|
|
||||||
_showCommonGroupsObservable = observable;
|
|
||||||
subscribe(_showCommonGroupsObservable, [this](const CommonGroupsEvent &event) {
|
|
||||||
onForceHideCommonGroups();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void InfoWidget::onForceHideCommonGroups() {
|
|
||||||
if (_forceHiddenCommonGroups) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_forceHiddenCommonGroups = true;
|
|
||||||
_commonGroups.destroyDelayed();
|
|
||||||
refreshVisibility();
|
|
||||||
contentSizeUpdated();
|
|
||||||
}
|
|
||||||
|
|
||||||
void InfoWidget::onShowCommonGroups() {
|
void InfoWidget::onShowCommonGroups() {
|
||||||
auto count = getCommonGroupsCount();
|
auto count = getCommonGroupsCount();
|
||||||
if (count <= 0) {
|
if (count <= 0) {
|
||||||
refreshCommonGroups();
|
refreshCommonGroups();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_getCommonGroupsRequestId) {
|
if (auto main = App::main()) {
|
||||||
return;
|
main->showWideSection(Profile::CommonGroups::SectionMemento(peer()));
|
||||||
}
|
}
|
||||||
auto user = peer()->asUser();
|
|
||||||
t_assert(user != nullptr);
|
|
||||||
auto request = MTPmessages_GetCommonChats(user->inputUser, MTP_int(0), MTP_int(kCommonGroupsLimit));
|
|
||||||
_getCommonGroupsRequestId = MTP::send(request, ::rpcDone(base::lambda_guarded(this, [this](const MTPmessages_Chats &result) {
|
|
||||||
_getCommonGroupsRequestId = 0;
|
|
||||||
|
|
||||||
CommonGroupsEvent event;
|
|
||||||
if (auto chats = Api::getChatsFromMessagesChats(result)) {
|
|
||||||
auto &list = chats->c_vector().v;
|
|
||||||
event.groups.reserve(list.size());
|
|
||||||
for_const (auto &chatData, list) {
|
|
||||||
if (auto chat = App::feedChat(chatData)) {
|
|
||||||
event.groups.push_back(chat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto oldHeight = height();
|
|
||||||
onForceHideCommonGroups();
|
|
||||||
if (!event.groups.empty() && _showCommonGroupsObservable) {
|
|
||||||
event.initialHeight = oldHeight - (isHidden() ? 0 : height());
|
|
||||||
_showCommonGroupsObservable->notify(event, true);
|
|
||||||
}
|
|
||||||
})));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InfoWidget::setLabeledText(ChildWidget<Ui::FlatLabel> *labelWidget, const QString &label,
|
void InfoWidget::setLabeledText(ChildWidget<Ui::FlatLabel> *labelWidget, const QString &label,
|
||||||
|
|
|
@ -36,17 +36,12 @@ class LeftOutlineButton;
|
||||||
|
|
||||||
namespace Profile {
|
namespace Profile {
|
||||||
|
|
||||||
struct CommonGroupsEvent;
|
|
||||||
class InfoWidget : public BlockWidget, public RPCSender {
|
class InfoWidget : public BlockWidget, public RPCSender {
|
||||||
public:
|
public:
|
||||||
InfoWidget(QWidget *parent, PeerData *peer);
|
InfoWidget(QWidget *parent, PeerData *peer);
|
||||||
|
|
||||||
void setShowCommonGroupsObservable(base::Observable<CommonGroupsEvent> *observable);
|
|
||||||
|
|
||||||
void showFinished() override;
|
void showFinished() override;
|
||||||
|
|
||||||
void restoreState(const SectionMemento *memento) override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Resizes content and counts natural widget height for the desired width.
|
// Resizes content and counts natural widget height for the desired width.
|
||||||
int resizeGetHeight(int newWidth) override;
|
int resizeGetHeight(int newWidth) override;
|
||||||
|
@ -66,7 +61,6 @@ private:
|
||||||
void refreshVisibility();
|
void refreshVisibility();
|
||||||
|
|
||||||
int getCommonGroupsCount() const;
|
int getCommonGroupsCount() const;
|
||||||
void onForceHideCommonGroups();
|
|
||||||
void onShowCommonGroups();
|
void onShowCommonGroups();
|
||||||
void slideCommonGroupsDown();
|
void slideCommonGroupsDown();
|
||||||
|
|
||||||
|
@ -87,11 +81,6 @@ private:
|
||||||
Animation _height;
|
Animation _height;
|
||||||
bool _showFinished = false;
|
bool _showFinished = false;
|
||||||
|
|
||||||
bool _forceHiddenCommonGroups = false;
|
|
||||||
mtpRequestId _getCommonGroupsRequestId = 0;
|
|
||||||
|
|
||||||
base::Observable<CommonGroupsEvent> *_showCommonGroupsObservable = nullptr;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Profile
|
} // namespace Profile
|
||||||
|
|
|
@ -0,0 +1,446 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "profile/profile_common_groups_section.h"
|
||||||
|
|
||||||
|
#include "profile/profile_section_memento.h"
|
||||||
|
#include "profile/profile_back_button.h"
|
||||||
|
#include "styles/style_widgets.h"
|
||||||
|
#include "styles/style_profile.h"
|
||||||
|
#include "styles/style_window.h"
|
||||||
|
#include "styles/style_settings.h"
|
||||||
|
#include "ui/effects/ripple_animation.h"
|
||||||
|
#include "ui/widgets/scroll_area.h"
|
||||||
|
#include "ui/widgets/shadow.h"
|
||||||
|
#include "mainwidget.h"
|
||||||
|
#include "observer_peer.h"
|
||||||
|
#include "apiwrap.h"
|
||||||
|
#include "lang.h"
|
||||||
|
|
||||||
|
namespace Profile {
|
||||||
|
namespace CommonGroups {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr int kCommonGroupsPerPage = 40;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Window::SectionWidget *SectionMemento::createWidget(QWidget *parent, const QRect &geometry) const {
|
||||||
|
auto result = new Widget(parent, _peer);
|
||||||
|
result->setInternalState(geometry, this);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FixedBar::FixedBar(QWidget *parent) : TWidget(parent)
|
||||||
|
, _backButton(this, lang(lng_profile_common_groups_section)) {
|
||||||
|
_backButton->moveToLeft(0, 0);
|
||||||
|
connect(_backButton, SIGNAL(clicked()), this, SLOT(onBack()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FixedBar::onBack() {
|
||||||
|
App::main()->showBackFromStack();
|
||||||
|
}
|
||||||
|
|
||||||
|
int FixedBar::resizeGetHeight(int newWidth) {
|
||||||
|
auto newHeight = 0;
|
||||||
|
|
||||||
|
auto buttonLeft = newWidth;
|
||||||
|
_backButton->resizeToWidth(newWidth);
|
||||||
|
_backButton->moveToLeft(0, 0);
|
||||||
|
newHeight += _backButton->height();
|
||||||
|
|
||||||
|
return newHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FixedBar::setAnimatingMode(bool enabled) {
|
||||||
|
if (_animatingMode != enabled) {
|
||||||
|
_animatingMode = enabled;
|
||||||
|
setCursor(_animatingMode ? style::cur_pointer : style::cur_default);
|
||||||
|
if (_animatingMode) {
|
||||||
|
setAttribute(Qt::WA_OpaquePaintEvent, false);
|
||||||
|
hideChildren();
|
||||||
|
} else {
|
||||||
|
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
|
showChildren();
|
||||||
|
}
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FixedBar::mousePressEvent(QMouseEvent *e) {
|
||||||
|
if (e->button() == Qt::LeftButton) {
|
||||||
|
onBack();
|
||||||
|
} else {
|
||||||
|
TWidget::mousePressEvent(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InnerWidget::Item::Item(PeerData *peer) : peer(peer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
InnerWidget::Item::~Item() = default;
|
||||||
|
|
||||||
|
InnerWidget::InnerWidget(QWidget *parent, PeerData *peer) : TWidget(parent)
|
||||||
|
, _peer(peer) {
|
||||||
|
setMouseTracking(true);
|
||||||
|
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
|
_rowHeight = st::profileCommonGroupsPadding.top() + st::profileCommonGroupsPhotoSize + st::profileCommonGroupsPadding.bottom();
|
||||||
|
_contentTop = st::profileCommonGroupsSkip;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) {
|
||||||
|
_visibleTop = visibleTop;
|
||||||
|
_visibleBottom = visibleBottom;
|
||||||
|
|
||||||
|
checkPreloadMore();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::checkPreloadMore() {
|
||||||
|
if (_visibleTop + PreloadHeightsCount * (_visibleBottom - _visibleTop) > height()) {
|
||||||
|
preloadMore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::saveState(SectionMemento *memento) const {
|
||||||
|
if (auto count = _items.size()) {
|
||||||
|
QList<PeerData*> groups;
|
||||||
|
groups.reserve(count);
|
||||||
|
for_const (auto item, _items) {
|
||||||
|
groups.push_back(item->peer);
|
||||||
|
}
|
||||||
|
memento->setCommonGroups(groups);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::restoreState(const SectionMemento *memento) {
|
||||||
|
auto list = memento->getCommonGroups();
|
||||||
|
_allLoaded = false;
|
||||||
|
if (!list.empty()) {
|
||||||
|
showInitial(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::showInitial(const QList<PeerData*> &list) {
|
||||||
|
for_const (auto group, list) {
|
||||||
|
_items.push_back(computeItem(group));
|
||||||
|
_preloadGroupId = group->bareId();
|
||||||
|
}
|
||||||
|
updateSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::preloadMore() {
|
||||||
|
if (_preloadRequestId || _allLoaded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto user = peer()->asUser();
|
||||||
|
t_assert(user != nullptr);
|
||||||
|
auto request = MTPmessages_GetCommonChats(user->inputUser, MTP_int(_preloadGroupId), MTP_int(kCommonGroupsPerPage));
|
||||||
|
_preloadRequestId = MTP::send(request, ::rpcDone(base::lambda_guarded(this, [this](const MTPmessages_Chats &result) {
|
||||||
|
_preloadRequestId = 0;
|
||||||
|
_preloadGroupId = 0;
|
||||||
|
_allLoaded = true;
|
||||||
|
if (auto chats = Api::getChatsFromMessagesChats(result)) {
|
||||||
|
auto &list = chats->c_vector().v;
|
||||||
|
if (!list.empty()) {
|
||||||
|
_items.reserve(_items.size() + list.size());
|
||||||
|
for_const (auto &chatData, list) {
|
||||||
|
if (auto chat = App::feedChat(chatData)) {
|
||||||
|
auto found = false;
|
||||||
|
for_const (auto item, _items) {
|
||||||
|
if (item->peer == chat) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
_items.push_back(computeItem(chat));
|
||||||
|
}
|
||||||
|
_preloadGroupId = chat->bareId();
|
||||||
|
_allLoaded = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::updateSize() {
|
||||||
|
TWidget::resizeToWidth(width());
|
||||||
|
checkPreloadMore();
|
||||||
|
}
|
||||||
|
|
||||||
|
int InnerWidget::resizeGetHeight(int newWidth) {
|
||||||
|
update();
|
||||||
|
|
||||||
|
auto contentLeftMin = st::profileCommonGroupsLeftMin;
|
||||||
|
auto contentLeftMax = st::profileCommonGroupsLeftMax;
|
||||||
|
auto widthWithMin = st::windowMinWidth;
|
||||||
|
auto widthWithMax = st::profileCommonGroupsWidthMax + 2 * contentLeftMax;
|
||||||
|
_contentLeft = anim::interpolate(contentLeftMax, contentLeftMin, qMax(widthWithMax - newWidth, 0) / float64(widthWithMax - widthWithMin));
|
||||||
|
_contentWidth = qMin(newWidth - 2 * _contentLeft, st::profileCommonGroupsWidthMax);
|
||||||
|
|
||||||
|
auto newHeight = _contentTop;
|
||||||
|
newHeight += _items.size() * _rowHeight;
|
||||||
|
newHeight += st::profileCommonGroupsSkip;
|
||||||
|
return qMax(newHeight, _minHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::paintEvent(QPaintEvent *e) {
|
||||||
|
Painter p(this);
|
||||||
|
|
||||||
|
auto ms = getms();
|
||||||
|
auto clip = e->rect();
|
||||||
|
p.fillRect(clip, st::profileBg);
|
||||||
|
|
||||||
|
auto from = floorclamp(clip.y() - _contentTop, _rowHeight, 0, _items.size());
|
||||||
|
auto to = ceilclamp(clip.y() + clip.height() - _contentTop, _rowHeight, 0, _items.size());
|
||||||
|
for (auto i = from; i != to; ++i) {
|
||||||
|
paintRow(p, i, ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::paintRow(Painter &p, int index, TimeMs ms) {
|
||||||
|
auto item = _items[index];
|
||||||
|
auto selected = (_pressed >= 0) ? (index == _pressed) : (index == _selected);
|
||||||
|
|
||||||
|
auto x = _contentLeft;
|
||||||
|
auto y = _contentTop + index * _rowHeight;
|
||||||
|
if (selected) {
|
||||||
|
p.fillRect(myrtlrect(x, y, _contentWidth, _rowHeight), st::profileCommonGroupsBgOver);
|
||||||
|
}
|
||||||
|
if (auto &ripple = item->ripple) {
|
||||||
|
ripple->paint(p, x, y, width(), ms);
|
||||||
|
if (ripple->empty()) {
|
||||||
|
ripple.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
x += st::profileCommonGroupsPadding.left();
|
||||||
|
y += st::profileCommonGroupsPadding.top();
|
||||||
|
item->peer->paintUserpic(p, st::profileCommonGroupsPhotoSize, rtl() ? (width() - x - st::profileCommonGroupsPhotoSize) : x, y);
|
||||||
|
|
||||||
|
x += st::profileCommonGroupsPhotoSize + st::profileCommonGroupsNameLeft;
|
||||||
|
y += st::profileCommonGroupsNameTop;
|
||||||
|
auto nameWidth = _contentWidth - (x - _contentLeft) - st::profileCommonGroupsPadding.right();
|
||||||
|
if (item->name.isEmpty()) {
|
||||||
|
item->name.setText(st::semiboldFont, App::peerName(item->peer), _textNameOptions);
|
||||||
|
}
|
||||||
|
_items[index]->name.drawLeftElided(p, x, y, nameWidth, width());
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::keyPressEvent(QKeyEvent *e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::updateSelected(QPoint localPos) {
|
||||||
|
auto selected = -1;
|
||||||
|
auto selectedKick = false;
|
||||||
|
|
||||||
|
if (rtl()) localPos.setX(width() - localPos.x());
|
||||||
|
if (localPos.x() >= _contentLeft && localPos.x() < _contentLeft + _contentWidth && localPos.y() >= _contentTop) {
|
||||||
|
selected = (localPos.y() - _contentTop) / _rowHeight;
|
||||||
|
if (selected >= _items.size()) {
|
||||||
|
selected = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_selected != selected) {
|
||||||
|
updateRow(_selected);
|
||||||
|
_selected = selected;
|
||||||
|
updateRow(_selected);
|
||||||
|
if (_pressed < 0) {
|
||||||
|
setCursor((_selected >= 0) ? style::cur_pointer : style::cur_default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::updateRow(int index) {
|
||||||
|
rtlupdate(_contentLeft, _contentTop + index * _rowHeight, _contentWidth, _rowHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::mousePressEvent(QMouseEvent *e) {
|
||||||
|
_pressed = _selected;
|
||||||
|
if (_pressed >= 0) {
|
||||||
|
auto item = _items[_pressed];
|
||||||
|
if (!item->ripple) {
|
||||||
|
auto mask = Ui::RippleAnimation::rectMask(QSize(_contentWidth, _rowHeight));
|
||||||
|
item->ripple = std_::make_unique<Ui::RippleAnimation>(st::profileCommonGroupsRipple, std_::move(mask), [this, index = _pressed] {
|
||||||
|
updateRow(index);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
auto left = _contentLeft;
|
||||||
|
auto top = _contentTop + _rowHeight * _pressed;
|
||||||
|
item->ripple->add(e->pos() - QPoint(left, top));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::mouseMoveEvent(QMouseEvent *e) {
|
||||||
|
updateSelected(e->pos());
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
|
updateRow(_pressed);
|
||||||
|
auto pressed = base::take(_pressed, -1);
|
||||||
|
if (pressed >= 0 && pressed < _items.size()) {
|
||||||
|
if (auto &ripple = _items[pressed]->ripple) {
|
||||||
|
ripple->lastStop();
|
||||||
|
}
|
||||||
|
if (pressed == _selected) {
|
||||||
|
Ui::showPeerHistory(_items[pressed]->peer, ShowAtUnreadMsgId, Ui::ShowWay::Forward);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setCursor(_selected ? style::cur_pointer : style::cur_default);
|
||||||
|
updateRow(_selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
InnerWidget::Item *InnerWidget::computeItem(PeerData *group) {
|
||||||
|
// Skip groups that migrated to supergroups.
|
||||||
|
if (group->migrateTo()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = _dataMap.constFind(group);
|
||||||
|
if (it == _dataMap.cend()) {
|
||||||
|
it = _dataMap.insert(group, new Item(group));
|
||||||
|
}
|
||||||
|
return it.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
InnerWidget::~InnerWidget() {
|
||||||
|
for (auto item : base::take(_dataMap)) {
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget::Widget(QWidget *parent, PeerData *peer) : Window::SectionWidget(parent)
|
||||||
|
, _scroll(this, st::settingsScroll)
|
||||||
|
, _inner(this, peer)
|
||||||
|
, _fixedBar(this)
|
||||||
|
, _fixedBarShadow(this, st::shadowColor) {
|
||||||
|
_fixedBar->move(0, 0);
|
||||||
|
_fixedBar->resizeToWidth(width());
|
||||||
|
_fixedBar->show();
|
||||||
|
|
||||||
|
_fixedBarShadow->raise();
|
||||||
|
updateAdaptiveLayout();
|
||||||
|
subscribe(Adaptive::Changed(), [this]() { updateAdaptiveLayout(); });
|
||||||
|
|
||||||
|
_scroll->setOwnedWidget(_inner);
|
||||||
|
_scroll->move(0, _fixedBar->height());
|
||||||
|
_scroll->show();
|
||||||
|
|
||||||
|
connect(_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
|
||||||
|
connect(_inner, SIGNAL(cancelled()), _fixedBar, SLOT(onBack()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::updateAdaptiveLayout() {
|
||||||
|
_fixedBarShadow->moveToLeft(Adaptive::OneColumn() ? 0 : st::lineWidth, _fixedBar->height());
|
||||||
|
}
|
||||||
|
|
||||||
|
PeerData *Widget::peer() const {
|
||||||
|
return _inner->peer();
|
||||||
|
}
|
||||||
|
|
||||||
|
QPixmap Widget::grabForShowAnimation(const Window::SectionSlideParams ¶ms) {
|
||||||
|
if (params.withTopBarShadow) _fixedBarShadow->hide();
|
||||||
|
auto result = myGrab(this);
|
||||||
|
if (params.withTopBarShadow) _fixedBarShadow->show();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::setInnerFocus() {
|
||||||
|
_inner->setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Widget::showInternal(const Window::SectionMemento *memento) {
|
||||||
|
if (auto profileMemento = dynamic_cast<const SectionMemento*>(memento)) {
|
||||||
|
if (profileMemento->getPeer() == peer()) {
|
||||||
|
restoreState(profileMemento);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::setInternalState(const QRect &geometry, const SectionMemento *memento) {
|
||||||
|
setGeometry(geometry);
|
||||||
|
myEnsureResized(this);
|
||||||
|
restoreState(memento);
|
||||||
|
}
|
||||||
|
|
||||||
|
std_::unique_ptr<Window::SectionMemento> Widget::createMemento() const {
|
||||||
|
auto result = std_::make_unique<SectionMemento>(peer());
|
||||||
|
saveState(result.get());
|
||||||
|
return std_::move(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::saveState(SectionMemento *memento) const {
|
||||||
|
memento->setScrollTop(_scroll->scrollTop());
|
||||||
|
_inner->saveState(memento);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::restoreState(const SectionMemento *memento) {
|
||||||
|
_inner->restoreState(memento);
|
||||||
|
auto scrollTop = memento->getScrollTop();
|
||||||
|
_scroll->scrollToY(scrollTop);
|
||||||
|
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::resizeEvent(QResizeEvent *e) {
|
||||||
|
if (!width() || !height()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int newScrollTop = _scroll->scrollTop() + topDelta();
|
||||||
|
_fixedBar->resizeToWidth(width());
|
||||||
|
_fixedBarShadow->resize(width(), st::lineWidth);
|
||||||
|
|
||||||
|
QSize scrollSize(width(), height() - _fixedBar->height());
|
||||||
|
if (_scroll->size() != scrollSize) {
|
||||||
|
_scroll->resize(scrollSize);
|
||||||
|
_inner->resizeToWidth(scrollSize.width(), _scroll->height());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_scroll->isHidden()) {
|
||||||
|
if (topDelta()) {
|
||||||
|
_scroll->scrollToY(newScrollTop);
|
||||||
|
}
|
||||||
|
int scrollTop = _scroll->scrollTop();
|
||||||
|
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::onScroll() {
|
||||||
|
int scrollTop = _scroll->scrollTop();
|
||||||
|
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::showAnimatedHook() {
|
||||||
|
_fixedBar->setAnimatingMode(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::showFinishedHook() {
|
||||||
|
_fixedBar->setAnimatingMode(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace CommonGroups
|
||||||
|
} // namespace Profile
|
|
@ -0,0 +1,216 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "window/section_widget.h"
|
||||||
|
#include "window/section_memento.h"
|
||||||
|
|
||||||
|
namespace Notify {
|
||||||
|
struct PeerUpdate;
|
||||||
|
} // namespace Notify
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class ScrollArea;
|
||||||
|
class PlainShadow;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
|
namespace Profile {
|
||||||
|
|
||||||
|
class BackButton;
|
||||||
|
|
||||||
|
namespace CommonGroups {
|
||||||
|
|
||||||
|
class SectionMemento : public Window::SectionMemento {
|
||||||
|
public:
|
||||||
|
SectionMemento(PeerData *peer) : _peer(peer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Window::SectionWidget *createWidget(QWidget *parent, const QRect &geometry) const override;
|
||||||
|
|
||||||
|
PeerData *getPeer() const {
|
||||||
|
return _peer;
|
||||||
|
}
|
||||||
|
void setScrollTop(int scrollTop) {
|
||||||
|
_scrollTop = scrollTop;
|
||||||
|
}
|
||||||
|
int getScrollTop() const {
|
||||||
|
return _scrollTop;
|
||||||
|
}
|
||||||
|
void setCommonGroups(const QList<PeerData*> &groups) {
|
||||||
|
_commonGroups = groups;
|
||||||
|
}
|
||||||
|
const QList<PeerData*> &getCommonGroups() const {
|
||||||
|
return _commonGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
PeerData *_peer;
|
||||||
|
int _scrollTop = 0;
|
||||||
|
QList<PeerData*> _commonGroups;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class FixedBar final : public TWidget, private base::Subscriber {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
FixedBar(QWidget *parent);
|
||||||
|
|
||||||
|
// When animating mode is enabled the content is hidden and the
|
||||||
|
// whole fixed bar acts like a back button.
|
||||||
|
void setAnimatingMode(bool enabled);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void mousePressEvent(QMouseEvent *e) override;
|
||||||
|
int resizeGetHeight(int newWidth) override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onBack();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ChildWidget<BackButton> _backButton;
|
||||||
|
|
||||||
|
bool _animatingMode = false;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class InnerWidget final : public TWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
InnerWidget(QWidget *parent, PeerData *peer);
|
||||||
|
|
||||||
|
PeerData *peer() const {
|
||||||
|
return _peer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates the area that is visible inside the scroll container.
|
||||||
|
void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
|
||||||
|
|
||||||
|
void resizeToWidth(int newWidth, int minHeight) {
|
||||||
|
_minHeight = minHeight;
|
||||||
|
return TWidget::resizeToWidth(newWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveState(SectionMemento *memento) const;
|
||||||
|
void restoreState(const SectionMemento *memento);
|
||||||
|
|
||||||
|
~InnerWidget();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void cancelled();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
void keyPressEvent(QKeyEvent *e) override;
|
||||||
|
void mousePressEvent(QMouseEvent *e) override;
|
||||||
|
void mouseMoveEvent(QMouseEvent *e) override;
|
||||||
|
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||||
|
|
||||||
|
// Resizes content and counts natural widget height for the desired width.
|
||||||
|
int resizeGetHeight(int newWidth) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateSelected(QPoint localPos);
|
||||||
|
void updateRow(int index);
|
||||||
|
void showInitial(const QList<PeerData*> &list);
|
||||||
|
void checkPreloadMore();
|
||||||
|
void preloadMore();
|
||||||
|
void updateSize();
|
||||||
|
void paintRow(Painter &p, int index, TimeMs ms);
|
||||||
|
|
||||||
|
PeerData *_peer;
|
||||||
|
|
||||||
|
int _minHeight = 0;
|
||||||
|
int _rowHeight = 0;
|
||||||
|
int _contentLeft = 0;
|
||||||
|
int _contentTop = 0;
|
||||||
|
int _contentWidth = 0;
|
||||||
|
int _visibleTop = 0;
|
||||||
|
int _visibleBottom = 0;
|
||||||
|
|
||||||
|
struct Item {
|
||||||
|
explicit Item(PeerData *peer);
|
||||||
|
~Item();
|
||||||
|
|
||||||
|
PeerData * const peer;
|
||||||
|
Text name;
|
||||||
|
std_::unique_ptr<Ui::RippleAnimation> ripple;
|
||||||
|
};
|
||||||
|
Item *computeItem(PeerData *group);
|
||||||
|
QMap<PeerData*, Item*> _dataMap;
|
||||||
|
QList<Item*> _items;
|
||||||
|
int _selected = -1;
|
||||||
|
int _pressed = -1;
|
||||||
|
|
||||||
|
int32 _preloadGroupId = 0;
|
||||||
|
mtpRequestId _preloadRequestId = 0;
|
||||||
|
bool _allLoaded = true;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class Widget final : public Window::SectionWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
Widget(QWidget *parent, PeerData *peer);
|
||||||
|
|
||||||
|
PeerData *peer() const;
|
||||||
|
PeerData *peerForDialogs() const override {
|
||||||
|
return peer();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasTopBarShadow() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPixmap grabForShowAnimation(const Window::SectionSlideParams ¶ms) override;
|
||||||
|
|
||||||
|
void setInnerFocus() override;
|
||||||
|
|
||||||
|
bool showInternal(const Window::SectionMemento *memento) override;
|
||||||
|
std_::unique_ptr<Window::SectionMemento> createMemento() const override;
|
||||||
|
|
||||||
|
void setInternalState(const QRect &geometry, const SectionMemento *memento);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
|
||||||
|
void showAnimatedHook() override;
|
||||||
|
void showFinishedHook() override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onScroll();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateAdaptiveLayout();
|
||||||
|
void saveState(SectionMemento *memento) const;
|
||||||
|
void restoreState(const SectionMemento *memento);
|
||||||
|
|
||||||
|
ChildWidget<Ui::ScrollArea> _scroll;
|
||||||
|
ChildWidget<InnerWidget> _inner;
|
||||||
|
ChildWidget<FixedBar> _fixedBar;
|
||||||
|
ChildWidget<Ui::PlainShadow> _fixedBarShadow;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace CommonGroups
|
||||||
|
} // namespace Profile
|
|
@ -29,59 +29,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "boxes/addcontactbox.h"
|
#include "boxes/addcontactbox.h"
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
#include "observer_peer.h"
|
#include "observer_peer.h"
|
||||||
#include "window/top_bar_widget.h"
|
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
|
#include "profile/profile_back_button.h"
|
||||||
|
|
||||||
namespace Profile {
|
namespace Profile {
|
||||||
|
|
||||||
class BackButton final : public Ui::AbstractButton, private base::Subscriber {
|
|
||||||
public:
|
|
||||||
BackButton(QWidget *parent) : Ui::AbstractButton(parent)
|
|
||||||
, _text(lang(lng_menu_back).toUpper()) {
|
|
||||||
setCursor(style::cur_pointer);
|
|
||||||
|
|
||||||
subscribe(Adaptive::Changed(), [this] { updateAdaptiveLayout(); });
|
|
||||||
updateAdaptiveLayout();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
int resizeGetHeight(int newWidth) override {
|
|
||||||
return st::profileTopBarHeight;
|
|
||||||
}
|
|
||||||
void paintEvent(QPaintEvent *e) override {
|
|
||||||
Painter p(this);
|
|
||||||
|
|
||||||
p.fillRect(e->rect(), st::profileBg);
|
|
||||||
st::topBarBack.paint(p, (st::topBarArrowPadding.left() - st::topBarBack.width()) / 2, (st::topBarHeight - st::topBarBack.height()) / 2, width());
|
|
||||||
|
|
||||||
p.setFont(st::topBarButton.font);
|
|
||||||
p.setPen(st::topBarButton.textFg);
|
|
||||||
p.drawTextLeft(st::topBarArrowPadding.left(), st::topBarButton.padding.top() + st::topBarButton.textTop, width(), _text);
|
|
||||||
|
|
||||||
Window::TopBarWidget::paintUnreadCounter(p, width());
|
|
||||||
}
|
|
||||||
void onStateChanged(State was, StateChangeSource source) override {
|
|
||||||
if (isDown() && !(was & StateFlag::Down)) {
|
|
||||||
emit clicked();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void updateAdaptiveLayout() {
|
|
||||||
if (!Adaptive::OneColumn()) {
|
|
||||||
unsubscribe(base::take(_unreadCounterSubscription));
|
|
||||||
} else if (!_unreadCounterSubscription) {
|
|
||||||
_unreadCounterSubscription = subscribe(Global::RefUnreadCounterUpdate(), [this] {
|
|
||||||
rtlupdate(0, 0, st::titleUnreadCounterRight, st::titleUnreadCounterTop);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int _unreadCounterSubscription = 0;
|
|
||||||
QString _text;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using UpdateFlag = Notify::PeerUpdate::Flag;
|
using UpdateFlag = Notify::PeerUpdate::Flag;
|
||||||
|
@ -98,7 +49,7 @@ FixedBar::FixedBar(QWidget *parent, PeerData *peer) : TWidget(parent)
|
||||||
, _peerChat(peer->asChat())
|
, _peerChat(peer->asChat())
|
||||||
, _peerChannel(peer->asChannel())
|
, _peerChannel(peer->asChannel())
|
||||||
, _peerMegagroup(peer->isMegagroup() ? _peerChannel : nullptr)
|
, _peerMegagroup(peer->isMegagroup() ? _peerChannel : nullptr)
|
||||||
, _backButton(this) {
|
, _backButton(this, lang(lng_menu_back)) {
|
||||||
_backButton->moveToLeft(0, 0);
|
_backButton->moveToLeft(0, 0);
|
||||||
connect(_backButton, SIGNAL(clicked()), this, SLOT(onBack()));
|
connect(_backButton, SIGNAL(clicked()), this, SLOT(onBack()));
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "styles/style_profile.h"
|
#include "styles/style_profile.h"
|
||||||
#include "styles/style_window.h"
|
#include "styles/style_window.h"
|
||||||
#include "profile/profile_cover.h"
|
#include "profile/profile_cover.h"
|
||||||
#include "profile/profile_block_common_groups.h"
|
|
||||||
#include "profile/profile_block_info.h"
|
#include "profile/profile_block_info.h"
|
||||||
#include "profile/profile_block_settings.h"
|
#include "profile/profile_block_settings.h"
|
||||||
#include "profile/profile_block_invite_link.h"
|
#include "profile/profile_block_invite_link.h"
|
||||||
|
@ -50,16 +49,7 @@ void InnerWidget::createBlocks() {
|
||||||
auto channel = _peer->asChannel();
|
auto channel = _peer->asChannel();
|
||||||
auto megagroup = _peer->isMegagroup() ? channel : nullptr;
|
auto megagroup = _peer->isMegagroup() ? channel : nullptr;
|
||||||
if (user || channel || megagroup) {
|
if (user || channel || megagroup) {
|
||||||
auto widget = new InfoWidget(this, _peer);
|
_blocks.push_back({ new InfoWidget(this, _peer), BlockSide::Right });
|
||||||
widget->setShowCommonGroupsObservable(&_showCommonGroupsObservable);
|
|
||||||
_blocks.push_back({ widget, BlockSide::Right });
|
|
||||||
}
|
|
||||||
if (user) {
|
|
||||||
_commonGroupsWidget = new CommonGroupsWidget(this, _peer);
|
|
||||||
_commonGroupsWidget->setShowCommonGroupsObservable(&_showCommonGroupsObservable);
|
|
||||||
_blocks.push_back({ _commonGroupsWidget, BlockSide::Right });
|
|
||||||
} else {
|
|
||||||
_commonGroupsWidget = nullptr;
|
|
||||||
}
|
}
|
||||||
_blocks.push_back({ new SettingsWidget(this, _peer), BlockSide::Right });
|
_blocks.push_back({ new SettingsWidget(this, _peer), BlockSide::Right });
|
||||||
if (chat || channel || megagroup) {
|
if (chat || channel || megagroup) {
|
||||||
|
|
|
@ -20,13 +20,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "profile/profile_block_common_groups.h"
|
|
||||||
|
|
||||||
namespace Profile {
|
namespace Profile {
|
||||||
|
|
||||||
class CoverWidget;
|
class CoverWidget;
|
||||||
class BlockWidget;
|
class BlockWidget;
|
||||||
struct CommonGroupsEvent;
|
|
||||||
class SectionMemento;
|
class SectionMemento;
|
||||||
|
|
||||||
class InnerWidget final : public TWidget {
|
class InnerWidget final : public TWidget {
|
||||||
|
@ -117,12 +114,8 @@ private:
|
||||||
};
|
};
|
||||||
QList<Block> _blocks;
|
QList<Block> _blocks;
|
||||||
|
|
||||||
// We need to save this pointer for getting common groups list for section memento.
|
|
||||||
CommonGroupsWidget *_commonGroupsWidget = nullptr;
|
|
||||||
|
|
||||||
Mode _mode = Mode::OneColumn;
|
Mode _mode = Mode::OneColumn;
|
||||||
|
|
||||||
base::Observable<CommonGroupsEvent> _showCommonGroupsObservable;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Profile
|
} // namespace Profile
|
||||||
|
|
|
@ -42,17 +42,10 @@ public:
|
||||||
int getScrollTop() const {
|
int getScrollTop() const {
|
||||||
return _scrollTop;
|
return _scrollTop;
|
||||||
}
|
}
|
||||||
void setCommonGroups(const QList<PeerData*> &groups) {
|
|
||||||
_commonGroups = groups;
|
|
||||||
}
|
|
||||||
const QList<PeerData*> &getCommonGroups() const {
|
|
||||||
return _commonGroups;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PeerData *_peer;
|
PeerData *_peer;
|
||||||
int _scrollTop = 0;
|
int _scrollTop = 0;
|
||||||
QList<PeerData*> _commonGroups;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "ui/widgets/scroll_area.h"
|
#include "ui/widgets/scroll_area.h"
|
||||||
|
#include "ui/widgets/shadow.h"
|
||||||
|
|
||||||
namespace Profile {
|
namespace Profile {
|
||||||
|
|
||||||
|
@ -61,6 +62,10 @@ PeerData *Widget::peer() const {
|
||||||
return _inner->peer();
|
return _inner->peer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Widget::hasTopBarShadow() const {
|
||||||
|
return _fixedBarShadow->isFullyShown();
|
||||||
|
}
|
||||||
|
|
||||||
QPixmap Widget::grabForShowAnimation(const Window::SectionSlideParams ¶ms) {
|
QPixmap Widget::grabForShowAnimation(const Window::SectionSlideParams ¶ms) {
|
||||||
if (params.withTopBarShadow) _fixedBarShadow->hide();
|
if (params.withTopBarShadow) _fixedBarShadow->hide();
|
||||||
auto result = myGrab(this);
|
auto result = myGrab(this);
|
||||||
|
|
|
@ -21,10 +21,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "window/section_widget.h"
|
#include "window/section_widget.h"
|
||||||
#include "ui/widgets/shadow.h"
|
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class ScrollArea;
|
class ScrollArea;
|
||||||
|
class ToggleableShadow;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Profile {
|
namespace Profile {
|
||||||
|
@ -43,9 +43,7 @@ public:
|
||||||
return peer();
|
return peer();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasTopBarShadow() const override {
|
bool hasTopBarShadow() const override;
|
||||||
return _fixedBarShadow->isFullyShown();
|
|
||||||
}
|
|
||||||
|
|
||||||
QPixmap grabForShowAnimation(const Window::SectionSlideParams ¶ms) override;
|
QPixmap grabForShowAnimation(const Window::SectionSlideParams ¶ms) override;
|
||||||
|
|
||||||
|
|
|
@ -179,7 +179,7 @@ void CreateImplementationsMap() {
|
||||||
Implementations.createIfNull();
|
Implementations.createIfNull();
|
||||||
Type recordTypes[] = {
|
Type recordTypes[] = {
|
||||||
Type::RecordVideo,
|
Type::RecordVideo,
|
||||||
Type::RecordVoice
|
Type::RecordVoice,
|
||||||
};
|
};
|
||||||
for_const (auto type, recordTypes) {
|
for_const (auto type, recordTypes) {
|
||||||
Implementations->insert(type, &RecordAnimation::kMeta);
|
Implementations->insert(type, &RecordAnimation::kMeta);
|
||||||
|
@ -188,7 +188,7 @@ void CreateImplementationsMap() {
|
||||||
Type::UploadFile,
|
Type::UploadFile,
|
||||||
Type::UploadPhoto,
|
Type::UploadPhoto,
|
||||||
Type::UploadVideo,
|
Type::UploadVideo,
|
||||||
Type::UploadVoice
|
Type::UploadVoice,
|
||||||
};
|
};
|
||||||
for_const (auto type, uploadTypes) {
|
for_const (auto type, uploadTypes) {
|
||||||
Implementations->insert(type, &UploadAnimation::kMeta);
|
Implementations->insert(type, &UploadAnimation::kMeta);
|
||||||
|
|
|
@ -882,17 +882,17 @@ historySendActionTypingLargeNumerator: 28px;
|
||||||
historySendActionTypingSmallNumerator: 16px;
|
historySendActionTypingSmallNumerator: 16px;
|
||||||
historySendActionTypingDenominator: 12.;
|
historySendActionTypingDenominator: 12.;
|
||||||
|
|
||||||
historySendActionRecordDuration: 300;
|
historySendActionRecordDuration: 500;
|
||||||
historySendActionRecordPosition: point(1px, -4px);
|
historySendActionRecordPosition: point(1px, -4px);
|
||||||
historySendActionRecordDelta: 3px;
|
historySendActionRecordDelta: 4px;
|
||||||
historySendActionRecordStrokeNumerator: 12px;
|
historySendActionRecordStrokeNumerator: 16px;
|
||||||
historySendActionRecordDenominator: 8.;
|
historySendActionRecordDenominator: 8.;
|
||||||
|
|
||||||
historySendActionUploadDuration: 500;
|
historySendActionUploadDuration: 500;
|
||||||
historySendActionUploadPosition: point(0px, -4px);
|
historySendActionUploadPosition: point(0px, -4px);
|
||||||
historySendActionUploadDelta: 5px;
|
historySendActionUploadDelta: 5px;
|
||||||
historySendActionUploadStrokeNumerator: 12px;
|
historySendActionUploadStrokeNumerator: 16px;
|
||||||
historySendActionUploadSizeNumerator: 28px;
|
historySendActionUploadSizeNumerator: 32px;
|
||||||
historySendActionUploadDenominator: 8.;
|
historySendActionUploadDenominator: 8.;
|
||||||
|
|
||||||
MediaPlayerButton {
|
MediaPlayerButton {
|
||||||
|
|
|
@ -3,4 +3,4 @@ AppVersionStrMajor 0.10
|
||||||
AppVersionStrSmall 0.10.20
|
AppVersionStrSmall 0.10.20
|
||||||
AppVersionStr 0.10.20
|
AppVersionStr 0.10.20
|
||||||
AlphaChannel 0
|
AlphaChannel 0
|
||||||
BetaVersion 10019012
|
BetaVersion 10019013
|
||||||
|
|
|
@ -390,12 +390,12 @@
|
||||||
'<(src_loc)/platform/platform_main_window.h',
|
'<(src_loc)/platform/platform_main_window.h',
|
||||||
'<(src_loc)/platform/platform_notifications_manager.h',
|
'<(src_loc)/platform/platform_notifications_manager.h',
|
||||||
'<(src_loc)/platform/platform_window_title.h',
|
'<(src_loc)/platform/platform_window_title.h',
|
||||||
|
'<(src_loc)/profile/profile_back_button.cpp',
|
||||||
|
'<(src_loc)/profile/profile_back_button.h',
|
||||||
'<(src_loc)/profile/profile_block_actions.cpp',
|
'<(src_loc)/profile/profile_block_actions.cpp',
|
||||||
'<(src_loc)/profile/profile_block_actions.h',
|
'<(src_loc)/profile/profile_block_actions.h',
|
||||||
'<(src_loc)/profile/profile_block_channel_members.cpp',
|
'<(src_loc)/profile/profile_block_channel_members.cpp',
|
||||||
'<(src_loc)/profile/profile_block_channel_members.h',
|
'<(src_loc)/profile/profile_block_channel_members.h',
|
||||||
'<(src_loc)/profile/profile_block_common_groups.cpp',
|
|
||||||
'<(src_loc)/profile/profile_block_common_groups.h',
|
|
||||||
'<(src_loc)/profile/profile_block_info.cpp',
|
'<(src_loc)/profile/profile_block_info.cpp',
|
||||||
'<(src_loc)/profile/profile_block_info.h',
|
'<(src_loc)/profile/profile_block_info.h',
|
||||||
'<(src_loc)/profile/profile_block_invite_link.cpp',
|
'<(src_loc)/profile/profile_block_invite_link.cpp',
|
||||||
|
@ -410,6 +410,8 @@
|
||||||
'<(src_loc)/profile/profile_block_shared_media.h',
|
'<(src_loc)/profile/profile_block_shared_media.h',
|
||||||
'<(src_loc)/profile/profile_block_widget.cpp',
|
'<(src_loc)/profile/profile_block_widget.cpp',
|
||||||
'<(src_loc)/profile/profile_block_widget.h',
|
'<(src_loc)/profile/profile_block_widget.h',
|
||||||
|
'<(src_loc)/profile/profile_common_groups_section.cpp',
|
||||||
|
'<(src_loc)/profile/profile_common_groups_section.h',
|
||||||
'<(src_loc)/profile/profile_cover_drop_area.cpp',
|
'<(src_loc)/profile/profile_cover_drop_area.cpp',
|
||||||
'<(src_loc)/profile/profile_cover_drop_area.h',
|
'<(src_loc)/profile/profile_cover_drop_area.h',
|
||||||
'<(src_loc)/profile/profile_cover.cpp',
|
'<(src_loc)/profile/profile_cover.cpp',
|
||||||
|
|
Loading…
Reference in New Issue