Put mini-previews after sender name.
This commit is contained in:
parent
84f561b251
commit
d5f935b73d
|
@ -106,12 +106,15 @@ using ItemPreview = HistoryView::ItemPreview;
|
||||||
|
|
||||||
[[nodiscard]] QString WithCaptionDialogsText(
|
[[nodiscard]] QString WithCaptionDialogsText(
|
||||||
const QString &attachType,
|
const QString &attachType,
|
||||||
const QString &caption) {
|
const QString &caption,
|
||||||
|
bool hasMiniImages) {
|
||||||
if (caption.isEmpty()) {
|
if (caption.isEmpty()) {
|
||||||
return textcmdLink(1, TextUtilities::Clean(attachType));
|
return textcmdLink(1, TextUtilities::Clean(attachType));
|
||||||
}
|
}
|
||||||
|
|
||||||
return tr::lng_dialogs_text_media(
|
return hasMiniImages
|
||||||
|
? TextUtilities::Clean(caption)
|
||||||
|
: tr::lng_dialogs_text_media(
|
||||||
tr::now,
|
tr::now,
|
||||||
lt_media_part,
|
lt_media_part,
|
||||||
textcmdLink(1, tr::lng_dialogs_text_media_wrapped(
|
textcmdLink(1, tr::lng_dialogs_text_media_wrapped(
|
||||||
|
@ -491,10 +494,9 @@ ItemPreview MediaPhoto::toPreview(ToPreviewOptions options) const {
|
||||||
context = media;
|
context = media;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const auto type = tr::lng_in_dlg_photo(tr::now);
|
||||||
return {
|
return {
|
||||||
.text = WithCaptionDialogsText(
|
.text = WithCaptionDialogsText(type, caption, !images.empty()),
|
||||||
tr::lng_in_dlg_photo(tr::now),
|
|
||||||
caption),
|
|
||||||
.images = std::move(images),
|
.images = std::move(images),
|
||||||
.loadingContext = std::move(context),
|
.loadingContext = std::move(context),
|
||||||
};
|
};
|
||||||
|
@ -706,7 +708,7 @@ ItemPreview MediaFile::toPreview(ToPreviewOptions options) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
.text = WithCaptionDialogsText(type, caption),
|
.text = WithCaptionDialogsText(type, caption, !images.empty()),
|
||||||
.images = std::move(images),
|
.images = std::move(images),
|
||||||
.loadingContext = std::move(context),
|
.loadingContext = std::move(context),
|
||||||
};
|
};
|
||||||
|
@ -1029,10 +1031,9 @@ Data::CloudImage *MediaLocation::location() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemPreview MediaLocation::toPreview(ToPreviewOptions options) const {
|
ItemPreview MediaLocation::toPreview(ToPreviewOptions options) const {
|
||||||
// #TODO minis generate images
|
const auto type = tr::lng_maps_point(tr::now);
|
||||||
return {
|
const auto hasMiniImages = false;
|
||||||
.text = WithCaptionDialogsText(tr::lng_maps_point(tr::now), _title),
|
return { .text = WithCaptionDialogsText(type, _title, hasMiniImages) };
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MediaLocation::notificationText() const {
|
QString MediaLocation::notificationText() const {
|
||||||
|
|
|
@ -296,6 +296,7 @@ dialogsScamFont: font(9px semibold);
|
||||||
dialogsScamSkip: 4px;
|
dialogsScamSkip: 4px;
|
||||||
dialogsScamRadius: 2px;
|
dialogsScamRadius: 2px;
|
||||||
|
|
||||||
|
dialogsMiniPreviewTop: 1px;
|
||||||
dialogsMiniPreview: 16px;
|
dialogsMiniPreview: 16px;
|
||||||
dialogsMiniPreviewSkip: 2px;
|
dialogsMiniPreviewSkip: 2px;
|
||||||
dialogsMiniPreviewRight: 3px;
|
dialogsMiniPreviewRight: 3px;
|
||||||
|
|
|
@ -12,8 +12,61 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "ui/text/text_options.h"
|
#include "ui/text/text_options.h"
|
||||||
#include "ui/image/image.h"
|
#include "ui/image/image.h"
|
||||||
|
#include "lang/lang_keys.h"
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template <ushort kTag>
|
||||||
|
struct TextWithTagOffset {
|
||||||
|
TextWithTagOffset(QString text) : text(text) {
|
||||||
|
}
|
||||||
|
static TextWithTagOffset FromString(const QString &text) {
|
||||||
|
return { text };
|
||||||
|
}
|
||||||
|
|
||||||
|
QString text;
|
||||||
|
int offset = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace Lang {
|
||||||
|
|
||||||
|
template <ushort kTag>
|
||||||
|
struct ReplaceTag<TextWithTagOffset<kTag>> {
|
||||||
|
static TextWithTagOffset<kTag> Call(
|
||||||
|
TextWithTagOffset<kTag> &&original,
|
||||||
|
ushort tag,
|
||||||
|
const TextWithTagOffset<kTag> &replacement);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <ushort kTag>
|
||||||
|
TextWithTagOffset<kTag> ReplaceTag<TextWithTagOffset<kTag>>::Call(
|
||||||
|
TextWithTagOffset<kTag> &&original,
|
||||||
|
ushort tag,
|
||||||
|
const TextWithTagOffset<kTag> &replacement) {
|
||||||
|
const auto replacementPosition = FindTagReplacementPosition(
|
||||||
|
original.text,
|
||||||
|
tag);
|
||||||
|
if (replacementPosition < 0) {
|
||||||
|
return std::move(original);
|
||||||
|
}
|
||||||
|
original.text = ReplaceTag<QString>::Replace(
|
||||||
|
std::move(original.text),
|
||||||
|
replacement.text,
|
||||||
|
replacementPosition);
|
||||||
|
if (tag == kTag) {
|
||||||
|
original.offset = replacementPosition;
|
||||||
|
} else if (original.offset > replacementPosition) {
|
||||||
|
constexpr auto kReplaceCommandLength = 4;
|
||||||
|
original.offset += replacement.text.size() - kReplaceCommandLength;
|
||||||
|
}
|
||||||
|
return std::move(original);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Lang
|
||||||
|
|
||||||
namespace Dialogs::Ui {
|
namespace Dialogs::Ui {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -52,9 +105,16 @@ void MessageView::paint(
|
||||||
}
|
}
|
||||||
if (_textCachedFor != item.get()) {
|
if (_textCachedFor != item.get()) {
|
||||||
auto preview = item->toPreview(options);
|
auto preview = item->toPreview(options);
|
||||||
|
if (!preview.images.empty() && preview.imagesInTextPosition > 0) {
|
||||||
|
_senderCache.setText(
|
||||||
|
st::dialogsTextStyle,
|
||||||
|
preview.text.mid(0, preview.imagesInTextPosition).trimmed(),
|
||||||
|
DialogTextOptions());
|
||||||
|
preview.text = preview.text.mid(preview.imagesInTextPosition);
|
||||||
|
}
|
||||||
_textCache.setText(
|
_textCache.setText(
|
||||||
st::dialogsTextStyle,
|
st::dialogsTextStyle,
|
||||||
preview.text,
|
preview.text.trimmed(),
|
||||||
DialogTextOptions());
|
DialogTextOptions());
|
||||||
_textCachedFor = item;
|
_textCachedFor = item;
|
||||||
_imagesCache = std::move(preview.images);
|
_imagesCache = std::move(preview.images);
|
||||||
|
@ -71,12 +131,34 @@ void MessageView::paint(
|
||||||
_loadingContext = nullptr;
|
_loadingContext = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
p.setTextPalette(active
|
||||||
|
? st::dialogsTextPaletteActive
|
||||||
|
: selected
|
||||||
|
? st::dialogsTextPaletteOver
|
||||||
|
: st::dialogsTextPalette);
|
||||||
|
p.setFont(st::dialogsTextFont);
|
||||||
|
p.setPen(active ? st::dialogsTextFgActive : (selected ? st::dialogsTextFgOver : st::dialogsTextFg));
|
||||||
|
const auto guard = gsl::finally([&] {
|
||||||
|
p.restoreTextPalette();
|
||||||
|
});
|
||||||
|
|
||||||
auto rect = geometry;
|
auto rect = geometry;
|
||||||
|
if (!_senderCache.isEmpty()) {
|
||||||
|
_senderCache.drawElided(
|
||||||
|
p,
|
||||||
|
rect.left(),
|
||||||
|
rect.top(),
|
||||||
|
rect.width(),
|
||||||
|
rect.height() / st::dialogsTextFont->height);
|
||||||
|
const auto skip = st::dialogsMiniPreviewSkip
|
||||||
|
+ st::dialogsMiniPreviewRight;
|
||||||
|
rect.setLeft(rect.x() + _senderCache.maxWidth() + skip);
|
||||||
|
}
|
||||||
for (const auto &image : _imagesCache) {
|
for (const auto &image : _imagesCache) {
|
||||||
if (rect.width() < st::dialogsMiniPreview) {
|
if (rect.width() < st::dialogsMiniPreview) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
p.drawImage(rect.topLeft(), image);
|
p.drawImage(rect.x(), rect.y() + st::dialogsMiniPreviewTop, image);
|
||||||
rect.setLeft(rect.x()
|
rect.setLeft(rect.x()
|
||||||
+ st::dialogsMiniPreview
|
+ st::dialogsMiniPreview
|
||||||
+ st::dialogsMiniPreviewSkip);
|
+ st::dialogsMiniPreviewSkip);
|
||||||
|
@ -87,20 +169,29 @@ void MessageView::paint(
|
||||||
if (rect.isEmpty()) {
|
if (rect.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
p.setTextPalette(active
|
|
||||||
? st::dialogsTextPaletteActive
|
|
||||||
: selected
|
|
||||||
? st::dialogsTextPaletteOver
|
|
||||||
: st::dialogsTextPalette);
|
|
||||||
p.setFont(st::dialogsTextFont);
|
|
||||||
p.setPen(active ? st::dialogsTextFgActive : (selected ? st::dialogsTextFgOver : st::dialogsTextFg));
|
|
||||||
_textCache.drawElided(
|
_textCache.drawElided(
|
||||||
p,
|
p,
|
||||||
rect.left(),
|
rect.left(),
|
||||||
rect.top(),
|
rect.top(),
|
||||||
rect.width(),
|
rect.width(),
|
||||||
rect.height() / st::dialogsTextFont->height);
|
rect.height() / st::dialogsTextFont->height);
|
||||||
p.restoreTextPalette();
|
}
|
||||||
|
|
||||||
|
HistoryView::ItemPreview PreviewWithSender(
|
||||||
|
HistoryView::ItemPreview &&preview,
|
||||||
|
const QString &sender) {
|
||||||
|
auto textWithOffset = tr::lng_dialogs_text_with_from(
|
||||||
|
tr::now,
|
||||||
|
lt_from_part,
|
||||||
|
sender,
|
||||||
|
lt_message,
|
||||||
|
std::move(preview.text),
|
||||||
|
TextWithTagOffset<lt_from_part>::FromString);
|
||||||
|
preview.text = std::move(textWithOffset.text);
|
||||||
|
preview.imagesInTextPosition = (textWithOffset.offset < 0)
|
||||||
|
? 0
|
||||||
|
: textWithOffset.offset + sender.size();
|
||||||
|
return preview;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Dialogs::Ui
|
} // namespace Dialogs::Ui
|
||||||
|
|
|
@ -48,10 +48,15 @@ private:
|
||||||
struct LoadingContext;
|
struct LoadingContext;
|
||||||
|
|
||||||
mutable const HistoryItem *_textCachedFor = nullptr;
|
mutable const HistoryItem *_textCachedFor = nullptr;
|
||||||
|
mutable Ui::Text::String _senderCache;
|
||||||
mutable Ui::Text::String _textCache;
|
mutable Ui::Text::String _textCache;
|
||||||
mutable std::vector<QImage> _imagesCache;
|
mutable std::vector<QImage> _imagesCache;
|
||||||
mutable std::unique_ptr<LoadingContext> _loadingContext;
|
mutable std::unique_ptr<LoadingContext> _loadingContext;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] HistoryView::ItemPreview PreviewWithSender(
|
||||||
|
HistoryView::ItemPreview &&preview,
|
||||||
|
const QString &sender);
|
||||||
|
|
||||||
} // namespace Dialogs::Ui
|
} // namespace Dialogs::Ui
|
||||||
|
|
|
@ -33,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "core/crash_reports.h"
|
#include "core/crash_reports.h"
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
#include "api/api_text_entities.h"
|
#include "api/api_text_entities.h"
|
||||||
|
#include "dialogs/ui/dialogs_message_view.h"
|
||||||
#include "data/data_scheduled_messages.h" // kScheduledUntilOnlineTimestamp
|
#include "data/data_scheduled_messages.h" // kScheduledUntilOnlineTimestamp
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
|
@ -965,7 +966,9 @@ ItemPreview HistoryItem::toPreview(ToPreviewOptions options) const {
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}();
|
}();
|
||||||
if (sender) {
|
if (!sender) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
const auto fromText = sender->isSelf()
|
const auto fromText = sender->isSelf()
|
||||||
? tr::lng_from_you(tr::now)
|
? tr::lng_from_you(tr::now)
|
||||||
: sender->shortName();
|
: sender->shortName();
|
||||||
|
@ -975,14 +978,7 @@ ItemPreview HistoryItem::toPreview(ToPreviewOptions options) const {
|
||||||
tr::now,
|
tr::now,
|
||||||
lt_from,
|
lt_from,
|
||||||
TextUtilities::Clean(fromText)));
|
TextUtilities::Clean(fromText)));
|
||||||
result.text = tr::lng_dialogs_text_with_from(
|
return Dialogs::Ui::PreviewWithSender(std::move(result), fromWrapped);
|
||||||
tr::now,
|
|
||||||
lt_from_part,
|
|
||||||
fromWrapped,
|
|
||||||
lt_message,
|
|
||||||
std::move(result.text));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ui::Text::IsolatedEmoji HistoryItem::isolatedEmoji() const {
|
Ui::Text::IsolatedEmoji HistoryItem::isolatedEmoji() const {
|
||||||
|
|
|
@ -66,6 +66,7 @@ struct ToPreviewOptions {
|
||||||
struct ItemPreview {
|
struct ItemPreview {
|
||||||
QString text;
|
QString text;
|
||||||
std::vector<QImage> images;
|
std::vector<QImage> images;
|
||||||
|
int imagesInTextPosition = 0;
|
||||||
std::any loadingContext;
|
std::any loadingContext;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -6853,7 +6853,6 @@ void HistoryWidget::updateForwardingTexts() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count < 2) {
|
if (count < 2) {
|
||||||
// #TODO minis use images
|
|
||||||
text = _toForward.items.front()->toPreview({
|
text = _toForward.items.front()->toPreview({
|
||||||
.hideSender = true,
|
.hideSender = true,
|
||||||
.hideCaption = !keepCaptions,
|
.hideCaption = !keepCaptions,
|
||||||
|
|
|
@ -377,11 +377,14 @@ bool SendActionPainter::updateNeedsAnimating(crl::time now, bool force) {
|
||||||
if (force
|
if (force
|
||||||
|| sendActionChanged
|
|| sendActionChanged
|
||||||
|| (sendActionResult && !anim::Disabled())) {
|
|| (sendActionResult && !anim::Disabled())) {
|
||||||
|
const auto height = std::max(
|
||||||
|
st::normalFont->height,
|
||||||
|
st::dialogsMiniPreviewTop + st::dialogsMiniPreview);
|
||||||
_history->peer->owner().sendActionManager().updateAnimation({
|
_history->peer->owner().sendActionManager().updateAnimation({
|
||||||
_history,
|
_history,
|
||||||
0,
|
0,
|
||||||
_sendActionAnimation.width() + _animationLeft,
|
_sendActionAnimation.width() + _animationLeft,
|
||||||
st::normalFont->height,
|
height,
|
||||||
(force || sendActionChanged)
|
(force || sendActionChanged)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue