mirror of https://github.com/procxx/kepka.git
Better channel log entry layout inside messages.
Also move HistoryService class to a separate module.
This commit is contained in:
parent
0a39e7e2b1
commit
cedf8a65e7
|
@ -23,8 +23,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "core/basic_types.h"
|
#include "core/basic_types.h"
|
||||||
#include "history.h"
|
#include "history.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
#include "history/history_media.h"
|
|
||||||
#include "history/history_message.h"
|
|
||||||
#include "layout.h"
|
#include "layout.h"
|
||||||
|
|
||||||
class Messenger;
|
class Messenger;
|
||||||
|
|
|
@ -31,6 +31,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "base/observer.h"
|
#include "base/observer.h"
|
||||||
#include "base/task_queue.h"
|
#include "base/task_queue.h"
|
||||||
|
#include "history/history_media.h"
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(ClickHandlerPtr);
|
Q_DECLARE_METATYPE(ClickHandlerPtr);
|
||||||
Q_DECLARE_METATYPE(Qt::MouseButton);
|
Q_DECLARE_METATYPE(Qt::MouseButton);
|
||||||
|
|
|
@ -20,7 +20,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#include "history.h"
|
#include "history.h"
|
||||||
|
|
||||||
|
#include "history/history_message.h"
|
||||||
#include "history/history_media_types.h"
|
#include "history/history_media_types.h"
|
||||||
|
#include "history/history_service.h"
|
||||||
#include "dialogs/dialogs_indexed_list.h"
|
#include "dialogs/dialogs_indexed_list.h"
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
#include "data/data_drafts.h"
|
#include "data/data_drafts.h"
|
||||||
|
@ -63,9 +65,9 @@ HistoryItem *createUnsupportedMessage(History *history, MsgId msgId, MTPDmessage
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void historyInit() {
|
void HistoryInit() {
|
||||||
historyInitMessages();
|
HistoryInitMessages();
|
||||||
historyInitMedia();
|
HistoryInitMedia();
|
||||||
}
|
}
|
||||||
|
|
||||||
History::History(const PeerId &peerId)
|
History::History(const PeerId &peerId)
|
||||||
|
|
|
@ -25,7 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "ui/effects/send_action_animations.h"
|
#include "ui/effects/send_action_animations.h"
|
||||||
#include "base/observer.h"
|
#include "base/observer.h"
|
||||||
|
|
||||||
void historyInit();
|
void HistoryInit();
|
||||||
|
|
||||||
class HistoryItem;
|
class HistoryItem;
|
||||||
using SelectedItemSet = QMap<int, gsl::not_null<HistoryItem*>>;
|
using SelectedItemSet = QMap<int, gsl::not_null<HistoryItem*>>;
|
||||||
|
|
|
@ -22,6 +22,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "styles/style_history.h"
|
#include "styles/style_history.h"
|
||||||
#include "history/history_media_types.h"
|
#include "history/history_media_types.h"
|
||||||
|
#include "history/history_message.h"
|
||||||
#include "history/history_service_layout.h"
|
#include "history/history_service_layout.h"
|
||||||
#include "history/history_admin_log_section.h"
|
#include "history/history_admin_log_section.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
@ -496,7 +497,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
p.translate(0, -top);
|
p.translate(0, -top);
|
||||||
|
|
||||||
enumerateUserpics([&p, &clip](HistoryMessage *message, int userpicTop) {
|
enumerateUserpics([&p, &clip](gsl::not_null<HistoryMessage*> message, int userpicTop) {
|
||||||
// stop the enumeration if the userpic is below the painted rect
|
// stop the enumeration if the userpic is below the painted rect
|
||||||
if (userpicTop >= clip.top() + clip.height()) {
|
if (userpicTop >= clip.top() + clip.height()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -511,7 +512,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
|
||||||
|
|
||||||
auto dateHeight = st::msgServicePadding.bottom() + st::msgServiceFont->height + st::msgServicePadding.top();
|
auto dateHeight = st::msgServicePadding.bottom() + st::msgServiceFont->height + st::msgServicePadding.top();
|
||||||
auto scrollDateOpacity = _scrollDateOpacity.current(ms, _scrollDateShown ? 1. : 0.);
|
auto scrollDateOpacity = _scrollDateOpacity.current(ms, _scrollDateShown ? 1. : 0.);
|
||||||
enumerateDates([&p, &clip, scrollDateOpacity, dateHeight/*, lastDate, showFloatingBefore*/](HistoryItem *item, int itemtop, int dateTop) {
|
enumerateDates([&p, &clip, scrollDateOpacity, dateHeight/*, lastDate, showFloatingBefore*/](gsl::not_null<HistoryItem*> item, int itemtop, int dateTop) {
|
||||||
// stop the enumeration if the date is above the painted rect
|
// stop the enumeration if the date is above the painted rect
|
||||||
if (dateTop + dateHeight <= clip.top()) {
|
if (dateTop + dateHeight <= clip.top()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -664,9 +665,6 @@ void InnerWidget::mouseActionStart(const QPoint &screenPos, Qt::MouseButton butt
|
||||||
if (uponSelected) {
|
if (uponSelected) {
|
||||||
_mouseAction = MouseAction::PrepareDrag; // start text drag
|
_mouseAction = MouseAction::PrepareDrag; // start text drag
|
||||||
} else if (!_pressWasInactive) {
|
} else if (!_pressWasInactive) {
|
||||||
if (dynamic_cast<HistorySticker*>(App::pressedItem()->getMedia())) {
|
|
||||||
_mouseAction = MouseAction::PrepareDrag; // start sticker drag or by-date drag
|
|
||||||
} else {
|
|
||||||
if (dragState.afterSymbol) ++_mouseTextSymbol;
|
if (dragState.afterSymbol) ++_mouseTextSymbol;
|
||||||
auto selection = TextSelection { _mouseTextSymbol, _mouseTextSymbol };
|
auto selection = TextSelection { _mouseTextSymbol, _mouseTextSymbol };
|
||||||
repaintItem(std::exchange(_selectedItem, _mouseActionItem));
|
repaintItem(std::exchange(_selectedItem, _mouseActionItem));
|
||||||
|
@ -677,7 +675,6 @@ void InnerWidget::mouseActionStart(const QPoint &screenPos, Qt::MouseButton butt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!_mouseActionItem) {
|
if (!_mouseActionItem) {
|
||||||
_mouseAction = MouseAction::None;
|
_mouseAction = MouseAction::None;
|
||||||
|
@ -784,9 +781,9 @@ void InnerWidget::updateSelected() {
|
||||||
dragState = item->getState(itemPoint, request);
|
dragState = item->getState(itemPoint, request);
|
||||||
lnkhost = item;
|
lnkhost = item;
|
||||||
if (!dragState.link && itemPoint.x() >= st::historyPhotoLeft && itemPoint.x() < st::historyPhotoLeft + st::msgPhotoSize) {
|
if (!dragState.link && itemPoint.x() >= st::historyPhotoLeft && itemPoint.x() < st::historyPhotoLeft + st::msgPhotoSize) {
|
||||||
if (auto msg = item->toHistoryMessage()) {
|
if (auto message = item->toHistoryMessage()) {
|
||||||
if (msg->hasFromPhoto()) {
|
if (message->hasFromPhoto()) {
|
||||||
enumerateUserpics([&dragState, &lnkhost, &point](HistoryMessage *message, int userpicTop) -> bool {
|
enumerateUserpics([&dragState, &lnkhost, &point](gsl::not_null<HistoryMessage*> message, int userpicTop) -> bool {
|
||||||
// stop enumeration if the userpic is below our point
|
// stop enumeration if the userpic is below our point
|
||||||
if (userpicTop > point.y()) {
|
if (userpicTop > point.y()) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -152,7 +152,7 @@ private:
|
||||||
// This function finds all userpics on the left that are displayed and calls template method
|
// This function finds all userpics on the left that are displayed and calls template method
|
||||||
// for each found userpic (from the top to the bottom) using enumerateItems() method.
|
// for each found userpic (from the top to the bottom) using enumerateItems() method.
|
||||||
//
|
//
|
||||||
// Method has "bool (*Method)(HistoryMessage *message, int userpicTop)" signature
|
// Method has "bool (*Method)(gsl::not_null<HistoryMessage*> message, int userpicTop)" signature
|
||||||
// if it returns false the enumeration stops immidiately.
|
// if it returns false the enumeration stops immidiately.
|
||||||
template <typename Method>
|
template <typename Method>
|
||||||
void enumerateUserpics(Method method);
|
void enumerateUserpics(Method method);
|
||||||
|
@ -160,7 +160,7 @@ private:
|
||||||
// This function finds all date elements that are displayed and calls template method
|
// This function finds all date elements that are displayed and calls template method
|
||||||
// for each found date element (from the bottom to the top) using enumerateItems() method.
|
// for each found date element (from the bottom to the top) using enumerateItems() method.
|
||||||
//
|
//
|
||||||
// Method has "bool (*Method)(HistoryItem *item, int itemtop, int dateTop)" signature
|
// Method has "bool (*Method)(gsl::not_null<HistoryItem*> item, int itemtop, int dateTop)" signature
|
||||||
// if it returns false the enumeration stops immidiately.
|
// if it returns false the enumeration stops immidiately.
|
||||||
template <typename Method>
|
template <typename Method>
|
||||||
void enumerateDates(Method method);
|
void enumerateDates(Method method);
|
||||||
|
|
|
@ -20,6 +20,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#include "history/history_admin_log_item.h"
|
#include "history/history_admin_log_item.h"
|
||||||
|
|
||||||
|
#include "history/history_service.h"
|
||||||
|
#include "history/history_message.h"
|
||||||
#include "history/history_admin_log_inner.h"
|
#include "history/history_admin_log_inner.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "messenger.h"
|
#include "messenger.h"
|
||||||
|
|
|
@ -22,6 +22,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "styles/style_history.h"
|
#include "styles/style_history.h"
|
||||||
#include "core/file_utilities.h"
|
#include "core/file_utilities.h"
|
||||||
|
#include "history/history_message.h"
|
||||||
#include "history/history_service_layout.h"
|
#include "history/history_service_layout.h"
|
||||||
#include "history/history_media_types.h"
|
#include "history/history_media_types.h"
|
||||||
#include "ui/widgets/popup_menu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
|
@ -270,7 +271,7 @@ void HistoryInner::enumerateUserpics(Method method) {
|
||||||
// -1 means we didn't find an attached to next message yet.
|
// -1 means we didn't find an attached to next message yet.
|
||||||
int lowestAttachedItemTop = -1;
|
int lowestAttachedItemTop = -1;
|
||||||
|
|
||||||
auto userpicCallback = [this, &lowestAttachedItemTop, &method](HistoryItem *item, int itemtop, int itembottom) {
|
auto userpicCallback = [this, &lowestAttachedItemTop, &method](gsl::not_null<HistoryItem*> item, int itemtop, int itembottom) {
|
||||||
// Skip all service messages.
|
// Skip all service messages.
|
||||||
auto message = item->toHistoryMessage();
|
auto message = item->toHistoryMessage();
|
||||||
if (!message) return true;
|
if (!message) return true;
|
||||||
|
@ -318,7 +319,7 @@ void HistoryInner::enumerateDates(Method method) {
|
||||||
// -1 means we didn't find a same-day with previous message yet.
|
// -1 means we didn't find a same-day with previous message yet.
|
||||||
auto lowestInOneDayItemBottom = -1;
|
auto lowestInOneDayItemBottom = -1;
|
||||||
|
|
||||||
auto dateCallback = [this, &lowestInOneDayItemBottom, &method, drawtop](HistoryItem *item, int itemtop, int itembottom) {
|
auto dateCallback = [this, &lowestInOneDayItemBottom, &method, drawtop](gsl::not_null<HistoryItem*> item, int itemtop, int itembottom) {
|
||||||
if (lowestInOneDayItemBottom < 0 && item->isInOneDayWithPrevious()) {
|
if (lowestInOneDayItemBottom < 0 && item->isInOneDayWithPrevious()) {
|
||||||
lowestInOneDayItemBottom = itembottom - item->marginBottom();
|
lowestInOneDayItemBottom = itembottom - item->marginBottom();
|
||||||
}
|
}
|
||||||
|
@ -508,7 +509,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mtop >= 0 || htop >= 0) {
|
if (mtop >= 0 || htop >= 0) {
|
||||||
enumerateUserpics([&p, &clip](HistoryMessage *message, int userpicTop) {
|
enumerateUserpics([&p, &clip](gsl::not_null<HistoryMessage*> message, int userpicTop) {
|
||||||
// stop the enumeration if the userpic is below the painted rect
|
// stop the enumeration if the userpic is below the painted rect
|
||||||
if (userpicTop >= clip.top() + clip.height()) {
|
if (userpicTop >= clip.top() + clip.height()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -531,7 +532,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
|
||||||
//int showFloatingBefore = height() - 2 * (_visibleAreaBottom - _visibleAreaTop) - dateHeight;
|
//int showFloatingBefore = height() - 2 * (_visibleAreaBottom - _visibleAreaTop) - dateHeight;
|
||||||
|
|
||||||
auto scrollDateOpacity = _scrollDateOpacity.current(ms, _scrollDateShown ? 1. : 0.);
|
auto scrollDateOpacity = _scrollDateOpacity.current(ms, _scrollDateShown ? 1. : 0.);
|
||||||
enumerateDates([&p, &clip, scrollDateOpacity, dateHeight/*, lastDate, showFloatingBefore*/](HistoryItem *item, int itemtop, int dateTop) {
|
enumerateDates([&p, &clip, scrollDateOpacity, dateHeight/*, lastDate, showFloatingBefore*/](gsl::not_null<HistoryItem*> item, int itemtop, int dateTop) {
|
||||||
// stop the enumeration if the date is above the painted rect
|
// stop the enumeration if the date is above the painted rect
|
||||||
if (dateTop + dateHeight <= clip.top()) {
|
if (dateTop + dateHeight <= clip.top()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -2038,7 +2039,7 @@ void HistoryInner::onUpdateSelected() {
|
||||||
|
|
||||||
auto dateHeight = st::msgServicePadding.bottom() + st::msgServiceFont->height + st::msgServicePadding.top();
|
auto dateHeight = st::msgServicePadding.bottom() + st::msgServiceFont->height + st::msgServicePadding.top();
|
||||||
auto scrollDateOpacity = _scrollDateOpacity.current(_scrollDateShown ? 1. : 0.);
|
auto scrollDateOpacity = _scrollDateOpacity.current(_scrollDateShown ? 1. : 0.);
|
||||||
enumerateDates([this, &dragState, &lnkhost, &point, scrollDateOpacity, dateHeight/*, lastDate, showFloatingBefore*/](HistoryItem *item, int itemtop, int dateTop) {
|
enumerateDates([this, &dragState, &lnkhost, &point, scrollDateOpacity, dateHeight/*, lastDate, showFloatingBefore*/](gsl::not_null<HistoryItem*> item, int itemtop, int dateTop) {
|
||||||
// stop enumeration if the date is above our point
|
// stop enumeration if the date is above our point
|
||||||
if (dateTop + dateHeight <= point.y()) {
|
if (dateTop + dateHeight <= point.y()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -2097,7 +2098,7 @@ void HistoryInner::onUpdateSelected() {
|
||||||
if (!dragState.link && m.x() >= st::historyPhotoLeft && m.x() < st::historyPhotoLeft + st::msgPhotoSize) {
|
if (!dragState.link && m.x() >= st::historyPhotoLeft && m.x() < st::historyPhotoLeft + st::msgPhotoSize) {
|
||||||
if (auto msg = item->toHistoryMessage()) {
|
if (auto msg = item->toHistoryMessage()) {
|
||||||
if (msg->hasFromPhoto()) {
|
if (msg->hasFromPhoto()) {
|
||||||
enumerateUserpics([&dragState, &lnkhost, &point](HistoryMessage *message, int userpicTop) -> bool {
|
enumerateUserpics([&dragState, &lnkhost, &point](gsl::not_null<HistoryMessage*> message, int userpicTop) -> bool {
|
||||||
// stop enumeration if the userpic is below our point
|
// stop enumeration if the userpic is below our point
|
||||||
if (userpicTop > point.y()) {
|
if (userpicTop > point.y()) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -272,7 +272,7 @@ private:
|
||||||
// This function finds all history items that are displayed and calls template method
|
// This function finds all history items that are displayed and calls template method
|
||||||
// for each found message (in given direction) in the passed history with passed top offset.
|
// for each found message (in given direction) in the passed history with passed top offset.
|
||||||
//
|
//
|
||||||
// Method has "bool (*Method)(HistoryItem *item, int itemtop, int itembottom)" signature
|
// Method has "bool (*Method)(gsl::not_null<HistoryItem*> item, int itemtop, int itembottom)" signature
|
||||||
// if it returns false the enumeration stops immidiately.
|
// if it returns false the enumeration stops immidiately.
|
||||||
template <bool TopToBottom, typename Method>
|
template <bool TopToBottom, typename Method>
|
||||||
void enumerateItemsInHistory(History *history, int historytop, Method method);
|
void enumerateItemsInHistory(History *history, int historytop, Method method);
|
||||||
|
@ -292,7 +292,7 @@ private:
|
||||||
// This function finds all userpics on the left that are displayed and calls template method
|
// This function finds all userpics on the left that are displayed and calls template method
|
||||||
// for each found userpic (from the top to the bottom) using enumerateItems() method.
|
// for each found userpic (from the top to the bottom) using enumerateItems() method.
|
||||||
//
|
//
|
||||||
// Method has "bool (*Method)(HistoryMessage *message, int userpicTop)" signature
|
// Method has "bool (*Method)(gsl::not_null<HistoryMessage*> message, int userpicTop)" signature
|
||||||
// if it returns false the enumeration stops immidiately.
|
// if it returns false the enumeration stops immidiately.
|
||||||
template <typename Method>
|
template <typename Method>
|
||||||
void enumerateUserpics(Method method);
|
void enumerateUserpics(Method method);
|
||||||
|
@ -300,7 +300,7 @@ private:
|
||||||
// This function finds all date elements that are displayed and calls template method
|
// This function finds all date elements that are displayed and calls template method
|
||||||
// for each found date element (from the bottom to the top) using enumerateItems() method.
|
// for each found date element (from the bottom to the top) using enumerateItems() method.
|
||||||
//
|
//
|
||||||
// Method has "bool (*Method)(HistoryItem *item, int itemtop, int dateTop)" signature
|
// Method has "bool (*Method)(gsl::not_null<HistoryItem*> item, int itemtop, int dateTop)" signature
|
||||||
// if it returns false the enumeration stops immidiately.
|
// if it returns false the enumeration stops immidiately.
|
||||||
template <typename Method>
|
template <typename Method>
|
||||||
void enumerateDates(Method method);
|
void enumerateDates(Method method);
|
||||||
|
|
|
@ -24,6 +24,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "history/history_service_layout.h"
|
#include "history/history_service_layout.h"
|
||||||
#include "history/history_media_types.h"
|
#include "history/history_media_types.h"
|
||||||
|
#include "history/history_message.h"
|
||||||
#include "media/media_clip_reader.h"
|
#include "media/media_clip_reader.h"
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
#include "styles/style_history.h"
|
#include "styles/style_history.h"
|
||||||
|
@ -562,6 +563,10 @@ HistoryMediaPtr::HistoryMediaPtr(std::unique_ptr<HistoryMedia> pointer) : _point
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HistoryMediaPtr::reset(std::unique_ptr<HistoryMedia> pointer) {
|
||||||
|
*this = std::move(pointer);
|
||||||
|
}
|
||||||
|
|
||||||
HistoryMediaPtr &HistoryMediaPtr::operator=(std::unique_ptr<HistoryMedia> pointer) {
|
HistoryMediaPtr &HistoryMediaPtr::operator=(std::unique_ptr<HistoryMedia> pointer) {
|
||||||
if (_pointer) {
|
if (_pointer) {
|
||||||
_pointer->detachFromParent();
|
_pointer->detachFromParent();
|
||||||
|
@ -573,6 +578,10 @@ HistoryMediaPtr &HistoryMediaPtr::operator=(std::unique_ptr<HistoryMedia> pointe
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HistoryMediaPtr::~HistoryMediaPtr() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
TextSelection unshiftSelection(TextSelection selection, const Text &byText) {
|
TextSelection unshiftSelection(TextSelection selection, const Text &byText) {
|
||||||
|
|
|
@ -441,9 +441,7 @@ public:
|
||||||
HistoryMedia *get() const {
|
HistoryMedia *get() const {
|
||||||
return _pointer.get();
|
return _pointer.get();
|
||||||
}
|
}
|
||||||
void reset(std::unique_ptr<HistoryMedia> pointer = nullptr) {
|
void reset(std::unique_ptr<HistoryMedia> pointer = nullptr);
|
||||||
*this = std::move(pointer);
|
|
||||||
}
|
|
||||||
bool isNull() const {
|
bool isNull() const {
|
||||||
return !_pointer;
|
return !_pointer;
|
||||||
}
|
}
|
||||||
|
@ -458,9 +456,7 @@ public:
|
||||||
explicit operator bool() const {
|
explicit operator bool() const {
|
||||||
return !isNull();
|
return !isNull();
|
||||||
}
|
}
|
||||||
~HistoryMediaPtr() {
|
~HistoryMediaPtr();
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<HistoryMedia> _pointer;
|
std::unique_ptr<HistoryMedia> _pointer;
|
||||||
|
|
|
@ -32,6 +32,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "boxes/add_contact_box.h"
|
#include "boxes/add_contact_box.h"
|
||||||
#include "core/click_handler_types.h"
|
#include "core/click_handler_types.h"
|
||||||
#include "history/history_location_manager.h"
|
#include "history/history_location_manager.h"
|
||||||
|
#include "history/history_message.h"
|
||||||
#include "window/window_controller.h"
|
#include "window/window_controller.h"
|
||||||
#include "styles/style_history.h"
|
#include "styles/style_history.h"
|
||||||
#include "calls/calls_instance.h"
|
#include "calls/calls_instance.h"
|
||||||
|
@ -87,7 +88,7 @@ bool needReSetInlineResultDocument(const MTPMessageMedia &media, DocumentData *e
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void historyInitMedia() {
|
void HistoryInitMedia() {
|
||||||
initTextOptions();
|
initTextOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,6 +594,19 @@ TextWithEntities HistoryPhoto::selectedText(TextSelection selection) const {
|
||||||
return captionedSelectedText(lang(lng_in_dlg_photo), _caption, selection);
|
return captionedSelectedText(lang(lng_in_dlg_photo), _caption, selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HistoryPhoto::needsBubble() const {
|
||||||
|
if (!_caption.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (auto message = _parent->toHistoryMessage()) {
|
||||||
|
return message->viaBot()
|
||||||
|
|| message->Has<HistoryMessageForwarded>()
|
||||||
|
|| message->Has<HistoryMessageReply>()
|
||||||
|
|| message->displayFromName();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int32 HistoryPhoto::addToOverview(AddToOverviewMethod method) {
|
int32 HistoryPhoto::addToOverview(AddToOverviewMethod method) {
|
||||||
auto result = int32(0);
|
auto result = int32(0);
|
||||||
if (_parent->toHistoryMessage()) {
|
if (_parent->toHistoryMessage()) {
|
||||||
|
@ -887,6 +901,19 @@ TextWithEntities HistoryVideo::selectedText(TextSelection selection) const {
|
||||||
return captionedSelectedText(lang(lng_in_dlg_video), _caption, selection);
|
return captionedSelectedText(lang(lng_in_dlg_video), _caption, selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HistoryVideo::needsBubble() const {
|
||||||
|
if (!_caption.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (auto message = _parent->toHistoryMessage()) {
|
||||||
|
return message->viaBot()
|
||||||
|
|| message->Has<HistoryMessageForwarded>()
|
||||||
|
|| message->Has<HistoryMessageReply>()
|
||||||
|
|| message->displayFromName();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int32 HistoryVideo::addToOverview(AddToOverviewMethod method) {
|
int32 HistoryVideo::addToOverview(AddToOverviewMethod method) {
|
||||||
return addToOneOverview(OverviewVideos, method);
|
return addToOneOverview(OverviewVideos, method);
|
||||||
}
|
}
|
||||||
|
@ -2284,6 +2311,22 @@ TextWithEntities HistoryGif::selectedText(TextSelection selection) const {
|
||||||
return captionedSelectedText(mediaTypeString(), _caption, selection);
|
return captionedSelectedText(mediaTypeString(), _caption, selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HistoryGif::needsBubble() const {
|
||||||
|
if (_data->isRoundVideo()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!_caption.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (auto message = _parent->toHistoryMessage()) {
|
||||||
|
return message->viaBot()
|
||||||
|
|| message->Has<HistoryMessageForwarded>()
|
||||||
|
|| message->Has<HistoryMessageReply>()
|
||||||
|
|| message->displayFromName();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int32 HistoryGif::addToOverview(AddToOverviewMethod method) {
|
int32 HistoryGif::addToOverview(AddToOverviewMethod method) {
|
||||||
auto result = int32(0);
|
auto result = int32(0);
|
||||||
if (_data->isRoundVideo()) {
|
if (_data->isRoundVideo()) {
|
||||||
|
@ -3156,11 +3199,13 @@ void HistoryWebPage::initDimensions() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto textFloatsAroundInfo = !_asArticle && !_attach && isBubbleBottom();
|
||||||
|
|
||||||
// init strings
|
// init strings
|
||||||
if (_description.isEmpty() && !_data->description.text.isEmpty()) {
|
if (_description.isEmpty() && !_data->description.text.isEmpty()) {
|
||||||
auto text = _data->description;
|
auto text = _data->description;
|
||||||
|
|
||||||
if (!_asArticle && !_attach) {
|
if (textFloatsAroundInfo) {
|
||||||
text.text += _parent->skipBlock();
|
text.text += _parent->skipBlock();
|
||||||
}
|
}
|
||||||
auto opts = &_webpageDescriptionOptions;
|
auto opts = &_webpageDescriptionOptions;
|
||||||
|
@ -3172,7 +3217,7 @@ void HistoryWebPage::initDimensions() {
|
||||||
_description.setMarkedText(st::webPageDescriptionStyle, text, *opts);
|
_description.setMarkedText(st::webPageDescriptionStyle, text, *opts);
|
||||||
}
|
}
|
||||||
if (_title.isEmpty() && !title.isEmpty()) {
|
if (_title.isEmpty() && !title.isEmpty()) {
|
||||||
if (!_asArticle && !_attach && _description.isEmpty()) {
|
if (textFloatsAroundInfo && _description.isEmpty()) {
|
||||||
title += _parent->skipBlock();
|
title += _parent->skipBlock();
|
||||||
}
|
}
|
||||||
_title.setText(st::webPageTitleStyle, title, _webpageTitleOptions);
|
_title.setText(st::webPageTitleStyle, title, _webpageTitleOptions);
|
||||||
|
@ -3218,7 +3263,7 @@ void HistoryWebPage::initDimensions() {
|
||||||
if (!attachAtTop) _minh += st::mediaInBubbleSkip;
|
if (!attachAtTop) _minh += st::mediaInBubbleSkip;
|
||||||
|
|
||||||
_attach->initDimensions();
|
_attach->initDimensions();
|
||||||
QMargins bubble(_attach->bubbleMargins());
|
auto bubble = _attach->bubbleMargins();
|
||||||
auto maxMediaWidth = _attach->maxWidth() - bubble.left() - bubble.right();
|
auto maxMediaWidth = _attach->maxWidth() - bubble.left() - bubble.right();
|
||||||
if (isBubbleBottom() && _attach->customInfoLayout()) {
|
if (isBubbleBottom() && _attach->customInfoLayout()) {
|
||||||
maxMediaWidth += skipBlockWidth;
|
maxMediaWidth += skipBlockWidth;
|
||||||
|
@ -3307,7 +3352,7 @@ int HistoryWebPage::resizeGetHeight(int width) {
|
||||||
if (_description.isEmpty()) {
|
if (_description.isEmpty()) {
|
||||||
_descriptionLines = 0;
|
_descriptionLines = 0;
|
||||||
} else {
|
} else {
|
||||||
int32 descriptionHeight = _description.countHeight(width);
|
auto descriptionHeight = _description.countHeight(width);
|
||||||
if (descriptionHeight < (linesMax - siteNameLines - _titleLines) * st::webPageDescriptionFont->height) {
|
if (descriptionHeight < (linesMax - siteNameLines - _titleLines) * st::webPageDescriptionFont->height) {
|
||||||
_descriptionLines = (descriptionHeight / st::webPageDescriptionFont->height);
|
_descriptionLines = (descriptionHeight / st::webPageDescriptionFont->height);
|
||||||
} else {
|
} else {
|
||||||
|
@ -3320,7 +3365,7 @@ int HistoryWebPage::resizeGetHeight(int width) {
|
||||||
auto attachAtTop = !_siteNameWidth && !_titleLines && !_descriptionLines;
|
auto attachAtTop = !_siteNameWidth && !_titleLines && !_descriptionLines;
|
||||||
if (!attachAtTop) _height += st::mediaInBubbleSkip;
|
if (!attachAtTop) _height += st::mediaInBubbleSkip;
|
||||||
|
|
||||||
QMargins bubble(_attach->bubbleMargins());
|
auto bubble = _attach->bubbleMargins();
|
||||||
|
|
||||||
_attach->resizeGetHeight(width + bubble.left() + bubble.right());
|
_attach->resizeGetHeight(width + bubble.left() + bubble.right());
|
||||||
_height += _attach->height() - bubble.top() - bubble.bottom();
|
_height += _attach->height() - bubble.top() - bubble.bottom();
|
||||||
|
@ -4636,6 +4681,19 @@ TextWithEntities HistoryLocation::selectedText(TextSelection selection) const {
|
||||||
return titleResult;
|
return titleResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HistoryLocation::needsBubble() const {
|
||||||
|
if (!_title.isEmpty() || !_description.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (auto message = _parent->toHistoryMessage()) {
|
||||||
|
return message->viaBot()
|
||||||
|
|| message->Has<HistoryMessageForwarded>()
|
||||||
|
|| message->Has<HistoryMessageReply>()
|
||||||
|
|| message->displayFromName();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int32 HistoryLocation::fullWidth() const {
|
int32 HistoryLocation::fullWidth() const {
|
||||||
return st::locationSize.width();
|
return st::locationSize.width();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "history/history_media.h"
|
||||||
#include "ui/effects/radial_animation.h"
|
#include "ui/effects/radial_animation.h"
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
|
@ -28,7 +29,7 @@ class Playback;
|
||||||
} // namespace Clip
|
} // namespace Clip
|
||||||
} // namespace Media
|
} // namespace Media
|
||||||
|
|
||||||
void historyInitMedia();
|
void HistoryInitMedia();
|
||||||
|
|
||||||
class HistoryFileMedia : public HistoryMedia {
|
class HistoryFileMedia : public HistoryMedia {
|
||||||
public:
|
public:
|
||||||
|
@ -167,18 +168,7 @@ public:
|
||||||
TextWithEntities getCaption() const override {
|
TextWithEntities getCaption() const override {
|
||||||
return _caption.originalTextWithEntities();
|
return _caption.originalTextWithEntities();
|
||||||
}
|
}
|
||||||
bool needsBubble() const override {
|
bool needsBubble() const override;
|
||||||
if (!_caption.isEmpty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (auto message = _parent->toHistoryMessage()) {
|
|
||||||
return message->viaBot()
|
|
||||||
|| message->Has<HistoryMessageForwarded>()
|
|
||||||
|| message->Has<HistoryMessageReply>()
|
|
||||||
|| message->displayFromName();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool customInfoLayout() const override {
|
bool customInfoLayout() const override {
|
||||||
return _caption.isEmpty();
|
return _caption.isEmpty();
|
||||||
}
|
}
|
||||||
|
@ -264,18 +254,7 @@ public:
|
||||||
TextWithEntities getCaption() const override {
|
TextWithEntities getCaption() const override {
|
||||||
return _caption.originalTextWithEntities();
|
return _caption.originalTextWithEntities();
|
||||||
}
|
}
|
||||||
bool needsBubble() const override {
|
bool needsBubble() const override;
|
||||||
if (!_caption.isEmpty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (auto message = _parent->toHistoryMessage()) {
|
|
||||||
return message->viaBot()
|
|
||||||
|| message->Has<HistoryMessageForwarded>()
|
|
||||||
|| message->Has<HistoryMessageReply>()
|
|
||||||
|| message->displayFromName();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool customInfoLayout() const override {
|
bool customInfoLayout() const override {
|
||||||
return _caption.isEmpty();
|
return _caption.isEmpty();
|
||||||
}
|
}
|
||||||
|
@ -536,21 +515,7 @@ public:
|
||||||
TextWithEntities getCaption() const override {
|
TextWithEntities getCaption() const override {
|
||||||
return _caption.originalTextWithEntities();
|
return _caption.originalTextWithEntities();
|
||||||
}
|
}
|
||||||
bool needsBubble() const override {
|
bool needsBubble() const override;
|
||||||
if (_data->isRoundVideo()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!_caption.isEmpty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (auto message = _parent->toHistoryMessage()) {
|
|
||||||
return message->viaBot()
|
|
||||||
|| message->Has<HistoryMessageForwarded>()
|
|
||||||
|| message->Has<HistoryMessageReply>()
|
|
||||||
|| message->displayFromName();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool customInfoLayout() const override {
|
bool customInfoLayout() const override {
|
||||||
return _caption.isEmpty();
|
return _caption.isEmpty();
|
||||||
}
|
}
|
||||||
|
@ -1109,18 +1074,7 @@ public:
|
||||||
QString inDialogsText() const override;
|
QString inDialogsText() const override;
|
||||||
TextWithEntities selectedText(TextSelection selection) const override;
|
TextWithEntities selectedText(TextSelection selection) const override;
|
||||||
|
|
||||||
bool needsBubble() const override {
|
bool needsBubble() const override;
|
||||||
if (!_title.isEmpty() || !_description.isEmpty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (auto message = _parent->toHistoryMessage()) {
|
|
||||||
return message->viaBot()
|
|
||||||
|| message->Has<HistoryMessageForwarded>()
|
|
||||||
|| message->Has<HistoryMessageReply>()
|
|
||||||
|| message->displayFromName();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool customInfoLayout() const override {
|
bool customInfoLayout() const override {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "history/history_location_manager.h"
|
#include "history/history_location_manager.h"
|
||||||
#include "history/history_service_layout.h"
|
#include "history/history_service_layout.h"
|
||||||
#include "history/history_media_types.h"
|
#include "history/history_media_types.h"
|
||||||
|
#include "history/history_service.h"
|
||||||
#include "auth_session.h"
|
#include "auth_session.h"
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
#include "styles/style_widgets.h"
|
#include "styles/style_widgets.h"
|
||||||
|
@ -37,26 +38,11 @@ namespace {
|
||||||
|
|
||||||
constexpr auto kPinnedMessageTextLimit = 16;
|
constexpr auto kPinnedMessageTextLimit = 16;
|
||||||
|
|
||||||
TextParseOptions _historySrvOptions = {
|
|
||||||
TextParseLinks | TextParseMentions | TextParseHashtags/* | TextParseMultiline*/ | TextParseRichText, // flags
|
|
||||||
0, // maxw
|
|
||||||
0, // maxh
|
|
||||||
Qt::LayoutDirectionAuto, // lang-dependent
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void initTextOptions() {
|
inline void initTextOptions() {
|
||||||
_historySrvOptions.dir = _textNameOptions.dir = _textDlgOptions.dir = cLangDir();
|
_historySrvOptions.dir = _textNameOptions.dir = _textDlgOptions.dir = cLangDir();
|
||||||
_textDlgOptions.maxw = st::dialogsWidthMax * 2;
|
_textDlgOptions.maxw = st::dialogsWidthMax * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
ApiWrap::RequestMessageDataCallback historyDependentItemCallback(const FullMsgId &msgId) {
|
|
||||||
return [dependent = msgId](ChannelData *channel, MsgId msgId) {
|
|
||||||
if (auto item = App::histItemById(dependent)) {
|
|
||||||
item->updateDependencyItem();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
style::color fromNameFg(int index) {
|
style::color fromNameFg(int index) {
|
||||||
Expects(index >= 0 && index < 8);
|
Expects(index >= 0 && index < 8);
|
||||||
style::color colors[] = {
|
style::color colors[] = {
|
||||||
|
@ -87,8 +73,8 @@ style::color fromNameFgSelected(int index) {
|
||||||
return colors[index];
|
return colors[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
MTPDmessage::Flags newForwardedFlags(PeerData *peer, int32 from, HistoryMessage *fwd) {
|
MTPDmessage::Flags NewForwardedFlags(gsl::not_null<PeerData*> peer, int32 from, gsl::not_null<HistoryMessage*> fwd) {
|
||||||
auto result = newMessageFlags(peer) | MTPDmessage::Flag::f_fwd_from;
|
auto result = NewMessageFlags(peer) | MTPDmessage::Flag::f_fwd_from;
|
||||||
if (from) {
|
if (from) {
|
||||||
result |= MTPDmessage::Flag::f_from_id;
|
result |= MTPDmessage::Flag::f_from_id;
|
||||||
}
|
}
|
||||||
|
@ -121,7 +107,26 @@ MTPDmessage::Flags newForwardedFlags(PeerData *peer, int32 from, HistoryMessage
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void historyInitMessages() {
|
base::lambda<void(ChannelData*, MsgId)> HistoryDependentItemCallback(const FullMsgId &msgId) {
|
||||||
|
return [dependent = msgId](ChannelData *channel, MsgId msgId) {
|
||||||
|
if (auto item = App::histItemById(dependent)) {
|
||||||
|
item->updateDependencyItem();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
MTPDmessage::Flags NewMessageFlags(gsl::not_null<PeerData*> peer) {
|
||||||
|
MTPDmessage::Flags result = 0;
|
||||||
|
if (!peer->isSelf()) {
|
||||||
|
result |= MTPDmessage::Flag::f_out;
|
||||||
|
//if (p->isChat() || (p->isUser() && !p->asUser()->botInfo)) {
|
||||||
|
// result |= MTPDmessage::Flag::f_unread;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryInitMessages() {
|
||||||
initTextOptions();
|
initTextOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,8 +456,8 @@ HistoryMessage::HistoryMessage(gsl::not_null<History*> history, const MTPDmessag
|
||||||
setText(TextWithEntities {});
|
setText(TextWithEntities {});
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryMessage::HistoryMessage(gsl::not_null<History*> history, MsgId id, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *fwd)
|
HistoryMessage::HistoryMessage(gsl::not_null<History*> history, MsgId id, MTPDmessage::Flags flags, QDateTime date, int32 from, gsl::not_null<HistoryMessage*> fwd)
|
||||||
: HistoryItem(history, id, newForwardedFlags(history->peer, from, fwd) | flags, date, from) {
|
: HistoryItem(history, id, NewForwardedFlags(history->peer, from, fwd) | flags, date, from) {
|
||||||
CreateConfig config;
|
CreateConfig config;
|
||||||
|
|
||||||
if (fwd->Has<HistoryMessageForwarded>() || !fwd->history()->peer->isSelf()) {
|
if (fwd->Has<HistoryMessageForwarded>() || !fwd->history()->peer->isSelf()) {
|
||||||
|
@ -596,6 +601,10 @@ bool HistoryMessage::displayEditedBadge(bool hasViaBotOrInlineMarkup) const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HistoryMessage::uploading() const {
|
||||||
|
return _media && _media->uploading();
|
||||||
|
}
|
||||||
|
|
||||||
void HistoryMessage::createComponents(const CreateConfig &config) {
|
void HistoryMessage::createComponents(const CreateConfig &config) {
|
||||||
uint64 mask = 0;
|
uint64 mask = 0;
|
||||||
if (config.replyTo) {
|
if (config.replyTo) {
|
||||||
|
@ -638,7 +647,7 @@ void HistoryMessage::createComponents(const CreateConfig &config) {
|
||||||
if (auto reply = Get<HistoryMessageReply>()) {
|
if (auto reply = Get<HistoryMessageReply>()) {
|
||||||
reply->replyToMsgId = config.replyTo;
|
reply->replyToMsgId = config.replyTo;
|
||||||
if (!reply->updateData(this) && App::api()) {
|
if (!reply->updateData(this) && App::api()) {
|
||||||
App::api()->requestMessageData(history()->peer->asChannel(), reply->replyToMsgId, historyDependentItemCallback(fullId()));
|
App::api()->requestMessageData(history()->peer->asChannel(), reply->replyToMsgId, HistoryDependentItemCallback(fullId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (auto via = Get<HistoryMessageVia>()) {
|
if (auto via = Get<HistoryMessageVia>()) {
|
||||||
|
@ -793,24 +802,33 @@ int32 HistoryMessage::plainMaxWidth() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryMessage::initDimensions() {
|
void HistoryMessage::initDimensions() {
|
||||||
auto reply = Get<HistoryMessageReply>();
|
|
||||||
if (reply) {
|
|
||||||
reply->updateName();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateMediaInBubbleState();
|
updateMediaInBubbleState();
|
||||||
if (drawBubble()) {
|
if (drawBubble()) {
|
||||||
auto forwarded = Get<HistoryMessageForwarded>();
|
auto forwarded = Get<HistoryMessageForwarded>();
|
||||||
|
auto reply = Get<HistoryMessageReply>();
|
||||||
auto via = Get<HistoryMessageVia>();
|
auto via = Get<HistoryMessageVia>();
|
||||||
|
auto entry = Get<HistoryMessageLogEntryOriginal>();
|
||||||
if (forwarded) {
|
if (forwarded) {
|
||||||
forwarded->create(via);
|
forwarded->create(via);
|
||||||
}
|
}
|
||||||
|
if (reply) {
|
||||||
|
reply->updateName();
|
||||||
|
}
|
||||||
|
|
||||||
auto mediaDisplayed = false;
|
auto mediaDisplayed = false;
|
||||||
if (_media) {
|
if (_media) {
|
||||||
mediaDisplayed = _media->isDisplayed();
|
mediaDisplayed = _media->isDisplayed();
|
||||||
_media->initDimensions();
|
_media->initDimensions();
|
||||||
if (mediaDisplayed && _media->isBubbleBottom()) {
|
}
|
||||||
|
if (entry) {
|
||||||
|
entry->_page->initDimensions();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entry page is always a bubble bottom.
|
||||||
|
auto mediaOnBottom = (mediaDisplayed && _media->isBubbleBottom()) || (entry/* && entry->_page->isBubbleBottom()*/);
|
||||||
|
auto mediaOnTop = (mediaDisplayed && _media->isBubbleTop()) || (entry && entry->_page->isBubbleTop());
|
||||||
|
|
||||||
|
if (mediaDisplayed && mediaOnBottom) {
|
||||||
if (_text.hasSkipBlock()) {
|
if (_text.hasSkipBlock()) {
|
||||||
_text.removeSkipBlock();
|
_text.removeSkipBlock();
|
||||||
_textWidth = -1;
|
_textWidth = -1;
|
||||||
|
@ -821,43 +839,47 @@ void HistoryMessage::initDimensions() {
|
||||||
_textWidth = -1;
|
_textWidth = -1;
|
||||||
_textHeight = 0;
|
_textHeight = 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
auto entry = Get<HistoryMessageLogEntryOriginal>();
|
|
||||||
if (entry) {
|
|
||||||
entry->_page->initDimensions();
|
|
||||||
}
|
|
||||||
|
|
||||||
_maxw = plainMaxWidth();
|
_maxw = plainMaxWidth();
|
||||||
_minh = emptyText() ? 0 : _text.minHeight();
|
_minh = emptyText() ? 0 : _text.minHeight();
|
||||||
|
if (!mediaOnBottom) {
|
||||||
|
_minh += st::msgPadding.bottom();
|
||||||
|
if (mediaDisplayed) _minh += st::mediaInBubbleSkip;
|
||||||
|
}
|
||||||
|
if (!mediaOnTop) {
|
||||||
|
_minh += st::msgPadding.top();
|
||||||
|
if (mediaDisplayed) _minh += st::mediaInBubbleSkip;
|
||||||
|
if (entry) _minh += st::mediaInBubbleSkip;
|
||||||
|
}
|
||||||
if (mediaDisplayed) {
|
if (mediaDisplayed) {
|
||||||
if (!_media->isBubbleTop()) {
|
// Parts don't participate in maxWidth() in case of media message.
|
||||||
_minh += st::msgPadding.top() + st::mediaInBubbleSkip;
|
accumulate_max(_maxw, _media->maxWidth());
|
||||||
}
|
|
||||||
if (!_media->isBubbleBottom()) {
|
|
||||||
_minh += st::msgPadding.bottom() + st::mediaInBubbleSkip;
|
|
||||||
}
|
|
||||||
auto maxw = _media->maxWidth();
|
|
||||||
if (maxw > _maxw) _maxw = maxw;
|
|
||||||
_minh += _media->minHeight();
|
_minh += _media->minHeight();
|
||||||
} else {
|
} else {
|
||||||
_minh += st::msgPadding.top() + st::msgPadding.bottom();
|
// Count parts in maxWidth(), don't count them in minHeight().
|
||||||
|
// They will be added in resizeGetHeight() anyway.
|
||||||
if (displayFromName()) {
|
if (displayFromName()) {
|
||||||
auto namew = st::msgPadding.left() + author()->nameText.maxWidth() + st::msgPadding.right();
|
auto namew = st::msgPadding.left() + author()->nameText.maxWidth() + st::msgPadding.right();
|
||||||
if (via && !forwarded) {
|
if (via && !forwarded) {
|
||||||
namew += st::msgServiceFont->spacew + via->_maxWidth;
|
namew += st::msgServiceFont->spacew + via->_maxWidth;
|
||||||
}
|
}
|
||||||
if (namew > _maxw) _maxw = namew;
|
accumulate_max(_maxw, namew);
|
||||||
} else if (via && !forwarded) {
|
} else if (via && !forwarded) {
|
||||||
if (st::msgPadding.left() + via->_maxWidth + st::msgPadding.right() > _maxw) {
|
accumulate_max(_maxw, st::msgPadding.left() + via->_maxWidth + st::msgPadding.right());
|
||||||
_maxw = st::msgPadding.left() + via->_maxWidth + st::msgPadding.right();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (forwarded) {
|
if (forwarded) {
|
||||||
auto _namew = st::msgPadding.left() + forwarded->_text.maxWidth() + st::msgPadding.right();
|
auto namew = st::msgPadding.left() + forwarded->_text.maxWidth() + st::msgPadding.right();
|
||||||
if (via) {
|
if (via) {
|
||||||
_namew += st::msgServiceFont->spacew + via->_maxWidth;
|
namew += st::msgServiceFont->spacew + via->_maxWidth;
|
||||||
}
|
}
|
||||||
if (_namew > _maxw) _maxw = _namew;
|
accumulate_max(_maxw, namew);
|
||||||
|
}
|
||||||
|
if (reply) {
|
||||||
|
auto replyw = st::msgPadding.left() + reply->_maxReplyWidth - st::msgReplyPadding.left() - st::msgReplyPadding.right() + st::msgPadding.right();
|
||||||
|
if (reply->_replyToVia) {
|
||||||
|
replyw += st::msgServiceFont->spacew + reply->_replyToVia->_maxWidth;
|
||||||
|
}
|
||||||
|
accumulate_max(_maxw, replyw);
|
||||||
}
|
}
|
||||||
if (entry) {
|
if (entry) {
|
||||||
accumulate_max(_maxw, entry->_page->maxWidth());
|
accumulate_max(_maxw, entry->_page->maxWidth());
|
||||||
|
@ -874,22 +896,15 @@ void HistoryMessage::initDimensions() {
|
||||||
_maxw = st::msgMinWidth;
|
_maxw = st::msgMinWidth;
|
||||||
_minh = 0;
|
_minh = 0;
|
||||||
}
|
}
|
||||||
if (reply && !emptyText()) {
|
|
||||||
int replyw = st::msgPadding.left() + reply->_maxReplyWidth - st::msgReplyPadding.left() - st::msgReplyPadding.right() + st::msgPadding.right();
|
|
||||||
if (reply->_replyToVia) {
|
|
||||||
replyw += st::msgServiceFont->spacew + reply->_replyToVia->_maxWidth;
|
|
||||||
}
|
|
||||||
if (replyw > _maxw) _maxw = replyw;
|
|
||||||
}
|
|
||||||
if (auto markup = inlineReplyMarkup()) {
|
if (auto markup = inlineReplyMarkup()) {
|
||||||
if (!markup->inlineKeyboard) {
|
if (!markup->inlineKeyboard) {
|
||||||
markup->inlineKeyboard.reset(new ReplyKeyboard(this, std::make_unique<KeyboardStyle>(st::msgBotKbButton)));
|
markup->inlineKeyboard = std::make_unique<ReplyKeyboard>(this, std::make_unique<KeyboardStyle>(st::msgBotKbButton));
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we have a text bubble we can resize it to fit the keyboard
|
// if we have a text bubble we can resize it to fit the keyboard
|
||||||
// but if we have only media we don't do that
|
// but if we have only media we don't do that
|
||||||
if (!emptyText()) {
|
if (!emptyText()) {
|
||||||
_maxw = qMax(_maxw, markup->inlineKeyboard->naturalWidth());
|
accumulate_max(_maxw, markup->inlineKeyboard->naturalWidth());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -986,6 +1001,17 @@ void HistoryMessage::applyEditionToEmpty() {
|
||||||
finishEditionToEmpty();
|
finishEditionToEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HistoryMessage::displayForwardedFrom() const {
|
||||||
|
if (auto forwarded = Get<HistoryMessageForwarded>()) {
|
||||||
|
return Has<HistoryMessageVia>()
|
||||||
|
|| !_media
|
||||||
|
|| !_media->isDisplayed()
|
||||||
|
|| !_media->hideForwardedFrom()
|
||||||
|
|| forwarded->_authorOriginal->isChannel();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void HistoryMessage::updateMedia(const MTPMessageMedia *media) {
|
void HistoryMessage::updateMedia(const MTPMessageMedia *media) {
|
||||||
auto setMediaAllowed = [](HistoryMediaType type) {
|
auto setMediaAllowed = [](HistoryMediaType type) {
|
||||||
return (type == MediaTypeWebPage || type == MediaTypeGame || type == MediaTypeLocation);
|
return (type == MediaTypeWebPage || type == MediaTypeGame || type == MediaTypeLocation);
|
||||||
|
@ -1387,8 +1413,15 @@ void HistoryMessage::draw(Painter &p, QRect clip, TextSelection selection, TimeM
|
||||||
auto displayTail = skipTail ? RectPart::None : (outbg && !Adaptive::ChatWide()) ? RectPart::Right : RectPart::Left;
|
auto displayTail = skipTail ? RectPart::None : (outbg && !Adaptive::ChatWide()) ? RectPart::Right : RectPart::Left;
|
||||||
HistoryLayout::paintBubble(p, g, width(), selected, outbg, displayTail);
|
HistoryLayout::paintBubble(p, g, width(), selected, outbg, displayTail);
|
||||||
|
|
||||||
auto trect = g.marginsAdded(-st::msgPadding);
|
// Entry page is always a bubble bottom.
|
||||||
if (mediaDisplayed && _media->isBubbleTop()) {
|
auto mediaOnBottom = (mediaDisplayed && _media->isBubbleBottom()) || (entry/* && entry->_page->isBubbleBottom()*/);
|
||||||
|
auto mediaOnTop = (mediaDisplayed && _media->isBubbleTop()) || (entry && entry->_page->isBubbleTop());
|
||||||
|
|
||||||
|
auto trect = g.marginsRemoved(st::msgPadding);
|
||||||
|
if (mediaOnBottom) {
|
||||||
|
trect.setHeight(trect.height() + st::msgPadding.bottom());
|
||||||
|
}
|
||||||
|
if (mediaOnTop) {
|
||||||
trect.setY(trect.y() - st::msgPadding.top());
|
trect.setY(trect.y() - st::msgPadding.top());
|
||||||
} else {
|
} else {
|
||||||
paintFromName(p, trect, selected);
|
paintFromName(p, trect, selected);
|
||||||
|
@ -1396,13 +1429,10 @@ void HistoryMessage::draw(Painter &p, QRect clip, TextSelection selection, TimeM
|
||||||
paintReplyInfo(p, trect, selected);
|
paintReplyInfo(p, trect, selected);
|
||||||
paintViaBotIdInfo(p, trect, selected);
|
paintViaBotIdInfo(p, trect, selected);
|
||||||
}
|
}
|
||||||
if (mediaDisplayed && _media->isBubbleBottom()) {
|
|
||||||
trect.setHeight(trect.height() + st::msgPadding.bottom());
|
|
||||||
}
|
|
||||||
if (entry) {
|
if (entry) {
|
||||||
trect.setHeight(trect.height() - entry->_page->height());
|
trect.setHeight(trect.height() - entry->_page->height());
|
||||||
}
|
}
|
||||||
auto needDrawInfo = true;
|
auto needDrawInfo = mediaOnBottom ? !(entry ? entry->_page->customInfoLayout() : _media->customInfoLayout()) : true;
|
||||||
if (mediaDisplayed) {
|
if (mediaDisplayed) {
|
||||||
auto mediaAboveText = _media->isAboveMessage();
|
auto mediaAboveText = _media->isAboveMessage();
|
||||||
auto mediaHeight = _media->height();
|
auto mediaHeight = _media->height();
|
||||||
|
@ -1418,9 +1448,9 @@ void HistoryMessage::draw(Painter &p, QRect clip, TextSelection selection, TimeM
|
||||||
if (mediaAboveText) {
|
if (mediaAboveText) {
|
||||||
trect.setY(trect.y() + mediaHeight);
|
trect.setY(trect.y() + mediaHeight);
|
||||||
paintText(p, trect, selection);
|
paintText(p, trect, selection);
|
||||||
}
|
} else {
|
||||||
|
|
||||||
needDrawInfo = !_media->customInfoLayout();
|
needDrawInfo = !_media->customInfoLayout();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
paintText(p, trect, selection);
|
paintText(p, trect, selection);
|
||||||
}
|
}
|
||||||
|
@ -1563,11 +1593,14 @@ int HistoryMessage::performResizeGetHeight() {
|
||||||
auto entry = Get<HistoryMessageLogEntryOriginal>();
|
auto entry = Get<HistoryMessageLogEntryOriginal>();
|
||||||
|
|
||||||
auto mediaDisplayed = false;
|
auto mediaDisplayed = false;
|
||||||
auto mediaInBubbleState = MediaInBubbleState::None;
|
|
||||||
if (_media) {
|
if (_media) {
|
||||||
mediaDisplayed = _media->isDisplayed();
|
mediaDisplayed = _media->isDisplayed();
|
||||||
mediaInBubbleState = _media->inBubbleState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Entry page is always a bubble bottom.
|
||||||
|
auto mediaOnBottom = (mediaDisplayed && _media->isBubbleBottom()) || (entry/* && entry->_page->isBubbleBottom()*/);
|
||||||
|
auto mediaOnTop = (mediaDisplayed && _media->isBubbleTop()) || (entry && entry->_page->isBubbleTop());
|
||||||
|
|
||||||
if (contentWidth >= _maxw) {
|
if (contentWidth >= _maxw) {
|
||||||
_height = _minh;
|
_height = _minh;
|
||||||
if (mediaDisplayed) {
|
if (mediaDisplayed) {
|
||||||
|
@ -1587,16 +1620,17 @@ int HistoryMessage::performResizeGetHeight() {
|
||||||
}
|
}
|
||||||
_height = _textHeight;
|
_height = _textHeight;
|
||||||
}
|
}
|
||||||
|
if (!mediaOnBottom) {
|
||||||
|
_height += st::msgPadding.bottom();
|
||||||
|
if (mediaDisplayed) _height += st::mediaInBubbleSkip;
|
||||||
|
}
|
||||||
|
if (!mediaOnTop) {
|
||||||
|
_height += st::msgPadding.top();
|
||||||
|
if (mediaDisplayed) _height += st::mediaInBubbleSkip;
|
||||||
|
if (entry) _height += st::mediaInBubbleSkip;
|
||||||
|
}
|
||||||
if (mediaDisplayed) {
|
if (mediaDisplayed) {
|
||||||
if (!_media->isBubbleTop()) {
|
|
||||||
_height += st::msgPadding.top() + st::mediaInBubbleSkip;
|
|
||||||
}
|
|
||||||
if (!_media->isBubbleBottom()) {
|
|
||||||
_height += st::msgPadding.bottom() + st::mediaInBubbleSkip;
|
|
||||||
}
|
|
||||||
_height += _media->resizeGetHeight(contentWidth);
|
_height += _media->resizeGetHeight(contentWidth);
|
||||||
} else {
|
|
||||||
_height += st::msgPadding.top() + st::msgPadding.bottom();
|
|
||||||
}
|
}
|
||||||
if (entry) {
|
if (entry) {
|
||||||
_height += entry->_page->resizeGetHeight(contentWidth);
|
_height += entry->_page->resizeGetHeight(contentWidth);
|
||||||
|
@ -1887,6 +1921,16 @@ TextSelection HistoryMessage::adjustSelection(TextSelection selection, TextSelec
|
||||||
return { textSelection.from, fromMediaSelection(mediaSelection).to };
|
return { textSelection.from, fromMediaSelection(mediaSelection).to };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HistoryMessage::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
|
||||||
|
if (_media) _media->clickHandlerActiveChanged(p, active);
|
||||||
|
HistoryItem::clickHandlerActiveChanged(p, active);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryMessage::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) {
|
||||||
|
if (_media) _media->clickHandlerPressedChanged(p, pressed);
|
||||||
|
HistoryItem::clickHandlerPressedChanged(p, pressed);
|
||||||
|
}
|
||||||
|
|
||||||
QString HistoryMessage::notificationHeader() const {
|
QString HistoryMessage::notificationHeader() const {
|
||||||
return (!_history->peer->isUser() && !isPost()) ? from()->name : QString();
|
return (!_history->peer->isUser() && !isPost()) ? from()->name : QString();
|
||||||
}
|
}
|
||||||
|
@ -1905,644 +1949,3 @@ HistoryMessage::~HistoryMessage() {
|
||||||
reply->clearData(this);
|
reply->clearData(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
|
||||||
auto prepareChatAddUserText = [this](const MTPDmessageActionChatAddUser &action) {
|
|
||||||
auto result = PreparedText {};
|
|
||||||
auto &users = action.vusers.v;
|
|
||||||
if (users.size() == 1) {
|
|
||||||
auto u = App::user(peerFromUser(users[0]));
|
|
||||||
if (u == _from) {
|
|
||||||
result.links.push_back(fromLink());
|
|
||||||
result.text = lng_action_user_joined(lt_from, fromLinkText());
|
|
||||||
} else {
|
|
||||||
result.links.push_back(fromLink());
|
|
||||||
result.links.push_back(peerOpenClickHandler(u));
|
|
||||||
result.text = lng_action_add_user(lt_from, fromLinkText(), lt_user, textcmdLink(2, u->name));
|
|
||||||
}
|
|
||||||
} else if (users.isEmpty()) {
|
|
||||||
result.links.push_back(fromLink());
|
|
||||||
result.text = lng_action_add_user(lt_from, fromLinkText(), lt_user, "somebody");
|
|
||||||
} else {
|
|
||||||
result.links.push_back(fromLink());
|
|
||||||
for (auto i = 0, l = users.size(); i != l; ++i) {
|
|
||||||
auto user = App::user(peerFromUser(users[i]));
|
|
||||||
result.links.push_back(peerOpenClickHandler(user));
|
|
||||||
|
|
||||||
auto linkText = textcmdLink(i + 2, user->name);
|
|
||||||
if (i == 0) {
|
|
||||||
result.text = linkText;
|
|
||||||
} else if (i + 1 == l) {
|
|
||||||
result.text = lng_action_add_users_and_last(lt_accumulated, result.text, lt_user, linkText);
|
|
||||||
} else {
|
|
||||||
result.text = lng_action_add_users_and_one(lt_accumulated, result.text, lt_user, linkText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result.text = lng_action_add_users_many(lt_from, fromLinkText(), lt_users, result.text);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto prepareChatJoinedByLink = [this](const MTPDmessageActionChatJoinedByLink &action) {
|
|
||||||
auto result = PreparedText {};
|
|
||||||
result.links.push_back(fromLink());
|
|
||||||
result.text = lng_action_user_joined_by_link(lt_from, fromLinkText());
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto prepareChatCreate = [this](const MTPDmessageActionChatCreate &action) {
|
|
||||||
auto result = PreparedText {};
|
|
||||||
result.links.push_back(fromLink());
|
|
||||||
result.text = lng_action_created_chat(lt_from, fromLinkText(), lt_title, textClean(qs(action.vtitle)));
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto prepareChannelCreate = [this](const MTPDmessageActionChannelCreate &action) {
|
|
||||||
auto result = PreparedText {};
|
|
||||||
if (isPost()) {
|
|
||||||
result.text = lang(lng_action_created_channel);
|
|
||||||
} else {
|
|
||||||
result.links.push_back(fromLink());
|
|
||||||
result.text = lng_action_created_chat(lt_from, fromLinkText(), lt_title, textClean(qs(action.vtitle)));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto prepareChatDeletePhoto = [this] {
|
|
||||||
auto result = PreparedText {};
|
|
||||||
if (isPost()) {
|
|
||||||
result.text = lang(lng_action_removed_photo_channel);
|
|
||||||
} else {
|
|
||||||
result.links.push_back(fromLink());
|
|
||||||
result.text = lng_action_removed_photo(lt_from, fromLinkText());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto prepareChatDeleteUser = [this](const MTPDmessageActionChatDeleteUser &action) {
|
|
||||||
auto result = PreparedText {};
|
|
||||||
if (peerFromUser(action.vuser_id) == _from->id) {
|
|
||||||
result.links.push_back(fromLink());
|
|
||||||
result.text = lng_action_user_left(lt_from, fromLinkText());
|
|
||||||
} else {
|
|
||||||
auto user = App::user(peerFromUser(action.vuser_id));
|
|
||||||
result.links.push_back(fromLink());
|
|
||||||
result.links.push_back(peerOpenClickHandler(user));
|
|
||||||
result.text = lng_action_kick_user(lt_from, fromLinkText(), lt_user, textcmdLink(2, user->name));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto prepareChatEditPhoto = [this](const MTPDmessageActionChatEditPhoto &action) {
|
|
||||||
auto result = PreparedText {};
|
|
||||||
if (isPost()) {
|
|
||||||
result.text = lang(lng_action_changed_photo_channel);
|
|
||||||
} else {
|
|
||||||
result.links.push_back(fromLink());
|
|
||||||
result.text = lng_action_changed_photo(lt_from, fromLinkText());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto prepareChatEditTitle = [this](const MTPDmessageActionChatEditTitle &action) {
|
|
||||||
auto result = PreparedText {};
|
|
||||||
if (isPost()) {
|
|
||||||
result.text = lng_action_changed_title_channel(lt_title, textClean(qs(action.vtitle)));
|
|
||||||
} else {
|
|
||||||
result.links.push_back(fromLink());
|
|
||||||
result.text = lng_action_changed_title(lt_from, fromLinkText(), lt_title, textClean(qs(action.vtitle)));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto messageText = PreparedText {};
|
|
||||||
|
|
||||||
switch (action.type()) {
|
|
||||||
case mtpc_messageActionChatAddUser: messageText = prepareChatAddUserText(action.c_messageActionChatAddUser()); break;
|
|
||||||
case mtpc_messageActionChatJoinedByLink: messageText = prepareChatJoinedByLink(action.c_messageActionChatJoinedByLink()); break;
|
|
||||||
case mtpc_messageActionChatCreate: messageText = prepareChatCreate(action.c_messageActionChatCreate()); break;
|
|
||||||
case mtpc_messageActionChannelCreate: messageText = prepareChannelCreate(action.c_messageActionChannelCreate()); break;
|
|
||||||
case mtpc_messageActionHistoryClear: break; // Leave empty text.
|
|
||||||
case mtpc_messageActionChatDeletePhoto: messageText = prepareChatDeletePhoto(); break;
|
|
||||||
case mtpc_messageActionChatDeleteUser: messageText = prepareChatDeleteUser(action.c_messageActionChatDeleteUser()); break;
|
|
||||||
case mtpc_messageActionChatEditPhoto: messageText = prepareChatEditPhoto(action.c_messageActionChatEditPhoto()); break;
|
|
||||||
case mtpc_messageActionChatEditTitle: messageText = prepareChatEditTitle(action.c_messageActionChatEditTitle()); break;
|
|
||||||
case mtpc_messageActionChatMigrateTo: messageText.text = lang(lng_action_group_migrate); break;
|
|
||||||
case mtpc_messageActionChannelMigrateFrom: messageText.text = lang(lng_action_group_migrate); break;
|
|
||||||
case mtpc_messageActionPinMessage: messageText = preparePinnedText(); break;
|
|
||||||
case mtpc_messageActionGameScore: messageText = prepareGameScoreText(); break;
|
|
||||||
case mtpc_messageActionPhoneCall: Unexpected("PhoneCall type in HistoryService.");
|
|
||||||
case mtpc_messageActionPaymentSent: messageText = preparePaymentSentText(); break;
|
|
||||||
default: messageText.text = lang(lng_message_empty); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
setServiceText(messageText);
|
|
||||||
|
|
||||||
// Additional information.
|
|
||||||
switch (action.type()) {
|
|
||||||
case mtpc_messageActionChatAddUser: {
|
|
||||||
if (auto channel = history()->peer->asMegagroup()) {
|
|
||||||
auto &users = action.c_messageActionChatAddUser().vusers;
|
|
||||||
for_const (auto &item, users.v) {
|
|
||||||
if (item.v == AuthSession::CurrentUserId()) {
|
|
||||||
channel->mgInfo->joinedMessageFound = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case mtpc_messageActionChatJoinedByLink: {
|
|
||||||
if (_from->isSelf() && history()->peer->isMegagroup()) {
|
|
||||||
history()->peer->asChannel()->mgInfo->joinedMessageFound = true;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case mtpc_messageActionChatEditPhoto: {
|
|
||||||
auto &photo = action.c_messageActionChatEditPhoto().vphoto;
|
|
||||||
if (photo.type() == mtpc_photo) {
|
|
||||||
_media = std::make_unique<HistoryPhoto>(this, history()->peer, photo.c_photo(), st::msgServicePhotoWidth);
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case mtpc_messageActionChatMigrateTo:
|
|
||||||
case mtpc_messageActionChannelMigrateFrom: {
|
|
||||||
_flags |= MTPDmessage_ClientFlag::f_is_group_migrate;
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HistoryService::updateDependent(bool force) {
|
|
||||||
auto dependent = GetDependentData();
|
|
||||||
t_assert(dependent != nullptr);
|
|
||||||
|
|
||||||
if (!force) {
|
|
||||||
if (!dependent->msgId || dependent->msg) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dependent->lnk) {
|
|
||||||
dependent->lnk = goToMessageClickHandler(history()->peer, dependent->msgId);
|
|
||||||
}
|
|
||||||
bool gotDependencyItem = false;
|
|
||||||
if (!dependent->msg) {
|
|
||||||
dependent->msg = App::histItemById(channelId(), dependent->msgId);
|
|
||||||
if (dependent->msg) {
|
|
||||||
App::historyRegDependency(this, dependent->msg);
|
|
||||||
gotDependencyItem = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dependent->msg) {
|
|
||||||
updateDependentText();
|
|
||||||
} else if (force) {
|
|
||||||
if (dependent->msgId > 0) {
|
|
||||||
dependent->msgId = 0;
|
|
||||||
gotDependencyItem = true;
|
|
||||||
}
|
|
||||||
updateDependentText();
|
|
||||||
}
|
|
||||||
if (force && gotDependencyItem) {
|
|
||||||
AuthSession::Current().notifications().checkDelayed();
|
|
||||||
}
|
|
||||||
return (dependent->msg || !dependent->msgId);
|
|
||||||
}
|
|
||||||
|
|
||||||
HistoryService::PreparedText HistoryService::preparePinnedText() {
|
|
||||||
auto result = PreparedText {};
|
|
||||||
auto pinned = Get<HistoryServicePinned>();
|
|
||||||
if (pinned && pinned->msg) {
|
|
||||||
auto mediaText = ([pinned]() -> QString {
|
|
||||||
auto media = pinned->msg->getMedia();
|
|
||||||
switch (media ? media->type() : MediaTypeCount) {
|
|
||||||
case MediaTypePhoto: return lang(lng_action_pinned_media_photo);
|
|
||||||
case MediaTypeVideo: return lang(lng_action_pinned_media_video);
|
|
||||||
case MediaTypeContact: return lang(lng_action_pinned_media_contact);
|
|
||||||
case MediaTypeFile: return lang(lng_action_pinned_media_file);
|
|
||||||
case MediaTypeGif: {
|
|
||||||
if (auto document = media->getDocument()) {
|
|
||||||
if (document->isRoundVideo()) {
|
|
||||||
return lang(lng_action_pinned_media_video_message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lang(lng_action_pinned_media_gif);
|
|
||||||
} break;
|
|
||||||
case MediaTypeSticker: {
|
|
||||||
auto emoji = static_cast<HistorySticker*>(media)->emoji();
|
|
||||||
if (emoji.isEmpty()) {
|
|
||||||
return lang(lng_action_pinned_media_sticker);
|
|
||||||
}
|
|
||||||
return lng_action_pinned_media_emoji_sticker(lt_emoji, emoji);
|
|
||||||
} break;
|
|
||||||
case MediaTypeLocation: return lang(lng_action_pinned_media_location);
|
|
||||||
case MediaTypeMusicFile: return lang(lng_action_pinned_media_audio);
|
|
||||||
case MediaTypeVoiceFile: return lang(lng_action_pinned_media_voice);
|
|
||||||
case MediaTypeGame: {
|
|
||||||
auto title = static_cast<HistoryGame*>(media)->game()->title;
|
|
||||||
return lng_action_pinned_media_game(lt_game, title);
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
return QString();
|
|
||||||
})();
|
|
||||||
|
|
||||||
result.links.push_back(fromLink());
|
|
||||||
result.links.push_back(pinned->lnk);
|
|
||||||
if (mediaText.isEmpty()) {
|
|
||||||
auto original = pinned->msg->originalText().text;
|
|
||||||
auto cutAt = 0;
|
|
||||||
auto limit = kPinnedMessageTextLimit;
|
|
||||||
auto size = original.size();
|
|
||||||
for (; limit != 0;) {
|
|
||||||
--limit;
|
|
||||||
if (cutAt >= size) break;
|
|
||||||
if (original.at(cutAt).isLowSurrogate() && cutAt + 1 < size && original.at(cutAt + 1).isHighSurrogate()) {
|
|
||||||
cutAt += 2;
|
|
||||||
} else {
|
|
||||||
++cutAt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!limit && cutAt + 5 < size) {
|
|
||||||
original = original.mid(0, cutAt) + qstr("...");
|
|
||||||
}
|
|
||||||
result.text = lng_action_pinned_message(lt_from, fromLinkText(), lt_text, textcmdLink(2, original));
|
|
||||||
} else {
|
|
||||||
result.text = lng_action_pinned_media(lt_from, fromLinkText(), lt_media, textcmdLink(2, mediaText));
|
|
||||||
}
|
|
||||||
} else if (pinned && pinned->msgId) {
|
|
||||||
result.links.push_back(fromLink());
|
|
||||||
result.links.push_back(pinned->lnk);
|
|
||||||
result.text = lng_action_pinned_media(lt_from, fromLinkText(), lt_media, textcmdLink(2, lang(lng_contacts_loading)));
|
|
||||||
} else {
|
|
||||||
result.links.push_back(fromLink());
|
|
||||||
result.text = lng_action_pinned_media(lt_from, fromLinkText(), lt_media, lang(lng_deleted_message));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
HistoryService::PreparedText HistoryService::prepareGameScoreText() {
|
|
||||||
auto result = PreparedText {};
|
|
||||||
auto gamescore = Get<HistoryServiceGameScore>();
|
|
||||||
|
|
||||||
auto computeGameTitle = [gamescore, &result]() -> QString {
|
|
||||||
if (gamescore && gamescore->msg) {
|
|
||||||
if (auto media = gamescore->msg->getMedia()) {
|
|
||||||
if (media->type() == MediaTypeGame) {
|
|
||||||
result.links.push_back(MakeShared<ReplyMarkupClickHandler>(gamescore->msg, 0, 0));
|
|
||||||
auto titleText = static_cast<HistoryGame*>(media)->game()->title;
|
|
||||||
return textcmdLink(result.links.size(), titleText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lang(lng_deleted_message);
|
|
||||||
} else if (gamescore && gamescore->msgId) {
|
|
||||||
return lang(lng_contacts_loading);
|
|
||||||
}
|
|
||||||
return QString();
|
|
||||||
};
|
|
||||||
|
|
||||||
auto scoreNumber = gamescore ? gamescore->score : 0;
|
|
||||||
if (_from->isSelf()) {
|
|
||||||
auto gameTitle = computeGameTitle();
|
|
||||||
if (gameTitle.isEmpty()) {
|
|
||||||
result.text = lng_action_game_you_scored_no_game(lt_count, scoreNumber);
|
|
||||||
} else {
|
|
||||||
result.text = lng_action_game_you_scored(lt_count, scoreNumber, lt_game, gameTitle);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result.links.push_back(fromLink());
|
|
||||||
auto gameTitle = computeGameTitle();
|
|
||||||
if (gameTitle.isEmpty()) {
|
|
||||||
result.text = lng_action_game_score_no_game(lt_count, scoreNumber, lt_from, fromLinkText());
|
|
||||||
} else {
|
|
||||||
result.text = lng_action_game_score(lt_count, scoreNumber, lt_from, fromLinkText(), lt_game, gameTitle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
HistoryService::PreparedText HistoryService::preparePaymentSentText() {
|
|
||||||
auto result = PreparedText {};
|
|
||||||
auto payment = Get<HistoryServicePayment>();
|
|
||||||
|
|
||||||
auto invoiceTitle = ([payment]() -> QString {
|
|
||||||
if (payment && payment->msg) {
|
|
||||||
if (auto media = payment->msg->getMedia()) {
|
|
||||||
if (media->type() == MediaTypeInvoice) {
|
|
||||||
return static_cast<HistoryInvoice*>(media)->getTitle();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lang(lng_deleted_message);
|
|
||||||
} else if (payment && payment->msgId) {
|
|
||||||
return lang(lng_contacts_loading);
|
|
||||||
}
|
|
||||||
return QString();
|
|
||||||
})();
|
|
||||||
|
|
||||||
if (invoiceTitle.isEmpty()) {
|
|
||||||
result.text = lng_action_payment_done(lt_amount, payment->amount, lt_user, history()->peer->name);
|
|
||||||
} else {
|
|
||||||
result.text = lng_action_payment_done_for(lt_amount, payment->amount, lt_user, history()->peer->name, lt_invoice, invoiceTitle);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
HistoryService::HistoryService(gsl::not_null<History*> history, const MTPDmessageService &message) :
|
|
||||||
HistoryItem(history, message.vid.v, mtpCastFlags(message.vflags.v), ::date(message.vdate), message.has_from_id() ? message.vfrom_id.v : 0) {
|
|
||||||
createFromMtp(message);
|
|
||||||
setMessageByAction(message.vaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
HistoryService::HistoryService(gsl::not_null<History*> history, MsgId msgId, QDateTime date, const PreparedText &message, MTPDmessage::Flags flags, int32 from, PhotoData *photo) :
|
|
||||||
HistoryItem(history, msgId, flags, date, from) {
|
|
||||||
setServiceText(message);
|
|
||||||
if (photo) {
|
|
||||||
_media = std::make_unique<HistoryPhoto>(this, history->peer, photo, st::msgServicePhotoWidth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryService::initDimensions() {
|
|
||||||
_maxw = _text.maxWidth() + st::msgServicePadding.left() + st::msgServicePadding.right();
|
|
||||||
_minh = _text.minHeight();
|
|
||||||
if (_media) _media->initDimensions();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HistoryService::updateDependencyItem() {
|
|
||||||
if (GetDependentData()) {
|
|
||||||
return updateDependent(true);
|
|
||||||
}
|
|
||||||
return HistoryItem::updateDependencyItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
QRect HistoryService::countGeometry() const {
|
|
||||||
auto result = QRect(0, 0, width(), _height);
|
|
||||||
if (Adaptive::ChatWide()) {
|
|
||||||
result.setWidth(qMin(result.width(), st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
|
|
||||||
}
|
|
||||||
return result.marginsRemoved(st::msgServiceMargin);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextWithEntities HistoryService::selectedText(TextSelection selection) const {
|
|
||||||
return _text.originalTextWithEntities((selection == FullSelection) ? AllTextSelection : selection);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString HistoryService::inDialogsText() const {
|
|
||||||
return textcmdLink(1, textClean(notificationText()));
|
|
||||||
}
|
|
||||||
|
|
||||||
QString HistoryService::inReplyText() const {
|
|
||||||
QString result = HistoryService::notificationText();
|
|
||||||
return result.trimmed().startsWith(author()->name) ? result.trimmed().mid(author()->name.size()).trimmed() : result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryService::setServiceText(const PreparedText &prepared) {
|
|
||||||
_text.setText(st::serviceTextStyle, prepared.text, _historySrvOptions);
|
|
||||||
auto linkIndex = 0;
|
|
||||||
for_const (auto &link, prepared.links) {
|
|
||||||
// Link indices start with 1.
|
|
||||||
_text.setLink(++linkIndex, link);
|
|
||||||
}
|
|
||||||
|
|
||||||
setPendingInitDimensions();
|
|
||||||
_textWidth = -1;
|
|
||||||
_textHeight = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryService::draw(Painter &p, QRect clip, TextSelection selection, TimeMs ms) const {
|
|
||||||
auto height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom();
|
|
||||||
auto dateh = 0;
|
|
||||||
auto unreadbarh = 0;
|
|
||||||
if (auto date = Get<HistoryMessageDate>()) {
|
|
||||||
dateh = date->height();
|
|
||||||
p.translate(0, dateh);
|
|
||||||
clip.translate(0, -dateh);
|
|
||||||
height -= dateh;
|
|
||||||
}
|
|
||||||
if (auto unreadbar = Get<HistoryMessageUnreadBar>()) {
|
|
||||||
unreadbarh = unreadbar->height();
|
|
||||||
if (clip.intersects(QRect(0, 0, width(), unreadbarh))) {
|
|
||||||
unreadbar->paint(p, 0, width());
|
|
||||||
}
|
|
||||||
p.translate(0, unreadbarh);
|
|
||||||
clip.translate(0, -unreadbarh);
|
|
||||||
height -= unreadbarh;
|
|
||||||
}
|
|
||||||
|
|
||||||
HistoryLayout::PaintContext context(ms, clip, selection);
|
|
||||||
HistoryLayout::ServiceMessagePainter::paint(p, this, context, height);
|
|
||||||
|
|
||||||
if (auto skiph = dateh + unreadbarh) {
|
|
||||||
p.translate(0, -skiph);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int HistoryService::resizeContentGetHeight() {
|
|
||||||
_height = displayedDateHeight();
|
|
||||||
if (auto unreadbar = Get<HistoryMessageUnreadBar>()) {
|
|
||||||
_height += unreadbar->height();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_text.isEmpty()) {
|
|
||||||
_textHeight = 0;
|
|
||||||
} else {
|
|
||||||
auto contentWidth = width();
|
|
||||||
if (Adaptive::ChatWide()) {
|
|
||||||
accumulate_min(contentWidth, st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left());
|
|
||||||
}
|
|
||||||
contentWidth -= st::msgServiceMargin.left() + st::msgServiceMargin.left(); // two small margins
|
|
||||||
if (contentWidth < st::msgServicePadding.left() + st::msgServicePadding.right() + 1) {
|
|
||||||
contentWidth = st::msgServicePadding.left() + st::msgServicePadding.right() + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto nwidth = qMax(contentWidth - st::msgServicePadding.left() - st::msgServicePadding.right(), 0);
|
|
||||||
if (nwidth != _textWidth) {
|
|
||||||
_textWidth = nwidth;
|
|
||||||
_textHeight = _text.countHeight(nwidth);
|
|
||||||
}
|
|
||||||
if (contentWidth >= _maxw) {
|
|
||||||
_height += _minh;
|
|
||||||
} else {
|
|
||||||
_height += _textHeight;
|
|
||||||
}
|
|
||||||
_height += st::msgServicePadding.top() + st::msgServicePadding.bottom() + st::msgServiceMargin.top() + st::msgServiceMargin.bottom();
|
|
||||||
if (_media) {
|
|
||||||
_height += st::msgServiceMargin.top() + _media->resizeGetHeight(_media->currentWidth());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return _height;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HistoryService::hasPoint(QPoint point) const {
|
|
||||||
auto g = countGeometry();
|
|
||||||
if (g.width() < 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto dateh = displayedDateHeight()) {
|
|
||||||
g.setTop(g.top() + dateh);
|
|
||||||
}
|
|
||||||
if (auto unreadbar = Get<HistoryMessageUnreadBar>()) {
|
|
||||||
g.setTop(g.top() + unreadbar->height());
|
|
||||||
}
|
|
||||||
if (_media) {
|
|
||||||
g.setHeight(g.height() - (st::msgServiceMargin.top() + _media->height()));
|
|
||||||
}
|
|
||||||
return g.contains(point);
|
|
||||||
}
|
|
||||||
|
|
||||||
HistoryTextState HistoryService::getState(QPoint point, HistoryStateRequest request) const {
|
|
||||||
HistoryTextState result;
|
|
||||||
|
|
||||||
auto g = countGeometry();
|
|
||||||
if (g.width() < 1) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto dateh = displayedDateHeight()) {
|
|
||||||
point.setY(point.y() - dateh);
|
|
||||||
g.setHeight(g.height() - dateh);
|
|
||||||
}
|
|
||||||
if (auto unreadbar = Get<HistoryMessageUnreadBar>()) {
|
|
||||||
auto unreadbarh = unreadbar->height();
|
|
||||||
point.setY(point.y() - unreadbarh);
|
|
||||||
g.setHeight(g.height() - unreadbarh);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_media) {
|
|
||||||
g.setHeight(g.height() - (st::msgServiceMargin.top() + _media->height()));
|
|
||||||
}
|
|
||||||
auto trect = g.marginsAdded(-st::msgServicePadding);
|
|
||||||
if (trect.contains(point)) {
|
|
||||||
auto textRequest = request.forText();
|
|
||||||
textRequest.align = style::al_center;
|
|
||||||
result = _text.getState(point - trect.topLeft(), trect.width(), textRequest);
|
|
||||||
if (auto gamescore = Get<HistoryServiceGameScore>()) {
|
|
||||||
if (!result.link && result.cursor == HistoryInTextCursorState && g.contains(point)) {
|
|
||||||
result.link = gamescore->lnk;
|
|
||||||
}
|
|
||||||
} else if (auto payment = Get<HistoryServicePayment>()) {
|
|
||||||
if (!result.link && result.cursor == HistoryInTextCursorState && g.contains(point)) {
|
|
||||||
result.link = payment->lnk;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (_media) {
|
|
||||||
result = _media->getState(point - QPoint(st::msgServiceMargin.left() + (g.width() - _media->maxWidth()) / 2, st::msgServiceMargin.top() + g.height() + st::msgServiceMargin.top()), request);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryService::createFromMtp(const MTPDmessageService &message) {
|
|
||||||
if (message.vaction.type() == mtpc_messageActionGameScore) {
|
|
||||||
UpdateComponents(HistoryServiceGameScore::Bit());
|
|
||||||
Get<HistoryServiceGameScore>()->score = message.vaction.c_messageActionGameScore().vscore.v;
|
|
||||||
} else if (message.vaction.type() == mtpc_messageActionPaymentSent) {
|
|
||||||
UpdateComponents(HistoryServicePayment::Bit());
|
|
||||||
auto amount = message.vaction.c_messageActionPaymentSent().vtotal_amount.v;
|
|
||||||
auto currency = qs(message.vaction.c_messageActionPaymentSent().vcurrency);
|
|
||||||
Get<HistoryServicePayment>()->amount = HistoryInvoice::fillAmountAndCurrency(amount, currency);
|
|
||||||
}
|
|
||||||
if (message.has_reply_to_msg_id()) {
|
|
||||||
if (message.vaction.type() == mtpc_messageActionPinMessage) {
|
|
||||||
UpdateComponents(HistoryServicePinned::Bit());
|
|
||||||
}
|
|
||||||
if (auto dependent = GetDependentData()) {
|
|
||||||
dependent->msgId = message.vreply_to_msg_id.v;
|
|
||||||
if (!updateDependent() && App::api()) {
|
|
||||||
App::api()->requestMessageData(history()->peer->asChannel(), dependent->msgId, historyDependentItemCallback(fullId()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setMessageByAction(message.vaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryService::applyEdition(const MTPDmessageService &message) {
|
|
||||||
clearDependency();
|
|
||||||
UpdateComponents(0);
|
|
||||||
|
|
||||||
createFromMtp(message);
|
|
||||||
|
|
||||||
if (message.vaction.type() == mtpc_messageActionHistoryClear) {
|
|
||||||
removeMedia();
|
|
||||||
finishEditionToEmpty();
|
|
||||||
} else {
|
|
||||||
finishEdition(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryService::removeMedia() {
|
|
||||||
if (!_media) return;
|
|
||||||
|
|
||||||
bool mediaWasDisplayed = _media->isDisplayed();
|
|
||||||
_media.reset();
|
|
||||||
if (mediaWasDisplayed) {
|
|
||||||
_textWidth = -1;
|
|
||||||
_textHeight = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 HistoryService::addToOverview(AddToOverviewMethod method) {
|
|
||||||
if (!indexInOverview()) return 0;
|
|
||||||
|
|
||||||
int32 result = 0;
|
|
||||||
if (auto media = getMedia()) {
|
|
||||||
result |= media->addToOverview(method);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryService::eraseFromOverview() {
|
|
||||||
if (auto media = getMedia()) {
|
|
||||||
media->eraseFromOverview();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryService::updateDependentText() {
|
|
||||||
auto text = PreparedText {};
|
|
||||||
if (Has<HistoryServicePinned>()) {
|
|
||||||
text = preparePinnedText();
|
|
||||||
} else if (Has<HistoryServiceGameScore>()) {
|
|
||||||
text = prepareGameScoreText();
|
|
||||||
} else if (Has<HistoryServicePayment>()) {
|
|
||||||
text = preparePaymentSentText();
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setServiceText(text);
|
|
||||||
if (history()->textCachedFor == this) {
|
|
||||||
history()->textCachedFor = nullptr;
|
|
||||||
}
|
|
||||||
if (App::main()) {
|
|
||||||
App::main()->dlgUpdated(history()->peer, id);
|
|
||||||
}
|
|
||||||
App::historyUpdateDependent(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryService::clearDependency() {
|
|
||||||
if (auto dependent = GetDependentData()) {
|
|
||||||
if (dependent->msg) {
|
|
||||||
App::historyUnregDependency(this, dependent->msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HistoryService::~HistoryService() {
|
|
||||||
clearDependency();
|
|
||||||
_media.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
HistoryJoined::HistoryJoined(gsl::not_null<History*> history, const QDateTime &inviteDate, gsl::not_null<UserData*> inviter, MTPDmessage::Flags flags)
|
|
||||||
: HistoryService(history, clientMsgId(), inviteDate, GenerateText(history, inviter), flags) {
|
|
||||||
}
|
|
||||||
|
|
||||||
HistoryJoined::PreparedText HistoryJoined::GenerateText(gsl::not_null<History*> history, gsl::not_null<UserData*> inviter) {
|
|
||||||
if (inviter->id == AuthSession::CurrentUserPeerId()) {
|
|
||||||
return { lang(history->isMegagroup() ? lng_action_you_joined_group : lng_action_you_joined) };
|
|
||||||
}
|
|
||||||
auto result = PreparedText {};
|
|
||||||
result.links.push_back(peerOpenClickHandler(inviter));
|
|
||||||
if (history->isMegagroup()) {
|
|
||||||
result.text = lng_action_add_you_group(lt_from, textcmdLink(1, inviter->name));
|
|
||||||
}
|
|
||||||
result.text = lng_action_add_you(lt_from, textcmdLink(1, inviter->name));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
|
@ -20,7 +20,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
void historyInitMessages();
|
void HistoryInitMessages();
|
||||||
|
base::lambda<void(ChannelData*, MsgId)> HistoryDependentItemCallback(const FullMsgId &msgId);
|
||||||
|
MTPDmessage::Flags NewMessageFlags(gsl::not_null<PeerData*> peer);
|
||||||
|
|
||||||
class HistoryMessage : public HistoryItem, private HistoryItemInstantiated<HistoryMessage> {
|
class HistoryMessage : public HistoryItem, private HistoryItemInstantiated<HistoryMessage> {
|
||||||
public:
|
public:
|
||||||
|
@ -30,7 +32,7 @@ public:
|
||||||
static gsl::not_null<HistoryMessage*> create(gsl::not_null<History*> history, const MTPDmessageService &msg) {
|
static gsl::not_null<HistoryMessage*> create(gsl::not_null<History*> history, const MTPDmessageService &msg) {
|
||||||
return _create(history, msg);
|
return _create(history, msg);
|
||||||
}
|
}
|
||||||
static gsl::not_null<HistoryMessage*> create(gsl::not_null<History*> history, MsgId msgId, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *fwd) {
|
static gsl::not_null<HistoryMessage*> create(gsl::not_null<History*> history, MsgId msgId, MTPDmessage::Flags flags, QDateTime date, int32 from, gsl::not_null<HistoryMessage*> fwd) {
|
||||||
return _create(history, msgId, flags, date, from, fwd);
|
return _create(history, msgId, flags, date, from, fwd);
|
||||||
}
|
}
|
||||||
static gsl::not_null<HistoryMessage*> create(gsl::not_null<History*> history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, const TextWithEntities &textWithEntities) {
|
static gsl::not_null<HistoryMessage*> create(gsl::not_null<History*> history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, const TextWithEntities &textWithEntities) {
|
||||||
|
@ -64,9 +66,7 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool displayEditedBadge(bool hasViaBotOrInlineMarkup) const;
|
bool displayEditedBadge(bool hasViaBotOrInlineMarkup) const;
|
||||||
bool uploading() const {
|
bool uploading() const;
|
||||||
return _media && _media->uploading();
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawInfo(Painter &p, int32 right, int32 bottom, int32 width, bool selected, InfoDisplayType type) const override;
|
void drawInfo(Painter &p, int32 right, int32 bottom, int32 width, bool selected, InfoDisplayType type) const override;
|
||||||
void setViewsCount(int32 count) override;
|
void setViewsCount(int32 count) override;
|
||||||
|
@ -84,14 +84,8 @@ public:
|
||||||
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override;
|
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override;
|
||||||
|
|
||||||
// ClickHandlerHost interface
|
// ClickHandlerHost interface
|
||||||
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override {
|
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
||||||
if (_media) _media->clickHandlerActiveChanged(p, active);
|
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
|
||||||
HistoryItem::clickHandlerActiveChanged(p, active);
|
|
||||||
}
|
|
||||||
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override {
|
|
||||||
if (_media) _media->clickHandlerPressedChanged(p, pressed);
|
|
||||||
HistoryItem::clickHandlerPressedChanged(p, pressed);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString notificationHeader() const override;
|
QString notificationHeader() const override;
|
||||||
|
|
||||||
|
@ -149,7 +143,7 @@ public:
|
||||||
private:
|
private:
|
||||||
HistoryMessage(gsl::not_null<History*> history, const MTPDmessage &msg);
|
HistoryMessage(gsl::not_null<History*> history, const MTPDmessage &msg);
|
||||||
HistoryMessage(gsl::not_null<History*> history, const MTPDmessageService &msg);
|
HistoryMessage(gsl::not_null<History*> history, const MTPDmessageService &msg);
|
||||||
HistoryMessage(gsl::not_null<History*> history, MsgId msgId, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *fwd); // local forwarded
|
HistoryMessage(gsl::not_null<History*> history, MsgId msgId, MTPDmessage::Flags flags, QDateTime date, int32 from, gsl::not_null<HistoryMessage*> fwd); // local forwarded
|
||||||
HistoryMessage(gsl::not_null<History*> history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, const TextWithEntities &textWithEntities); // local message
|
HistoryMessage(gsl::not_null<History*> history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, const TextWithEntities &textWithEntities); // local message
|
||||||
HistoryMessage(gsl::not_null<History*> history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, DocumentData *doc, const QString &caption, const MTPReplyMarkup &markup); // local document
|
HistoryMessage(gsl::not_null<History*> history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, DocumentData *doc, const QString &caption, const MTPReplyMarkup &markup); // local document
|
||||||
HistoryMessage(gsl::not_null<History*> history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, PhotoData *photo, const QString &caption, const MTPReplyMarkup &markup); // local photo
|
HistoryMessage(gsl::not_null<History*> history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, PhotoData *photo, const QString &caption, const MTPReplyMarkup &markup); // local photo
|
||||||
|
@ -167,16 +161,7 @@ private:
|
||||||
int performResizeGetHeight();
|
int performResizeGetHeight();
|
||||||
void applyEditionToEmpty();
|
void applyEditionToEmpty();
|
||||||
|
|
||||||
bool displayForwardedFrom() const {
|
bool displayForwardedFrom() const;
|
||||||
if (auto forwarded = Get<HistoryMessageForwarded>()) {
|
|
||||||
return Has<HistoryMessageVia>()
|
|
||||||
|| !_media
|
|
||||||
|| !_media->isDisplayed()
|
|
||||||
|| !_media->hideForwardedFrom()
|
|
||||||
|| forwarded->_authorOriginal->isChannel();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void paintFromName(Painter &p, QRect &trect, bool selected) const;
|
void paintFromName(Painter &p, QRect &trect, bool selected) const;
|
||||||
void paintForwardedInfo(Painter &p, QRect &trect, bool selected) const;
|
void paintForwardedInfo(Painter &p, QRect &trect, bool selected) const;
|
||||||
void paintReplyInfo(Painter &p, QRect &trect, bool selected) const;
|
void paintReplyInfo(Painter &p, QRect &trect, bool selected) const;
|
||||||
|
@ -236,163 +221,3 @@ private:
|
||||||
void updateMediaInBubbleState();
|
void updateMediaInBubbleState();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline MTPDmessage::Flags newMessageFlags(PeerData *p) {
|
|
||||||
MTPDmessage::Flags result = 0;
|
|
||||||
if (!p->isSelf()) {
|
|
||||||
result |= MTPDmessage::Flag::f_out;
|
|
||||||
//if (p->isChat() || (p->isUser() && !p->asUser()->botInfo)) {
|
|
||||||
// result |= MTPDmessage::Flag::f_unread;
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct HistoryServiceDependentData {
|
|
||||||
MsgId msgId = 0;
|
|
||||||
HistoryItem *msg = nullptr;
|
|
||||||
ClickHandlerPtr lnk;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct HistoryServicePinned : public RuntimeComponent<HistoryServicePinned>, public HistoryServiceDependentData {
|
|
||||||
};
|
|
||||||
|
|
||||||
struct HistoryServiceGameScore : public RuntimeComponent<HistoryServiceGameScore>, public HistoryServiceDependentData {
|
|
||||||
int score = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct HistoryServicePayment : public RuntimeComponent<HistoryServicePayment>, public HistoryServiceDependentData {
|
|
||||||
QString amount;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace HistoryLayout {
|
|
||||||
class ServiceMessagePainter;
|
|
||||||
} // namespace HistoryLayout
|
|
||||||
|
|
||||||
class HistoryService : public HistoryItem, private HistoryItemInstantiated<HistoryService> {
|
|
||||||
public:
|
|
||||||
struct PreparedText {
|
|
||||||
QString text;
|
|
||||||
QList<ClickHandlerPtr> links;
|
|
||||||
};
|
|
||||||
|
|
||||||
static gsl::not_null<HistoryService*> create(gsl::not_null<History*> history, const MTPDmessageService &message) {
|
|
||||||
return _create(history, message);
|
|
||||||
}
|
|
||||||
static gsl::not_null<HistoryService*> create(gsl::not_null<History*> history, MsgId msgId, QDateTime date, const PreparedText &message, MTPDmessage::Flags flags = 0, UserId from = 0, PhotoData *photo = nullptr) {
|
|
||||||
return _create(history, msgId, date, message, flags, from, photo);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool updateDependencyItem() override;
|
|
||||||
MsgId dependencyMsgId() const override {
|
|
||||||
if (auto dependent = GetDependentData()) {
|
|
||||||
return dependent->msgId;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
bool notificationReady() const override {
|
|
||||||
if (auto dependent = GetDependentData()) {
|
|
||||||
return (dependent->msg || !dependent->msgId);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QRect countGeometry() const;
|
|
||||||
|
|
||||||
void draw(Painter &p, QRect clip, TextSelection selection, TimeMs ms) const override;
|
|
||||||
bool hasPoint(QPoint point) const override;
|
|
||||||
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override;
|
|
||||||
|
|
||||||
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override {
|
|
||||||
return _text.adjustSelection(selection, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override {
|
|
||||||
if (_media) _media->clickHandlerActiveChanged(p, active);
|
|
||||||
HistoryItem::clickHandlerActiveChanged(p, active);
|
|
||||||
}
|
|
||||||
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override {
|
|
||||||
if (_media) _media->clickHandlerPressedChanged(p, pressed);
|
|
||||||
HistoryItem::clickHandlerPressedChanged(p, pressed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void applyEdition(const MTPDmessageService &message) override;
|
|
||||||
|
|
||||||
int32 addToOverview(AddToOverviewMethod method) override;
|
|
||||||
void eraseFromOverview() override;
|
|
||||||
|
|
||||||
bool needCheck() const override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool serviceMsg() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
TextWithEntities selectedText(TextSelection selection) const override;
|
|
||||||
QString inDialogsText() const override;
|
|
||||||
QString inReplyText() const override;
|
|
||||||
|
|
||||||
~HistoryService();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
friend class HistoryLayout::ServiceMessagePainter;
|
|
||||||
|
|
||||||
HistoryService(gsl::not_null<History*> history, const MTPDmessageService &message);
|
|
||||||
HistoryService(gsl::not_null<History*> history, MsgId msgId, QDateTime date, const PreparedText &message, MTPDmessage::Flags flags = 0, UserId from = 0, PhotoData *photo = 0);
|
|
||||||
friend class HistoryItemInstantiated<HistoryService>;
|
|
||||||
|
|
||||||
void initDimensions() override;
|
|
||||||
int resizeContentGetHeight() override;
|
|
||||||
|
|
||||||
void setServiceText(const PreparedText &prepared);
|
|
||||||
|
|
||||||
QString fromLinkText() const {
|
|
||||||
return textcmdLink(1, _from->name);
|
|
||||||
};
|
|
||||||
ClickHandlerPtr fromLink() const {
|
|
||||||
return peerOpenClickHandler(_from);
|
|
||||||
};
|
|
||||||
|
|
||||||
void removeMedia();
|
|
||||||
|
|
||||||
private:
|
|
||||||
HistoryServiceDependentData *GetDependentData() {
|
|
||||||
if (auto pinned = Get<HistoryServicePinned>()) {
|
|
||||||
return pinned;
|
|
||||||
} else if (auto gamescore = Get<HistoryServiceGameScore>()) {
|
|
||||||
return gamescore;
|
|
||||||
} else if (auto payment = Get<HistoryServicePayment>()) {
|
|
||||||
return payment;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
const HistoryServiceDependentData *GetDependentData() const {
|
|
||||||
return const_cast<HistoryService*>(this)->GetDependentData();
|
|
||||||
}
|
|
||||||
bool updateDependent(bool force = false);
|
|
||||||
void updateDependentText();
|
|
||||||
void clearDependency();
|
|
||||||
|
|
||||||
void createFromMtp(const MTPDmessageService &message);
|
|
||||||
void setMessageByAction(const MTPmessageAction &action);
|
|
||||||
|
|
||||||
PreparedText preparePinnedText();
|
|
||||||
PreparedText prepareGameScoreText();
|
|
||||||
PreparedText preparePaymentSentText();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class HistoryJoined : public HistoryService, private HistoryItemInstantiated<HistoryJoined> {
|
|
||||||
public:
|
|
||||||
static gsl::not_null<HistoryJoined*> create(gsl::not_null<History*> history, const QDateTime &inviteDate, gsl::not_null<UserData*> inviter, MTPDmessage::Flags flags) {
|
|
||||||
return _create(history, inviteDate, inviter, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
HistoryJoined(gsl::not_null<History*> history, const QDateTime &inviteDate, gsl::not_null<UserData*> inviter, MTPDmessage::Flags flags);
|
|
||||||
using HistoryItemInstantiated<HistoryJoined>::_create;
|
|
||||||
friend class HistoryItemInstantiated<HistoryJoined>;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static PreparedText GenerateText(gsl::not_null<History*> history, gsl::not_null<UserData*> inviter);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
|
@ -0,0 +1,696 @@
|
||||||
|
/*
|
||||||
|
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-2017 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "history/history_service.h"
|
||||||
|
|
||||||
|
#include "lang/lang_keys.h"
|
||||||
|
#include "mainwidget.h"
|
||||||
|
#include "apiwrap.h"
|
||||||
|
#include "history/history_service_layout.h"
|
||||||
|
#include "history/history_media_types.h"
|
||||||
|
#include "history/history_message.h"
|
||||||
|
#include "auth_session.h"
|
||||||
|
#include "window/notifications_manager.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kPinnedMessageTextLimit = 16;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TextParseOptions _historySrvOptions = {
|
||||||
|
TextParseLinks | TextParseMentions | TextParseHashtags/* | TextParseMultiline*/ | TextParseRichText, // flags
|
||||||
|
0, // maxw
|
||||||
|
0, // maxh
|
||||||
|
Qt::LayoutDirectionAuto, // lang-dependent
|
||||||
|
};
|
||||||
|
|
||||||
|
void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||||
|
auto prepareChatAddUserText = [this](const MTPDmessageActionChatAddUser &action) {
|
||||||
|
auto result = PreparedText {};
|
||||||
|
auto &users = action.vusers.v;
|
||||||
|
if (users.size() == 1) {
|
||||||
|
auto u = App::user(peerFromUser(users[0]));
|
||||||
|
if (u == _from) {
|
||||||
|
result.links.push_back(fromLink());
|
||||||
|
result.text = lng_action_user_joined(lt_from, fromLinkText());
|
||||||
|
} else {
|
||||||
|
result.links.push_back(fromLink());
|
||||||
|
result.links.push_back(peerOpenClickHandler(u));
|
||||||
|
result.text = lng_action_add_user(lt_from, fromLinkText(), lt_user, textcmdLink(2, u->name));
|
||||||
|
}
|
||||||
|
} else if (users.isEmpty()) {
|
||||||
|
result.links.push_back(fromLink());
|
||||||
|
result.text = lng_action_add_user(lt_from, fromLinkText(), lt_user, "somebody");
|
||||||
|
} else {
|
||||||
|
result.links.push_back(fromLink());
|
||||||
|
for (auto i = 0, l = users.size(); i != l; ++i) {
|
||||||
|
auto user = App::user(peerFromUser(users[i]));
|
||||||
|
result.links.push_back(peerOpenClickHandler(user));
|
||||||
|
|
||||||
|
auto linkText = textcmdLink(i + 2, user->name);
|
||||||
|
if (i == 0) {
|
||||||
|
result.text = linkText;
|
||||||
|
} else if (i + 1 == l) {
|
||||||
|
result.text = lng_action_add_users_and_last(lt_accumulated, result.text, lt_user, linkText);
|
||||||
|
} else {
|
||||||
|
result.text = lng_action_add_users_and_one(lt_accumulated, result.text, lt_user, linkText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.text = lng_action_add_users_many(lt_from, fromLinkText(), lt_users, result.text);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto prepareChatJoinedByLink = [this](const MTPDmessageActionChatJoinedByLink &action) {
|
||||||
|
auto result = PreparedText {};
|
||||||
|
result.links.push_back(fromLink());
|
||||||
|
result.text = lng_action_user_joined_by_link(lt_from, fromLinkText());
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto prepareChatCreate = [this](const MTPDmessageActionChatCreate &action) {
|
||||||
|
auto result = PreparedText {};
|
||||||
|
result.links.push_back(fromLink());
|
||||||
|
result.text = lng_action_created_chat(lt_from, fromLinkText(), lt_title, textClean(qs(action.vtitle)));
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto prepareChannelCreate = [this](const MTPDmessageActionChannelCreate &action) {
|
||||||
|
auto result = PreparedText {};
|
||||||
|
if (isPost()) {
|
||||||
|
result.text = lang(lng_action_created_channel);
|
||||||
|
} else {
|
||||||
|
result.links.push_back(fromLink());
|
||||||
|
result.text = lng_action_created_chat(lt_from, fromLinkText(), lt_title, textClean(qs(action.vtitle)));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto prepareChatDeletePhoto = [this] {
|
||||||
|
auto result = PreparedText {};
|
||||||
|
if (isPost()) {
|
||||||
|
result.text = lang(lng_action_removed_photo_channel);
|
||||||
|
} else {
|
||||||
|
result.links.push_back(fromLink());
|
||||||
|
result.text = lng_action_removed_photo(lt_from, fromLinkText());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto prepareChatDeleteUser = [this](const MTPDmessageActionChatDeleteUser &action) {
|
||||||
|
auto result = PreparedText {};
|
||||||
|
if (peerFromUser(action.vuser_id) == _from->id) {
|
||||||
|
result.links.push_back(fromLink());
|
||||||
|
result.text = lng_action_user_left(lt_from, fromLinkText());
|
||||||
|
} else {
|
||||||
|
auto user = App::user(peerFromUser(action.vuser_id));
|
||||||
|
result.links.push_back(fromLink());
|
||||||
|
result.links.push_back(peerOpenClickHandler(user));
|
||||||
|
result.text = lng_action_kick_user(lt_from, fromLinkText(), lt_user, textcmdLink(2, user->name));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto prepareChatEditPhoto = [this](const MTPDmessageActionChatEditPhoto &action) {
|
||||||
|
auto result = PreparedText {};
|
||||||
|
if (isPost()) {
|
||||||
|
result.text = lang(lng_action_changed_photo_channel);
|
||||||
|
} else {
|
||||||
|
result.links.push_back(fromLink());
|
||||||
|
result.text = lng_action_changed_photo(lt_from, fromLinkText());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto prepareChatEditTitle = [this](const MTPDmessageActionChatEditTitle &action) {
|
||||||
|
auto result = PreparedText {};
|
||||||
|
if (isPost()) {
|
||||||
|
result.text = lng_action_changed_title_channel(lt_title, textClean(qs(action.vtitle)));
|
||||||
|
} else {
|
||||||
|
result.links.push_back(fromLink());
|
||||||
|
result.text = lng_action_changed_title(lt_from, fromLinkText(), lt_title, textClean(qs(action.vtitle)));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto messageText = PreparedText {};
|
||||||
|
|
||||||
|
switch (action.type()) {
|
||||||
|
case mtpc_messageActionChatAddUser: messageText = prepareChatAddUserText(action.c_messageActionChatAddUser()); break;
|
||||||
|
case mtpc_messageActionChatJoinedByLink: messageText = prepareChatJoinedByLink(action.c_messageActionChatJoinedByLink()); break;
|
||||||
|
case mtpc_messageActionChatCreate: messageText = prepareChatCreate(action.c_messageActionChatCreate()); break;
|
||||||
|
case mtpc_messageActionChannelCreate: messageText = prepareChannelCreate(action.c_messageActionChannelCreate()); break;
|
||||||
|
case mtpc_messageActionHistoryClear: break; // Leave empty text.
|
||||||
|
case mtpc_messageActionChatDeletePhoto: messageText = prepareChatDeletePhoto(); break;
|
||||||
|
case mtpc_messageActionChatDeleteUser: messageText = prepareChatDeleteUser(action.c_messageActionChatDeleteUser()); break;
|
||||||
|
case mtpc_messageActionChatEditPhoto: messageText = prepareChatEditPhoto(action.c_messageActionChatEditPhoto()); break;
|
||||||
|
case mtpc_messageActionChatEditTitle: messageText = prepareChatEditTitle(action.c_messageActionChatEditTitle()); break;
|
||||||
|
case mtpc_messageActionChatMigrateTo: messageText.text = lang(lng_action_group_migrate); break;
|
||||||
|
case mtpc_messageActionChannelMigrateFrom: messageText.text = lang(lng_action_group_migrate); break;
|
||||||
|
case mtpc_messageActionPinMessage: messageText = preparePinnedText(); break;
|
||||||
|
case mtpc_messageActionGameScore: messageText = prepareGameScoreText(); break;
|
||||||
|
case mtpc_messageActionPhoneCall: Unexpected("PhoneCall type in HistoryService.");
|
||||||
|
case mtpc_messageActionPaymentSent: messageText = preparePaymentSentText(); break;
|
||||||
|
default: messageText.text = lang(lng_message_empty); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
setServiceText(messageText);
|
||||||
|
|
||||||
|
// Additional information.
|
||||||
|
switch (action.type()) {
|
||||||
|
case mtpc_messageActionChatAddUser: {
|
||||||
|
if (auto channel = history()->peer->asMegagroup()) {
|
||||||
|
auto &users = action.c_messageActionChatAddUser().vusers;
|
||||||
|
for_const (auto &item, users.v) {
|
||||||
|
if (item.v == AuthSession::CurrentUserId()) {
|
||||||
|
channel->mgInfo->joinedMessageFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case mtpc_messageActionChatJoinedByLink: {
|
||||||
|
if (_from->isSelf() && history()->peer->isMegagroup()) {
|
||||||
|
history()->peer->asChannel()->mgInfo->joinedMessageFound = true;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case mtpc_messageActionChatEditPhoto: {
|
||||||
|
auto &photo = action.c_messageActionChatEditPhoto().vphoto;
|
||||||
|
if (photo.type() == mtpc_photo) {
|
||||||
|
_media = std::make_unique<HistoryPhoto>(this, history()->peer, photo.c_photo(), st::msgServicePhotoWidth);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case mtpc_messageActionChatMigrateTo:
|
||||||
|
case mtpc_messageActionChannelMigrateFrom: {
|
||||||
|
_flags |= MTPDmessage_ClientFlag::f_is_group_migrate;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HistoryService::updateDependent(bool force) {
|
||||||
|
auto dependent = GetDependentData();
|
||||||
|
t_assert(dependent != nullptr);
|
||||||
|
|
||||||
|
if (!force) {
|
||||||
|
if (!dependent->msgId || dependent->msg) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dependent->lnk) {
|
||||||
|
dependent->lnk = goToMessageClickHandler(history()->peer, dependent->msgId);
|
||||||
|
}
|
||||||
|
bool gotDependencyItem = false;
|
||||||
|
if (!dependent->msg) {
|
||||||
|
dependent->msg = App::histItemById(channelId(), dependent->msgId);
|
||||||
|
if (dependent->msg) {
|
||||||
|
App::historyRegDependency(this, dependent->msg);
|
||||||
|
gotDependencyItem = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dependent->msg) {
|
||||||
|
updateDependentText();
|
||||||
|
} else if (force) {
|
||||||
|
if (dependent->msgId > 0) {
|
||||||
|
dependent->msgId = 0;
|
||||||
|
gotDependencyItem = true;
|
||||||
|
}
|
||||||
|
updateDependentText();
|
||||||
|
}
|
||||||
|
if (force && gotDependencyItem) {
|
||||||
|
AuthSession::Current().notifications().checkDelayed();
|
||||||
|
}
|
||||||
|
return (dependent->msg || !dependent->msgId);
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryService::PreparedText HistoryService::preparePinnedText() {
|
||||||
|
auto result = PreparedText {};
|
||||||
|
auto pinned = Get<HistoryServicePinned>();
|
||||||
|
if (pinned && pinned->msg) {
|
||||||
|
auto mediaText = ([pinned]() -> QString {
|
||||||
|
auto media = pinned->msg->getMedia();
|
||||||
|
switch (media ? media->type() : MediaTypeCount) {
|
||||||
|
case MediaTypePhoto: return lang(lng_action_pinned_media_photo);
|
||||||
|
case MediaTypeVideo: return lang(lng_action_pinned_media_video);
|
||||||
|
case MediaTypeContact: return lang(lng_action_pinned_media_contact);
|
||||||
|
case MediaTypeFile: return lang(lng_action_pinned_media_file);
|
||||||
|
case MediaTypeGif: {
|
||||||
|
if (auto document = media->getDocument()) {
|
||||||
|
if (document->isRoundVideo()) {
|
||||||
|
return lang(lng_action_pinned_media_video_message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lang(lng_action_pinned_media_gif);
|
||||||
|
} break;
|
||||||
|
case MediaTypeSticker: {
|
||||||
|
auto emoji = static_cast<HistorySticker*>(media)->emoji();
|
||||||
|
if (emoji.isEmpty()) {
|
||||||
|
return lang(lng_action_pinned_media_sticker);
|
||||||
|
}
|
||||||
|
return lng_action_pinned_media_emoji_sticker(lt_emoji, emoji);
|
||||||
|
} break;
|
||||||
|
case MediaTypeLocation: return lang(lng_action_pinned_media_location);
|
||||||
|
case MediaTypeMusicFile: return lang(lng_action_pinned_media_audio);
|
||||||
|
case MediaTypeVoiceFile: return lang(lng_action_pinned_media_voice);
|
||||||
|
case MediaTypeGame: {
|
||||||
|
auto title = static_cast<HistoryGame*>(media)->game()->title;
|
||||||
|
return lng_action_pinned_media_game(lt_game, title);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
|
})();
|
||||||
|
|
||||||
|
result.links.push_back(fromLink());
|
||||||
|
result.links.push_back(pinned->lnk);
|
||||||
|
if (mediaText.isEmpty()) {
|
||||||
|
auto original = pinned->msg->originalText().text;
|
||||||
|
auto cutAt = 0;
|
||||||
|
auto limit = kPinnedMessageTextLimit;
|
||||||
|
auto size = original.size();
|
||||||
|
for (; limit != 0;) {
|
||||||
|
--limit;
|
||||||
|
if (cutAt >= size) break;
|
||||||
|
if (original.at(cutAt).isLowSurrogate() && cutAt + 1 < size && original.at(cutAt + 1).isHighSurrogate()) {
|
||||||
|
cutAt += 2;
|
||||||
|
} else {
|
||||||
|
++cutAt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!limit && cutAt + 5 < size) {
|
||||||
|
original = original.mid(0, cutAt) + qstr("...");
|
||||||
|
}
|
||||||
|
result.text = lng_action_pinned_message(lt_from, fromLinkText(), lt_text, textcmdLink(2, original));
|
||||||
|
} else {
|
||||||
|
result.text = lng_action_pinned_media(lt_from, fromLinkText(), lt_media, textcmdLink(2, mediaText));
|
||||||
|
}
|
||||||
|
} else if (pinned && pinned->msgId) {
|
||||||
|
result.links.push_back(fromLink());
|
||||||
|
result.links.push_back(pinned->lnk);
|
||||||
|
result.text = lng_action_pinned_media(lt_from, fromLinkText(), lt_media, textcmdLink(2, lang(lng_contacts_loading)));
|
||||||
|
} else {
|
||||||
|
result.links.push_back(fromLink());
|
||||||
|
result.text = lng_action_pinned_media(lt_from, fromLinkText(), lt_media, lang(lng_deleted_message));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryService::PreparedText HistoryService::prepareGameScoreText() {
|
||||||
|
auto result = PreparedText {};
|
||||||
|
auto gamescore = Get<HistoryServiceGameScore>();
|
||||||
|
|
||||||
|
auto computeGameTitle = [gamescore, &result]() -> QString {
|
||||||
|
if (gamescore && gamescore->msg) {
|
||||||
|
if (auto media = gamescore->msg->getMedia()) {
|
||||||
|
if (media->type() == MediaTypeGame) {
|
||||||
|
result.links.push_back(MakeShared<ReplyMarkupClickHandler>(gamescore->msg, 0, 0));
|
||||||
|
auto titleText = static_cast<HistoryGame*>(media)->game()->title;
|
||||||
|
return textcmdLink(result.links.size(), titleText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lang(lng_deleted_message);
|
||||||
|
} else if (gamescore && gamescore->msgId) {
|
||||||
|
return lang(lng_contacts_loading);
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
|
};
|
||||||
|
|
||||||
|
auto scoreNumber = gamescore ? gamescore->score : 0;
|
||||||
|
if (_from->isSelf()) {
|
||||||
|
auto gameTitle = computeGameTitle();
|
||||||
|
if (gameTitle.isEmpty()) {
|
||||||
|
result.text = lng_action_game_you_scored_no_game(lt_count, scoreNumber);
|
||||||
|
} else {
|
||||||
|
result.text = lng_action_game_you_scored(lt_count, scoreNumber, lt_game, gameTitle);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.links.push_back(fromLink());
|
||||||
|
auto gameTitle = computeGameTitle();
|
||||||
|
if (gameTitle.isEmpty()) {
|
||||||
|
result.text = lng_action_game_score_no_game(lt_count, scoreNumber, lt_from, fromLinkText());
|
||||||
|
} else {
|
||||||
|
result.text = lng_action_game_score(lt_count, scoreNumber, lt_from, fromLinkText(), lt_game, gameTitle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryService::PreparedText HistoryService::preparePaymentSentText() {
|
||||||
|
auto result = PreparedText {};
|
||||||
|
auto payment = Get<HistoryServicePayment>();
|
||||||
|
|
||||||
|
auto invoiceTitle = ([payment]() -> QString {
|
||||||
|
if (payment && payment->msg) {
|
||||||
|
if (auto media = payment->msg->getMedia()) {
|
||||||
|
if (media->type() == MediaTypeInvoice) {
|
||||||
|
return static_cast<HistoryInvoice*>(media)->getTitle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lang(lng_deleted_message);
|
||||||
|
} else if (payment && payment->msgId) {
|
||||||
|
return lang(lng_contacts_loading);
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
|
})();
|
||||||
|
|
||||||
|
if (invoiceTitle.isEmpty()) {
|
||||||
|
result.text = lng_action_payment_done(lt_amount, payment->amount, lt_user, history()->peer->name);
|
||||||
|
} else {
|
||||||
|
result.text = lng_action_payment_done_for(lt_amount, payment->amount, lt_user, history()->peer->name, lt_invoice, invoiceTitle);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryService::HistoryService(gsl::not_null<History*> history, const MTPDmessageService &message) :
|
||||||
|
HistoryItem(history, message.vid.v, mtpCastFlags(message.vflags.v), ::date(message.vdate), message.has_from_id() ? message.vfrom_id.v : 0) {
|
||||||
|
createFromMtp(message);
|
||||||
|
setMessageByAction(message.vaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryService::HistoryService(gsl::not_null<History*> history, MsgId msgId, QDateTime date, const PreparedText &message, MTPDmessage::Flags flags, int32 from, PhotoData *photo) :
|
||||||
|
HistoryItem(history, msgId, flags, date, from) {
|
||||||
|
setServiceText(message);
|
||||||
|
if (photo) {
|
||||||
|
_media = std::make_unique<HistoryPhoto>(this, history->peer, photo, st::msgServicePhotoWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryService::initDimensions() {
|
||||||
|
_maxw = _text.maxWidth() + st::msgServicePadding.left() + st::msgServicePadding.right();
|
||||||
|
_minh = _text.minHeight();
|
||||||
|
if (_media) {
|
||||||
|
_media->initDimensions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HistoryService::updateDependencyItem() {
|
||||||
|
if (GetDependentData()) {
|
||||||
|
return updateDependent(true);
|
||||||
|
}
|
||||||
|
return HistoryItem::updateDependencyItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect HistoryService::countGeometry() const {
|
||||||
|
auto result = QRect(0, 0, width(), _height);
|
||||||
|
if (Adaptive::ChatWide()) {
|
||||||
|
result.setWidth(qMin(result.width(), st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
|
||||||
|
}
|
||||||
|
return result.marginsRemoved(st::msgServiceMargin);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextWithEntities HistoryService::selectedText(TextSelection selection) const {
|
||||||
|
return _text.originalTextWithEntities((selection == FullSelection) ? AllTextSelection : selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString HistoryService::inDialogsText() const {
|
||||||
|
return textcmdLink(1, textClean(notificationText()));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString HistoryService::inReplyText() const {
|
||||||
|
QString result = HistoryService::notificationText();
|
||||||
|
return result.trimmed().startsWith(author()->name) ? result.trimmed().mid(author()->name.size()).trimmed() : result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryService::setServiceText(const PreparedText &prepared) {
|
||||||
|
_text.setText(st::serviceTextStyle, prepared.text, _historySrvOptions);
|
||||||
|
auto linkIndex = 0;
|
||||||
|
for_const (auto &link, prepared.links) {
|
||||||
|
// Link indices start with 1.
|
||||||
|
_text.setLink(++linkIndex, link);
|
||||||
|
}
|
||||||
|
|
||||||
|
setPendingInitDimensions();
|
||||||
|
_textWidth = -1;
|
||||||
|
_textHeight = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryService::draw(Painter &p, QRect clip, TextSelection selection, TimeMs ms) const {
|
||||||
|
auto height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom();
|
||||||
|
auto dateh = 0;
|
||||||
|
auto unreadbarh = 0;
|
||||||
|
if (auto date = Get<HistoryMessageDate>()) {
|
||||||
|
dateh = date->height();
|
||||||
|
p.translate(0, dateh);
|
||||||
|
clip.translate(0, -dateh);
|
||||||
|
height -= dateh;
|
||||||
|
}
|
||||||
|
if (auto unreadbar = Get<HistoryMessageUnreadBar>()) {
|
||||||
|
unreadbarh = unreadbar->height();
|
||||||
|
if (clip.intersects(QRect(0, 0, width(), unreadbarh))) {
|
||||||
|
unreadbar->paint(p, 0, width());
|
||||||
|
}
|
||||||
|
p.translate(0, unreadbarh);
|
||||||
|
clip.translate(0, -unreadbarh);
|
||||||
|
height -= unreadbarh;
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryLayout::PaintContext context(ms, clip, selection);
|
||||||
|
HistoryLayout::ServiceMessagePainter::paint(p, this, context, height);
|
||||||
|
|
||||||
|
if (auto skiph = dateh + unreadbarh) {
|
||||||
|
p.translate(0, -skiph);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int HistoryService::resizeContentGetHeight() {
|
||||||
|
_height = displayedDateHeight();
|
||||||
|
if (auto unreadbar = Get<HistoryMessageUnreadBar>()) {
|
||||||
|
_height += unreadbar->height();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_text.isEmpty()) {
|
||||||
|
_textHeight = 0;
|
||||||
|
} else {
|
||||||
|
auto contentWidth = width();
|
||||||
|
if (Adaptive::ChatWide()) {
|
||||||
|
accumulate_min(contentWidth, st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left());
|
||||||
|
}
|
||||||
|
contentWidth -= st::msgServiceMargin.left() + st::msgServiceMargin.left(); // two small margins
|
||||||
|
if (contentWidth < st::msgServicePadding.left() + st::msgServicePadding.right() + 1) {
|
||||||
|
contentWidth = st::msgServicePadding.left() + st::msgServicePadding.right() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto nwidth = qMax(contentWidth - st::msgServicePadding.left() - st::msgServicePadding.right(), 0);
|
||||||
|
if (nwidth != _textWidth) {
|
||||||
|
_textWidth = nwidth;
|
||||||
|
_textHeight = _text.countHeight(nwidth);
|
||||||
|
}
|
||||||
|
if (contentWidth >= _maxw) {
|
||||||
|
_height += _minh;
|
||||||
|
} else {
|
||||||
|
_height += _textHeight;
|
||||||
|
}
|
||||||
|
_height += st::msgServicePadding.top() + st::msgServicePadding.bottom() + st::msgServiceMargin.top() + st::msgServiceMargin.bottom();
|
||||||
|
if (_media) {
|
||||||
|
_height += st::msgServiceMargin.top() + _media->resizeGetHeight(_media->currentWidth());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _height;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HistoryService::hasPoint(QPoint point) const {
|
||||||
|
auto g = countGeometry();
|
||||||
|
if (g.width() < 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto dateh = displayedDateHeight()) {
|
||||||
|
g.setTop(g.top() + dateh);
|
||||||
|
}
|
||||||
|
if (auto unreadbar = Get<HistoryMessageUnreadBar>()) {
|
||||||
|
g.setTop(g.top() + unreadbar->height());
|
||||||
|
}
|
||||||
|
if (_media) {
|
||||||
|
g.setHeight(g.height() - (st::msgServiceMargin.top() + _media->height()));
|
||||||
|
}
|
||||||
|
return g.contains(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryTextState HistoryService::getState(QPoint point, HistoryStateRequest request) const {
|
||||||
|
HistoryTextState result;
|
||||||
|
|
||||||
|
auto g = countGeometry();
|
||||||
|
if (g.width() < 1) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto dateh = displayedDateHeight()) {
|
||||||
|
point.setY(point.y() - dateh);
|
||||||
|
g.setHeight(g.height() - dateh);
|
||||||
|
}
|
||||||
|
if (auto unreadbar = Get<HistoryMessageUnreadBar>()) {
|
||||||
|
auto unreadbarh = unreadbar->height();
|
||||||
|
point.setY(point.y() - unreadbarh);
|
||||||
|
g.setHeight(g.height() - unreadbarh);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_media) {
|
||||||
|
g.setHeight(g.height() - (st::msgServiceMargin.top() + _media->height()));
|
||||||
|
}
|
||||||
|
auto trect = g.marginsAdded(-st::msgServicePadding);
|
||||||
|
if (trect.contains(point)) {
|
||||||
|
auto textRequest = request.forText();
|
||||||
|
textRequest.align = style::al_center;
|
||||||
|
result = _text.getState(point - trect.topLeft(), trect.width(), textRequest);
|
||||||
|
if (auto gamescore = Get<HistoryServiceGameScore>()) {
|
||||||
|
if (!result.link && result.cursor == HistoryInTextCursorState && g.contains(point)) {
|
||||||
|
result.link = gamescore->lnk;
|
||||||
|
}
|
||||||
|
} else if (auto payment = Get<HistoryServicePayment>()) {
|
||||||
|
if (!result.link && result.cursor == HistoryInTextCursorState && g.contains(point)) {
|
||||||
|
result.link = payment->lnk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (_media) {
|
||||||
|
result = _media->getState(point - QPoint(st::msgServiceMargin.left() + (g.width() - _media->maxWidth()) / 2, st::msgServiceMargin.top() + g.height() + st::msgServiceMargin.top()), request);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryService::createFromMtp(const MTPDmessageService &message) {
|
||||||
|
if (message.vaction.type() == mtpc_messageActionGameScore) {
|
||||||
|
UpdateComponents(HistoryServiceGameScore::Bit());
|
||||||
|
Get<HistoryServiceGameScore>()->score = message.vaction.c_messageActionGameScore().vscore.v;
|
||||||
|
} else if (message.vaction.type() == mtpc_messageActionPaymentSent) {
|
||||||
|
UpdateComponents(HistoryServicePayment::Bit());
|
||||||
|
auto amount = message.vaction.c_messageActionPaymentSent().vtotal_amount.v;
|
||||||
|
auto currency = qs(message.vaction.c_messageActionPaymentSent().vcurrency);
|
||||||
|
Get<HistoryServicePayment>()->amount = HistoryInvoice::fillAmountAndCurrency(amount, currency);
|
||||||
|
}
|
||||||
|
if (message.has_reply_to_msg_id()) {
|
||||||
|
if (message.vaction.type() == mtpc_messageActionPinMessage) {
|
||||||
|
UpdateComponents(HistoryServicePinned::Bit());
|
||||||
|
}
|
||||||
|
if (auto dependent = GetDependentData()) {
|
||||||
|
dependent->msgId = message.vreply_to_msg_id.v;
|
||||||
|
if (!updateDependent() && App::api()) {
|
||||||
|
App::api()->requestMessageData(history()->peer->asChannel(), dependent->msgId, HistoryDependentItemCallback(fullId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setMessageByAction(message.vaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryService::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
|
||||||
|
if (_media) _media->clickHandlerActiveChanged(p, active);
|
||||||
|
HistoryItem::clickHandlerActiveChanged(p, active);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryService::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) {
|
||||||
|
if (_media) _media->clickHandlerPressedChanged(p, pressed);
|
||||||
|
HistoryItem::clickHandlerPressedChanged(p, pressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryService::applyEdition(const MTPDmessageService &message) {
|
||||||
|
clearDependency();
|
||||||
|
UpdateComponents(0);
|
||||||
|
|
||||||
|
createFromMtp(message);
|
||||||
|
|
||||||
|
if (message.vaction.type() == mtpc_messageActionHistoryClear) {
|
||||||
|
removeMedia();
|
||||||
|
finishEditionToEmpty();
|
||||||
|
} else {
|
||||||
|
finishEdition(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryService::removeMedia() {
|
||||||
|
if (!_media) return;
|
||||||
|
|
||||||
|
bool mediaWasDisplayed = _media->isDisplayed();
|
||||||
|
_media.reset();
|
||||||
|
if (mediaWasDisplayed) {
|
||||||
|
_textWidth = -1;
|
||||||
|
_textHeight = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 HistoryService::addToOverview(AddToOverviewMethod method) {
|
||||||
|
if (!indexInOverview()) return 0;
|
||||||
|
|
||||||
|
int32 result = 0;
|
||||||
|
if (auto media = getMedia()) {
|
||||||
|
result |= media->addToOverview(method);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryService::eraseFromOverview() {
|
||||||
|
if (auto media = getMedia()) {
|
||||||
|
media->eraseFromOverview();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryService::updateDependentText() {
|
||||||
|
auto text = PreparedText {};
|
||||||
|
if (Has<HistoryServicePinned>()) {
|
||||||
|
text = preparePinnedText();
|
||||||
|
} else if (Has<HistoryServiceGameScore>()) {
|
||||||
|
text = prepareGameScoreText();
|
||||||
|
} else if (Has<HistoryServicePayment>()) {
|
||||||
|
text = preparePaymentSentText();
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setServiceText(text);
|
||||||
|
if (history()->textCachedFor == this) {
|
||||||
|
history()->textCachedFor = nullptr;
|
||||||
|
}
|
||||||
|
if (App::main()) {
|
||||||
|
App::main()->dlgUpdated(history()->peer, id);
|
||||||
|
}
|
||||||
|
App::historyUpdateDependent(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryService::clearDependency() {
|
||||||
|
if (auto dependent = GetDependentData()) {
|
||||||
|
if (dependent->msg) {
|
||||||
|
App::historyUnregDependency(this, dependent->msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryService::~HistoryService() {
|
||||||
|
clearDependency();
|
||||||
|
_media.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryJoined::HistoryJoined(gsl::not_null<History*> history, const QDateTime &inviteDate, gsl::not_null<UserData*> inviter, MTPDmessage::Flags flags)
|
||||||
|
: HistoryService(history, clientMsgId(), inviteDate, GenerateText(history, inviter), flags) {
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryJoined::PreparedText HistoryJoined::GenerateText(gsl::not_null<History*> history, gsl::not_null<UserData*> inviter) {
|
||||||
|
if (inviter->id == AuthSession::CurrentUserPeerId()) {
|
||||||
|
return { lang(history->isMegagroup() ? lng_action_you_joined_group : lng_action_you_joined) };
|
||||||
|
}
|
||||||
|
auto result = PreparedText {};
|
||||||
|
result.links.push_back(peerOpenClickHandler(inviter));
|
||||||
|
if (history->isMegagroup()) {
|
||||||
|
result.text = lng_action_add_you_group(lt_from, textcmdLink(1, inviter->name));
|
||||||
|
}
|
||||||
|
result.text = lng_action_add_you(lt_from, textcmdLink(1, inviter->name));
|
||||||
|
return result;
|
||||||
|
}
|
|
@ -0,0 +1,166 @@
|
||||||
|
/*
|
||||||
|
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-2017 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct HistoryServiceDependentData {
|
||||||
|
MsgId msgId = 0;
|
||||||
|
HistoryItem *msg = nullptr;
|
||||||
|
ClickHandlerPtr lnk;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HistoryServicePinned : public RuntimeComponent<HistoryServicePinned>, public HistoryServiceDependentData {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HistoryServiceGameScore : public RuntimeComponent<HistoryServiceGameScore>, public HistoryServiceDependentData {
|
||||||
|
int score = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HistoryServicePayment : public RuntimeComponent<HistoryServicePayment>, public HistoryServiceDependentData {
|
||||||
|
QString amount;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace HistoryLayout {
|
||||||
|
class ServiceMessagePainter;
|
||||||
|
} // namespace HistoryLayout
|
||||||
|
|
||||||
|
class HistoryService : public HistoryItem, private HistoryItemInstantiated<HistoryService> {
|
||||||
|
public:
|
||||||
|
struct PreparedText {
|
||||||
|
QString text;
|
||||||
|
QList<ClickHandlerPtr> links;
|
||||||
|
};
|
||||||
|
|
||||||
|
static gsl::not_null<HistoryService*> create(gsl::not_null<History*> history, const MTPDmessageService &message) {
|
||||||
|
return _create(history, message);
|
||||||
|
}
|
||||||
|
static gsl::not_null<HistoryService*> create(gsl::not_null<History*> history, MsgId msgId, QDateTime date, const PreparedText &message, MTPDmessage::Flags flags = 0, UserId from = 0, PhotoData *photo = nullptr) {
|
||||||
|
return _create(history, msgId, date, message, flags, from, photo);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool updateDependencyItem() override;
|
||||||
|
MsgId dependencyMsgId() const override {
|
||||||
|
if (auto dependent = GetDependentData()) {
|
||||||
|
return dependent->msgId;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
bool notificationReady() const override {
|
||||||
|
if (auto dependent = GetDependentData()) {
|
||||||
|
return (dependent->msg || !dependent->msgId);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect countGeometry() const;
|
||||||
|
|
||||||
|
void draw(Painter &p, QRect clip, TextSelection selection, TimeMs ms) const override;
|
||||||
|
bool hasPoint(QPoint point) const override;
|
||||||
|
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override;
|
||||||
|
|
||||||
|
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override {
|
||||||
|
return _text.adjustSelection(selection, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
||||||
|
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
|
||||||
|
|
||||||
|
void applyEdition(const MTPDmessageService &message) override;
|
||||||
|
|
||||||
|
int32 addToOverview(AddToOverviewMethod method) override;
|
||||||
|
void eraseFromOverview() override;
|
||||||
|
|
||||||
|
bool needCheck() const override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool serviceMsg() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
TextWithEntities selectedText(TextSelection selection) const override;
|
||||||
|
QString inDialogsText() const override;
|
||||||
|
QString inReplyText() const override;
|
||||||
|
|
||||||
|
~HistoryService();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
friend class HistoryLayout::ServiceMessagePainter;
|
||||||
|
|
||||||
|
HistoryService(gsl::not_null<History*> history, const MTPDmessageService &message);
|
||||||
|
HistoryService(gsl::not_null<History*> history, MsgId msgId, QDateTime date, const PreparedText &message, MTPDmessage::Flags flags = 0, UserId from = 0, PhotoData *photo = 0);
|
||||||
|
friend class HistoryItemInstantiated<HistoryService>;
|
||||||
|
|
||||||
|
void initDimensions() override;
|
||||||
|
int resizeContentGetHeight() override;
|
||||||
|
|
||||||
|
void setServiceText(const PreparedText &prepared);
|
||||||
|
|
||||||
|
QString fromLinkText() const {
|
||||||
|
return textcmdLink(1, _from->name);
|
||||||
|
};
|
||||||
|
ClickHandlerPtr fromLink() const {
|
||||||
|
return peerOpenClickHandler(_from);
|
||||||
|
};
|
||||||
|
|
||||||
|
void removeMedia();
|
||||||
|
|
||||||
|
private:
|
||||||
|
HistoryServiceDependentData *GetDependentData() {
|
||||||
|
if (auto pinned = Get<HistoryServicePinned>()) {
|
||||||
|
return pinned;
|
||||||
|
} else if (auto gamescore = Get<HistoryServiceGameScore>()) {
|
||||||
|
return gamescore;
|
||||||
|
} else if (auto payment = Get<HistoryServicePayment>()) {
|
||||||
|
return payment;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const HistoryServiceDependentData *GetDependentData() const {
|
||||||
|
return const_cast<HistoryService*>(this)->GetDependentData();
|
||||||
|
}
|
||||||
|
bool updateDependent(bool force = false);
|
||||||
|
void updateDependentText();
|
||||||
|
void clearDependency();
|
||||||
|
|
||||||
|
void createFromMtp(const MTPDmessageService &message);
|
||||||
|
void setMessageByAction(const MTPmessageAction &action);
|
||||||
|
|
||||||
|
PreparedText preparePinnedText();
|
||||||
|
PreparedText prepareGameScoreText();
|
||||||
|
PreparedText preparePaymentSentText();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class HistoryJoined : public HistoryService, private HistoryItemInstantiated<HistoryJoined> {
|
||||||
|
public:
|
||||||
|
static gsl::not_null<HistoryJoined*> create(gsl::not_null<History*> history, const QDateTime &inviteDate, gsl::not_null<UserData*> inviter, MTPDmessage::Flags flags) {
|
||||||
|
return _create(history, inviteDate, inviter, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
HistoryJoined(gsl::not_null<History*> history, const QDateTime &inviteDate, gsl::not_null<UserData*> inviter, MTPDmessage::Flags flags);
|
||||||
|
using HistoryItemInstantiated<HistoryJoined>::_create;
|
||||||
|
friend class HistoryItemInstantiated<HistoryJoined>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static PreparedText GenerateText(gsl::not_null<History*> history, gsl::not_null<UserData*> inviter);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
extern TextParseOptions _historySrvOptions;
|
|
@ -20,6 +20,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#include "history/history_service_layout.h"
|
#include "history/history_service_layout.h"
|
||||||
|
|
||||||
|
#include "history/history_service.h"
|
||||||
|
#include "history/history_media.h"
|
||||||
#include "data/data_abstract_structure.h"
|
#include "data/data_abstract_structure.h"
|
||||||
#include "styles/style_history.h"
|
#include "styles/style_history.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
|
|
|
@ -20,6 +20,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
class HistoryService;
|
||||||
|
|
||||||
namespace HistoryLayout {
|
namespace HistoryLayout {
|
||||||
|
|
||||||
int WideChatWidth();
|
int WideChatWidth();
|
||||||
|
|
|
@ -39,6 +39,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "ui/effects/ripple_animation.h"
|
#include "ui/effects/ripple_animation.h"
|
||||||
#include "inline_bots/inline_bot_result.h"
|
#include "inline_bots/inline_bot_result.h"
|
||||||
#include "data/data_drafts.h"
|
#include "data/data_drafts.h"
|
||||||
|
#include "history/history_message.h"
|
||||||
#include "history/history_service_layout.h"
|
#include "history/history_service_layout.h"
|
||||||
#include "history/history_media_types.h"
|
#include "history/history_media_types.h"
|
||||||
#include "history/history_drag_area.h"
|
#include "history/history_drag_area.h"
|
||||||
|
@ -3097,8 +3098,8 @@ void HistoryWidget::shareContact(const PeerId &peer, const QString &phone, const
|
||||||
App::main()->readServerHistory(history);
|
App::main()->readServerHistory(history);
|
||||||
fastShowAtEnd(history);
|
fastShowAtEnd(history);
|
||||||
|
|
||||||
PeerData *p = App::peer(peer);
|
auto p = App::peer(peer);
|
||||||
auto flags = newMessageFlags(p) | MTPDmessage::Flag::f_media; // unread, out
|
auto flags = NewMessageFlags(p) | MTPDmessage::Flag::f_media; // unread, out
|
||||||
|
|
||||||
bool lastKeyboardUsed = lastForceReplyReplied(FullMsgId(peerToChannel(peer), replyTo));
|
bool lastKeyboardUsed = lastForceReplyReplied(FullMsgId(peerToChannel(peer), replyTo));
|
||||||
|
|
||||||
|
@ -4545,7 +4546,7 @@ void HistoryWidget::sendFileConfirmed(const FileLoadResultPtr &file) {
|
||||||
|
|
||||||
fastShowAtEnd(h);
|
fastShowAtEnd(h);
|
||||||
|
|
||||||
auto flags = newMessageFlags(h->peer) | MTPDmessage::Flag::f_media; // unread, out
|
auto flags = NewMessageFlags(h->peer) | MTPDmessage::Flag::f_media; // unread, out
|
||||||
if (file->to.replyTo) flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
if (file->to.replyTo) flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
||||||
bool channelPost = h->peer->isChannel() && !h->peer->isMegagroup();
|
bool channelPost = h->peer->isChannel() && !h->peer->isMegagroup();
|
||||||
bool showFromName = !channelPost || h->peer->asChannel()->addsSignature();
|
bool showFromName = !channelPost || h->peer->asChannel()->addsSignature();
|
||||||
|
@ -5358,7 +5359,7 @@ void HistoryWidget::onInlineResultSend(InlineBots::Result *result, UserData *bot
|
||||||
bool lastKeyboardUsed = lastForceReplyReplied();
|
bool lastKeyboardUsed = lastForceReplyReplied();
|
||||||
|
|
||||||
bool out = !_peer->isSelf(), unread = !_peer->isSelf();
|
bool out = !_peer->isSelf(), unread = !_peer->isSelf();
|
||||||
auto flags = newMessageFlags(_peer) | MTPDmessage::Flag::f_media; // unread, out
|
auto flags = NewMessageFlags(_peer) | MTPDmessage::Flag::f_media; // unread, out
|
||||||
auto sendFlags = qFlags(MTPmessages_SendInlineBotResult::Flag::f_clear_draft);
|
auto sendFlags = qFlags(MTPmessages_SendInlineBotResult::Flag::f_clear_draft);
|
||||||
if (replyToId()) {
|
if (replyToId()) {
|
||||||
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
||||||
|
@ -5531,7 +5532,7 @@ bool HistoryWidget::sendExistingDocument(DocumentData *doc, const QString &capti
|
||||||
bool lastKeyboardUsed = lastForceReplyReplied();
|
bool lastKeyboardUsed = lastForceReplyReplied();
|
||||||
|
|
||||||
bool out = !_peer->isSelf(), unread = !_peer->isSelf();
|
bool out = !_peer->isSelf(), unread = !_peer->isSelf();
|
||||||
auto flags = newMessageFlags(_peer) | MTPDmessage::Flag::f_media; // unread, out
|
auto flags = NewMessageFlags(_peer) | MTPDmessage::Flag::f_media; // unread, out
|
||||||
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
||||||
if (replyToId()) {
|
if (replyToId()) {
|
||||||
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
||||||
|
@ -5587,7 +5588,7 @@ void HistoryWidget::sendExistingPhoto(PhotoData *photo, const QString &caption)
|
||||||
bool lastKeyboardUsed = lastForceReplyReplied();
|
bool lastKeyboardUsed = lastForceReplyReplied();
|
||||||
|
|
||||||
bool out = !_peer->isSelf(), unread = !_peer->isSelf();
|
bool out = !_peer->isSelf(), unread = !_peer->isSelf();
|
||||||
auto flags = newMessageFlags(_peer) | MTPDmessage::Flag::f_media; // unread, out
|
auto flags = NewMessageFlags(_peer) | MTPDmessage::Flag::f_media; // unread, out
|
||||||
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
||||||
if (replyToId()) {
|
if (replyToId()) {
|
||||||
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
||||||
|
|
|
@ -35,6 +35,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "dialogswidget.h"
|
#include "dialogswidget.h"
|
||||||
#include "historywidget.h"
|
#include "historywidget.h"
|
||||||
|
#include "history/history_message.h"
|
||||||
|
#include "history/history_media.h"
|
||||||
#include "history/history_service_layout.h"
|
#include "history/history_service_layout.h"
|
||||||
#include "overviewwidget.h"
|
#include "overviewwidget.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
|
@ -1493,7 +1495,7 @@ void MainWidget::sendMessage(const MessageToSend &message) {
|
||||||
App::historyRegSentData(randomId, history->peer->id, sendingText);
|
App::historyRegSentData(randomId, history->peer->id, sendingText);
|
||||||
|
|
||||||
MTPstring msgText(MTP_string(sendingText));
|
MTPstring msgText(MTP_string(sendingText));
|
||||||
auto flags = newMessageFlags(history->peer) | MTPDmessage::Flag::f_entities; // unread, out
|
auto flags = NewMessageFlags(history->peer) | MTPDmessage::Flag::f_entities; // unread, out
|
||||||
auto sendFlags = MTPmessages_SendMessage::Flags(0);
|
auto sendFlags = MTPmessages_SendMessage::Flags(0);
|
||||||
if (replyTo) {
|
if (replyTo) {
|
||||||
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
||||||
|
|
|
@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "media/player/media_player_float.h"
|
#include "media/player/media_player_float.h"
|
||||||
|
|
||||||
#include "styles/style_media_player.h"
|
#include "styles/style_media_player.h"
|
||||||
|
#include "history/history_media.h"
|
||||||
#include "media/media_clip_reader.h"
|
#include "media/media_clip_reader.h"
|
||||||
#include "media/view/media_clip_playback.h"
|
#include "media/view/media_clip_playback.h"
|
||||||
#include "media/media_audio.h"
|
#include "media/media_audio.h"
|
||||||
|
|
|
@ -26,6 +26,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "messenger.h"
|
#include "messenger.h"
|
||||||
#include "auth_session.h"
|
#include "auth_session.h"
|
||||||
#include "calls/calls_instance.h"
|
#include "calls/calls_instance.h"
|
||||||
|
#include "history/history_media.h"
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
namespace Player {
|
namespace Player {
|
||||||
|
|
|
@ -23,6 +23,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "media/player/media_player_instance.h"
|
#include "media/player/media_player_instance.h"
|
||||||
#include "overview/overview_layout.h"
|
#include "overview/overview_layout.h"
|
||||||
#include "styles/style_media_player.h"
|
#include "styles/style_media_player.h"
|
||||||
|
#include "history/history_media.h"
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
namespace Player {
|
namespace Player {
|
||||||
|
|
|
@ -32,6 +32,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "styles/style_mediaview.h"
|
#include "styles/style_mediaview.h"
|
||||||
#include "styles/style_history.h"
|
#include "styles/style_history.h"
|
||||||
#include "media/media_audio.h"
|
#include "media/media_audio.h"
|
||||||
|
#include "history/history_message.h"
|
||||||
#include "history/history_media_types.h"
|
#include "history/history_media_types.h"
|
||||||
#include "window/themes/window_theme_preview.h"
|
#include "window/themes/window_theme_preview.h"
|
||||||
#include "base/task_queue.h"
|
#include "base/task_queue.h"
|
||||||
|
@ -1182,8 +1183,8 @@ void MediaView::displayPhoto(PhotoData *photo, HistoryItem *item) {
|
||||||
_zoom = 0;
|
_zoom = 0;
|
||||||
|
|
||||||
_caption = Text();
|
_caption = Text();
|
||||||
if (HistoryMessage *itemMsg = item ? item->toHistoryMessage() : nullptr) {
|
if (auto itemMsg = item ? item->toHistoryMessage() : nullptr) {
|
||||||
if (HistoryPhoto *photoMsg = dynamic_cast<HistoryPhoto*>(itemMsg->getMedia())) {
|
if (auto photoMsg = dynamic_cast<HistoryPhoto*>(itemMsg->getMedia())) {
|
||||||
_caption.setMarkedText(st::mediaviewCaptionStyle, photoMsg->getCaption(), (item->author()->isUser() && item->author()->asUser()->botInfo) ? _captionBotOptions : _captionTextOptions);
|
_caption.setMarkedText(st::mediaviewCaptionStyle, photoMsg->getCaption(), (item->author()->isUser() && item->author()->asUser()->botInfo) ? _captionBotOptions : _captionTextOptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,7 +104,7 @@ Messenger::Messenger() : QObject()
|
||||||
|
|
||||||
style::startManager();
|
style::startManager();
|
||||||
anim::startManager();
|
anim::startManager();
|
||||||
historyInit();
|
HistoryInit();
|
||||||
Media::Player::start();
|
Media::Player::start();
|
||||||
|
|
||||||
DEBUG_LOG(("Application Info: inited..."));
|
DEBUG_LOG(("Application Info: inited..."));
|
||||||
|
|
|
@ -38,6 +38,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "overviewwidget.h"
|
#include "overviewwidget.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "overview/overview_layout.h"
|
#include "overview/overview_layout.h"
|
||||||
|
#include "history/history_message.h"
|
||||||
#include "history/history_media_types.h"
|
#include "history/history_media_types.h"
|
||||||
#include "history/history_service_layout.h"
|
#include "history/history_service_layout.h"
|
||||||
#include "media/media_audio.h"
|
#include "media/media_audio.h"
|
||||||
|
|
|
@ -161,6 +161,8 @@
|
||||||
<(src_loc)/history/history_media_types.h
|
<(src_loc)/history/history_media_types.h
|
||||||
<(src_loc)/history/history_message.cpp
|
<(src_loc)/history/history_message.cpp
|
||||||
<(src_loc)/history/history_message.h
|
<(src_loc)/history/history_message.h
|
||||||
|
<(src_loc)/history/history_service.cpp
|
||||||
|
<(src_loc)/history/history_service.h
|
||||||
<(src_loc)/history/history_service_layout.cpp
|
<(src_loc)/history/history_service_layout.cpp
|
||||||
<(src_loc)/history/history_service_layout.h
|
<(src_loc)/history/history_service_layout.h
|
||||||
<(src_loc)/inline_bots/inline_bot_layout_internal.cpp
|
<(src_loc)/inline_bots/inline_bot_layout_internal.cpp
|
||||||
|
|
Loading…
Reference in New Issue