mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 02:01:40 -05:00
Use Text to display empty group state.
This commit is contained in:
parent
8643972f8c
commit
01b7d4ffba
7 changed files with 175 additions and 123 deletions
|
@ -180,7 +180,7 @@ HistoryInner::HistoryInner(
|
|||
void HistoryInner::messagesReceived(
|
||||
PeerData *peer,
|
||||
const QVector<MTPMessage> &messages) {
|
||||
if (_history && _history->peer == peer) {
|
||||
if (_history->peer == peer) {
|
||||
_history->addOlderSlice(messages);
|
||||
} else if (_migrated && _migrated->peer == peer) {
|
||||
const auto newLoaded = _migrated
|
||||
|
@ -194,7 +194,7 @@ void HistoryInner::messagesReceived(
|
|||
}
|
||||
|
||||
void HistoryInner::messagesReceivedDown(PeerData *peer, const QVector<MTPMessage> &messages) {
|
||||
if (_history && _history->peer == peer) {
|
||||
if (_history->peer == peer) {
|
||||
const auto oldLoaded = _migrated
|
||||
&& _history->isEmpty()
|
||||
&& !_migrated->isEmpty();
|
||||
|
@ -523,6 +523,14 @@ TextSelection HistoryInner::itemRenderSelection(
|
|||
return TextSelection();
|
||||
}
|
||||
|
||||
void HistoryInner::paintEmpty(Painter &p, int width, int height) {
|
||||
if (!_emptyPainter) {
|
||||
_emptyPainter = std::make_unique<HistoryView::EmptyPainter>(
|
||||
_history);
|
||||
}
|
||||
_emptyPainter->paint(p, width, height);
|
||||
}
|
||||
|
||||
void HistoryInner::paintEvent(QPaintEvent *e) {
|
||||
if (Ui::skipPaintEvent(this, e)) {
|
||||
return;
|
||||
|
@ -552,7 +560,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
|
|||
p.restoreTextPalette();
|
||||
}
|
||||
} else if (historyDisplayedEmpty) {
|
||||
HistoryView::paintEmpty(p, _history, width(), height());
|
||||
paintEmpty(p, width(), height());
|
||||
}
|
||||
if (!noHistoryDisplayed) {
|
||||
auto readMentions = base::flat_set<not_null<HistoryItem*>>();
|
||||
|
@ -1371,8 +1379,6 @@ void HistoryInner::mouseReleaseEvent(QMouseEvent *e) {
|
|||
}
|
||||
|
||||
void HistoryInner::mouseDoubleClickEvent(QMouseEvent *e) {
|
||||
if (!_history) return;
|
||||
|
||||
mouseActionStart(e->globalPos(), e->button());
|
||||
|
||||
const auto mouseActionView = _mouseActionItem
|
||||
|
@ -2101,8 +2107,6 @@ bool HistoryInner::displayScrollDate() const {
|
|||
}
|
||||
|
||||
void HistoryInner::scrollDateCheck() {
|
||||
if (!_history) return;
|
||||
|
||||
auto newScrollDateItem = _history->scrollTopItem ? _history->scrollTopItem : (_migrated ? _migrated->scrollTopItem : nullptr);
|
||||
auto newScrollDateItemTop = _history->scrollTopItem ? _history->scrollTopOffset : (_migrated ? _migrated->scrollTopOffset : 0);
|
||||
//if (newScrollDateItem && !displayScrollDate()) {
|
||||
|
@ -2282,7 +2286,6 @@ auto HistoryInner::nextItem(Element *view) -> Element* {
|
|||
} else if (const auto result = view->nextInBlocks()) {
|
||||
return result;
|
||||
} else if (view->data()->history() == _migrated
|
||||
&& _history
|
||||
&& _migrated->loadedAtBottom()
|
||||
&& _history->loadedAtTop()
|
||||
&& !_history->isEmpty()) {
|
||||
|
@ -2380,7 +2383,7 @@ void HistoryInner::onTouchSelect() {
|
|||
}
|
||||
|
||||
void HistoryInner::mouseActionUpdate() {
|
||||
if (!_history || hasPendingResizedItems()) {
|
||||
if (hasPendingResizedItems()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2553,7 +2556,6 @@ void HistoryInner::mouseActionUpdate() {
|
|||
}
|
||||
} else if (item) {
|
||||
if (_mouseAction == MouseAction::Selecting) {
|
||||
auto canSelectMany = (_history != nullptr);
|
||||
if (selectingText) {
|
||||
uint16 second = dragState.symbol;
|
||||
if (dragState.afterSymbol && _mouseSelectType == TextSelectType::Letters) {
|
||||
|
@ -2573,8 +2575,8 @@ void HistoryInner::mouseActionUpdate() {
|
|||
_wasSelectedText = true;
|
||||
setFocus();
|
||||
}
|
||||
updateDragSelection(0, 0, false);
|
||||
} else if (canSelectMany) {
|
||||
updateDragSelection(nullptr, nullptr, false);
|
||||
} else {
|
||||
auto selectingDown = (itemTop(_mouseActionItem) < itemTop(item)) || (_mouseActionItem == item && _dragStartPosition.y() < m.y());
|
||||
auto dragSelFrom = _mouseActionItem->mainView();
|
||||
auto dragSelTo = view;
|
||||
|
@ -2680,7 +2682,7 @@ void HistoryInner::updateDragSelection(Element *dragSelFrom, Element *dragSelTo,
|
|||
|
||||
int HistoryInner::historyHeight() const {
|
||||
int result = 0;
|
||||
if (!_history || _history->isEmpty()) {
|
||||
if (_history->isEmpty()) {
|
||||
result += _migrated ? _migrated->height() : 0;
|
||||
} else {
|
||||
result += _history->height() - _historySkipHeight + (_migrated ? _migrated->height() : 0);
|
||||
|
@ -2706,7 +2708,11 @@ int HistoryInner::migratedTop() const {
|
|||
|
||||
int HistoryInner::historyTop() const {
|
||||
int mig = migratedTop();
|
||||
return (_history && !_history->isEmpty()) ? (mig >= 0 ? (mig + _migrated->height() - _historySkipHeight) : _historyPaddingTop) : -1;
|
||||
return !_history->isEmpty()
|
||||
? (mig >= 0
|
||||
? (mig + _migrated->height() - _historySkipHeight)
|
||||
: _historyPaddingTop)
|
||||
: -1;
|
||||
}
|
||||
|
||||
int HistoryInner::historyDrawTop() const {
|
||||
|
@ -2736,7 +2742,7 @@ int HistoryInner::itemTop(const Element *view) const {
|
|||
}
|
||||
|
||||
void HistoryInner::notifyIsBotChanged() {
|
||||
const auto newinfo = (_peer && _peer->isUser())
|
||||
const auto newinfo = _peer->isUser()
|
||||
? _peer->asUser()->botInfo.get()
|
||||
: nullptr;
|
||||
if ((!newinfo && !_botAbout)
|
||||
|
@ -2918,7 +2924,7 @@ void HistoryInner::deleteItem(not_null<HistoryItem*> item) {
|
|||
}
|
||||
|
||||
bool HistoryInner::hasPendingResizedItems() const {
|
||||
return (_history && _history->hasPendingResizedItems())
|
||||
return _history->hasPendingResizedItems()
|
||||
|| (_migrated && _migrated->hasPendingResizedItems());
|
||||
}
|
||||
|
||||
|
@ -3007,12 +3013,12 @@ void HistoryInner::applyDragSelection(
|
|||
addSelectionRange(toItems, _history, fromblock, fromitem, toblock, toitem);
|
||||
} else {
|
||||
auto toRemove = std::vector<not_null<HistoryItem*>>();
|
||||
for (auto i = toItems->begin(); i != toItems->cend(); ++i) {
|
||||
auto iy = itemTop(i->first);
|
||||
for (const auto &item : *toItems) {
|
||||
auto iy = itemTop(item.first);
|
||||
if (iy < -1) {
|
||||
toRemove.push_back(i->first);
|
||||
toRemove.emplace_back(item.first);
|
||||
} else if (iy >= 0 && iy >= selfromy && iy < seltoy) {
|
||||
toRemove.push_back(i->first);
|
||||
toRemove.emplace_back(item.first);
|
||||
}
|
||||
}
|
||||
for (const auto item : toRemove) {
|
||||
|
|
|
@ -23,6 +23,7 @@ struct TextState;
|
|||
struct StateRequest;
|
||||
enum class CursorState : char;
|
||||
enum class PointState : char;
|
||||
class EmptyPainter;
|
||||
} // namespace HistoryView
|
||||
|
||||
namespace Window {
|
||||
|
@ -54,6 +55,7 @@ public:
|
|||
void messagesReceivedDown(PeerData *peer, const QVector<MTPMessage> &messages);
|
||||
|
||||
TextWithEntities getSelectedText() const;
|
||||
void paintEmpty(Painter &p, int width, int height);
|
||||
|
||||
void touchScrollUpdated(const QPoint &screenPos);
|
||||
|
||||
|
@ -292,8 +294,8 @@ private:
|
|||
|
||||
not_null<Window::Controller*> _controller;
|
||||
|
||||
not_null<PeerData*> _peer;
|
||||
not_null<History*> _history;
|
||||
const not_null<PeerData*> _peer;
|
||||
const not_null<History*> _history;
|
||||
History *_migrated = nullptr;
|
||||
int _contentWidth = 0;
|
||||
int _historyPaddingTop = 0;
|
||||
|
@ -303,6 +305,7 @@ private:
|
|||
int _historySkipHeight = 0;
|
||||
|
||||
std::unique_ptr<BotAbout> _botAbout;
|
||||
std::unique_ptr<HistoryView::EmptyPainter> _emptyPainter;
|
||||
|
||||
HistoryWidget *_widget = nullptr;
|
||||
Ui::ScrollArea *_scroll = nullptr;
|
||||
|
|
|
@ -298,7 +298,7 @@ protected:
|
|||
|
||||
void setGroupId(MessageGroupId groupId);
|
||||
|
||||
Text _text = { int(st::msgMinWidth) };
|
||||
Text _text = { st::msgMinWidth };
|
||||
int _textWidth = -1;
|
||||
int _textHeight = 0;
|
||||
|
||||
|
|
|
@ -6557,7 +6557,10 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
if (_scroll->isHidden() && _history) {
|
||||
p.setClipRect(_scroll->geometry());
|
||||
HistoryView::paintEmpty(p, _history, width(), height() - _field->height() - 2 * st::historySendPadding);
|
||||
_list->paintEmpty(
|
||||
p,
|
||||
width(),
|
||||
height() - _field->height() - 2 * st::historySendPadding);
|
||||
}
|
||||
} else {
|
||||
const auto w = st::msgServiceFont->width(lang(lng_willbe_history))
|
||||
|
|
|
@ -15,10 +15,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_abstract_structure.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "styles/style_history.h"
|
||||
#include "ui/text_options.h"
|
||||
#include "mainwidget.h"
|
||||
#include "layout.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "styles/style_history.h"
|
||||
|
||||
namespace HistoryView {
|
||||
namespace {
|
||||
|
@ -175,81 +176,13 @@ void paintPreparedDate(Painter &p, const QString &dateText, int dateTextWidth, i
|
|||
p.drawText(left + st::msgServicePadding.left(), y + st::msgServiceMargin.top() + st::msgServicePadding.top() + st::msgServiceFont->ascent, dateText);
|
||||
}
|
||||
|
||||
void PaintAboutGroup(Painter &p, int width, int height) {
|
||||
constexpr auto kPhrasesCount = 4;
|
||||
const auto header = lang(lng_group_about_header);
|
||||
const auto text = lang(lng_group_about_text);
|
||||
const auto phrases = std::array<QString, kPhrasesCount>{
|
||||
lang(lng_group_about1),
|
||||
lang(lng_group_about2),
|
||||
lang(lng_group_about3),
|
||||
lang(lng_group_about4),
|
||||
};
|
||||
|
||||
const auto &font = st::msgServiceFont;
|
||||
const auto headerWidth = font->width(header);
|
||||
const auto textWidth = font->width(text);
|
||||
const auto phraseWidths = ranges::view::all(
|
||||
phrases
|
||||
) | ranges::view::transform([&](const QString &text) {
|
||||
return font->width(text);
|
||||
}) | ranges::to_vector;
|
||||
|
||||
const auto maxPhraseWidth = *ranges::max_element(phraseWidths);
|
||||
|
||||
const auto margin = st::msgMargin.left();
|
||||
const auto maxBubbleWidth = width - 2 * st::historyGroupAboutMargin;
|
||||
const auto padding = st::historyGroupAboutPadding;
|
||||
const auto bubbleWidth = std::min(
|
||||
maxBubbleWidth,
|
||||
std::max({
|
||||
maxPhraseWidth + st::historyGroupAboutBulletSkip,
|
||||
headerWidth,
|
||||
textWidth }) + padding.left() + padding.right());
|
||||
const auto bubbleHeight = padding.top()
|
||||
+ font->height
|
||||
+ st::historyGroupAboutHeaderSkip
|
||||
+ font->height
|
||||
+ st::historyGroupAboutTextSkip
|
||||
+ font->height * kPhrasesCount
|
||||
+ st::historyGroupAboutSkip * (kPhrasesCount - 1)
|
||||
+ padding.bottom();
|
||||
const auto bubbleLeft = (width - bubbleWidth) / 2;
|
||||
const auto bubbleTop = (height - bubbleHeight) / 3;
|
||||
|
||||
ServiceMessagePainter::paintBubble(
|
||||
p,
|
||||
bubbleLeft,
|
||||
bubbleTop,
|
||||
bubbleWidth,
|
||||
bubbleHeight);
|
||||
|
||||
p.setFont(font);
|
||||
p.setPen(st::msgServiceFg);
|
||||
const auto left = bubbleLeft + padding.left();
|
||||
auto top = bubbleTop + padding.top();
|
||||
|
||||
p.drawTextLeft(bubbleLeft + (bubbleWidth - headerWidth) / 2, top, width, header);
|
||||
top += font->height + st::historyGroupAboutHeaderSkip;
|
||||
|
||||
p.drawTextLeft(left, top, width, text);
|
||||
top += font->height + st::historyGroupAboutTextSkip;
|
||||
|
||||
p.setBrush(st::msgServiceFg);
|
||||
for (const auto &text : phrases) {
|
||||
p.setPen(st::msgServiceFg);
|
||||
p.drawTextLeft(left + st::historyGroupAboutBulletSkip, top, width, text);
|
||||
{
|
||||
PainterHighQualityEnabler hq(p);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.drawEllipse(
|
||||
left,
|
||||
top + (font->height - st::mediaUnreadSize) / 2,
|
||||
st::mediaUnreadSize,
|
||||
st::mediaUnreadSize);
|
||||
}
|
||||
top += font->height + st::historyGroupAboutSkip;
|
||||
bool NeedAboutGroup(not_null<History*> history) {
|
||||
if (const auto chat = history->peer->asChat()) {
|
||||
return chat->amCreator();
|
||||
} else if (const auto channel = history->peer->asMegagroup()) {
|
||||
return channel->amCreator();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namepsace
|
||||
|
@ -360,24 +293,6 @@ QVector<int> ServiceMessagePainter::countLineWidths(const Text &text, const QRec
|
|||
return lineWidths;
|
||||
}
|
||||
|
||||
void paintEmpty(
|
||||
Painter &p,
|
||||
not_null<History*> history,
|
||||
int width,
|
||||
int height) {
|
||||
const auto needAboutGroup = [&] {
|
||||
if (const auto chat = history->peer->asChat()) {
|
||||
return chat->amCreator();
|
||||
} else if (const auto channel = history->peer->asMegagroup()) {
|
||||
return channel->amCreator();
|
||||
}
|
||||
return false;
|
||||
}();
|
||||
if (needAboutGroup) {
|
||||
PaintAboutGroup(p, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void serviceColorsUpdated() {
|
||||
if (serviceMessageStyle) {
|
||||
for (auto &corner : serviceMessageStyle->corners) {
|
||||
|
@ -625,4 +540,119 @@ TextSelection Service::adjustSelection(
|
|||
return message()->_text.adjustSelection(selection, type);
|
||||
}
|
||||
|
||||
EmptyPainter::EmptyPainter(not_null<History*> history) : _history(history) {
|
||||
if (NeedAboutGroup(_history)) {
|
||||
fillAboutGroup();
|
||||
}
|
||||
}
|
||||
|
||||
void EmptyPainter::fillAboutGroup() {
|
||||
const auto phrases = {
|
||||
lang(lng_group_about1),
|
||||
lang(lng_group_about2),
|
||||
lang(lng_group_about3),
|
||||
lang(lng_group_about4),
|
||||
};
|
||||
const auto setText = [](Text &text, const QString &content) {
|
||||
text.setText(
|
||||
st::serviceTextStyle,
|
||||
content,
|
||||
Ui::ItemTextServiceOptions());
|
||||
};
|
||||
setText(_header, lang(lng_group_about_header));
|
||||
setText(_text, lang(lng_group_about_header));
|
||||
for (const auto &text : phrases) {
|
||||
_phrases.emplace_back(st::msgMinWidth);
|
||||
setText(_phrases.back(), text);
|
||||
}
|
||||
}
|
||||
|
||||
void EmptyPainter::paint(Painter &p, int width, int height) {
|
||||
if (_phrases.empty()) {
|
||||
return;
|
||||
}
|
||||
constexpr auto kMaxTextLines = 3;
|
||||
const auto maxPhraseWidth = ranges::max_element(
|
||||
_phrases,
|
||||
ranges::less(),
|
||||
&Text::maxWidth
|
||||
)->maxWidth();
|
||||
|
||||
const auto &font = st::serviceTextStyle.font;
|
||||
const auto margin = st::msgMargin.left();
|
||||
const auto maxBubbleWidth = width - 2 * st::historyGroupAboutMargin;
|
||||
const auto padding = st::historyGroupAboutPadding;
|
||||
const auto bubbleWidth = std::min(
|
||||
maxBubbleWidth,
|
||||
std::max({
|
||||
maxPhraseWidth + st::historyGroupAboutBulletSkip,
|
||||
_header.maxWidth(),
|
||||
_text.maxWidth() }) + padding.left() + padding.right());
|
||||
const auto innerWidth = bubbleWidth - padding.left() - padding.right();
|
||||
const auto textHeight = [&](const Text &text) {
|
||||
return std::min(
|
||||
text.countHeight(innerWidth),
|
||||
kMaxTextLines * font->height);
|
||||
};
|
||||
const auto bubbleHeight = padding.top()
|
||||
+ textHeight(_header)
|
||||
+ st::historyGroupAboutHeaderSkip
|
||||
+ textHeight(_text)
|
||||
+ st::historyGroupAboutTextSkip
|
||||
+ ranges::accumulate(_phrases, 0, ranges::plus(), textHeight)
|
||||
+ st::historyGroupAboutSkip * int(_phrases.size() - 1)
|
||||
+ padding.bottom();
|
||||
const auto bubbleLeft = (width - bubbleWidth) / 2;
|
||||
const auto bubbleTop = (height - bubbleHeight) / 3;
|
||||
|
||||
ServiceMessagePainter::paintBubble(
|
||||
p,
|
||||
bubbleLeft,
|
||||
bubbleTop,
|
||||
bubbleWidth,
|
||||
bubbleHeight);
|
||||
|
||||
p.setPen(st::msgServiceFg);
|
||||
p.setBrush(st::msgServiceFg);
|
||||
|
||||
const auto left = bubbleLeft + padding.left();
|
||||
auto top = bubbleTop + padding.top();
|
||||
|
||||
_header.drawElided(
|
||||
p,
|
||||
left,
|
||||
top,
|
||||
innerWidth,
|
||||
kMaxTextLines,
|
||||
style::al_top);
|
||||
top += textHeight(_header) + st::historyGroupAboutHeaderSkip;
|
||||
|
||||
_text.drawElided(
|
||||
p,
|
||||
left,
|
||||
top,
|
||||
innerWidth,
|
||||
kMaxTextLines);
|
||||
top += textHeight(_text) + st::historyGroupAboutTextSkip;
|
||||
|
||||
for (const auto &text : _phrases) {
|
||||
p.setPen(st::msgServiceFg);
|
||||
text.drawElided(
|
||||
p,
|
||||
left + st::historyGroupAboutBulletSkip,
|
||||
top,
|
||||
innerWidth,
|
||||
kMaxTextLines);
|
||||
|
||||
PainterHighQualityEnabler hq(p);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.drawEllipse(
|
||||
left,
|
||||
top + (font->height - st::mediaUnreadSize) / 2,
|
||||
st::mediaUnreadSize,
|
||||
st::mediaUnreadSize);
|
||||
top += textHeight(text) + st::historyGroupAboutSkip;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace HistoryView
|
||||
|
|
|
@ -74,11 +74,21 @@ private:
|
|||
|
||||
};
|
||||
|
||||
void paintEmpty(
|
||||
Painter &p,
|
||||
not_null<History*> history,
|
||||
int width,
|
||||
int height);
|
||||
class EmptyPainter {
|
||||
public:
|
||||
explicit EmptyPainter(not_null<History*> history);
|
||||
|
||||
void paint(Painter &p, int width, int height);
|
||||
|
||||
private:
|
||||
void fillAboutGroup();
|
||||
|
||||
not_null<History*> _history;
|
||||
Text _header = { st::msgMinWidth };
|
||||
Text _text = { st::msgMinWidth };
|
||||
std::vector<Text> _phrases;
|
||||
|
||||
};
|
||||
|
||||
void serviceColorsUpdated();
|
||||
|
||||
|
|
|
@ -352,7 +352,7 @@ private:
|
|||
WebPageData *_page = nullptr;
|
||||
int _pixw = 0;
|
||||
int _pixh = 0;
|
||||
Text _text = { int(st::msgMinWidth) };
|
||||
Text _text = { st::msgMinWidth };
|
||||
|
||||
struct LinkEntry {
|
||||
LinkEntry() : width(0) {
|
||||
|
|
Loading…
Add table
Reference in a new issue