mirror of https://github.com/procxx/kepka.git
Moved inline bot result structs from structs.cpp/h module.
Moved inline bot result layouts from layout.cpp/h module. Over status prepared for inline bot file result icon. Dependencies reduced, inline bots code moved to InlineBots namespace. Build in Xcode and QtCreator broken.
This commit is contained in:
parent
a2fc7f6915
commit
3e2485678d
|
@ -2486,6 +2486,8 @@ inlineDescriptionFg: #8a8a8a;
|
||||||
inlineRowMargin: 6px;
|
inlineRowMargin: 6px;
|
||||||
inlineRowBorder: linksBorder;
|
inlineRowBorder: linksBorder;
|
||||||
inlineRowBorderFg: linksBorderFg;
|
inlineRowBorderFg: linksBorderFg;
|
||||||
|
inlineRowFileNameTop: 2px;
|
||||||
|
inlineRowFileDescriptionTop: 23px;
|
||||||
inlineResultsMinWidth: 64px;
|
inlineResultsMinWidth: 64px;
|
||||||
inlineDurationMargin: 3px;
|
inlineDurationMargin: 3px;
|
||||||
|
|
||||||
|
|
|
@ -105,9 +105,6 @@ namespace {
|
||||||
typedef QHash<PhotoData*, LastPhotosList::iterator> LastPhotosMap;
|
typedef QHash<PhotoData*, LastPhotosList::iterator> LastPhotosMap;
|
||||||
LastPhotosMap lastPhotosMap;
|
LastPhotosMap lastPhotosMap;
|
||||||
|
|
||||||
typedef QMap<FileLoader*, InlineResult*> InlineResultLoaders;
|
|
||||||
InlineResultLoaders inlineResultLoaders;
|
|
||||||
|
|
||||||
style::color _msgServiceBg;
|
style::color _msgServiceBg;
|
||||||
style::color _msgServiceSelectBg;
|
style::color _msgServiceSelectBg;
|
||||||
style::color _historyScrollBarColor;
|
style::color _historyScrollBarColor;
|
||||||
|
@ -2376,14 +2373,6 @@ namespace {
|
||||||
if (changeInMin) App::main()->updateMutedIn(changeInMin);
|
if (changeInMin) App::main()->updateMutedIn(changeInMin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void regInlineResultLoader(FileLoader *loader, InlineResult *result) {
|
|
||||||
::inlineResultLoaders.insert(loader, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void unregInlineResultLoader(FileLoader *loader) {
|
|
||||||
::inlineResultLoaders.remove(loader);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setProxySettings(QNetworkAccessManager &manager) {
|
void setProxySettings(QNetworkAccessManager &manager) {
|
||||||
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
|
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
|
||||||
manager.setProxy(getHttpProxySettings());
|
manager.setProxy(getHttpProxySettings());
|
||||||
|
|
|
@ -259,10 +259,6 @@ namespace App {
|
||||||
void unregMuted(PeerData *peer);
|
void unregMuted(PeerData *peer);
|
||||||
void updateMuted();
|
void updateMuted();
|
||||||
|
|
||||||
void regInlineResultLoader(FileLoader *loader, InlineResult *result);
|
|
||||||
void unregInlineResultLoader(FileLoader *loader);
|
|
||||||
InlineResult *inlineResultFromLoader(FileLoader *loader);
|
|
||||||
|
|
||||||
void setProxySettings(QNetworkAccessManager &manager);
|
void setProxySettings(QNetworkAccessManager &manager);
|
||||||
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
|
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
|
||||||
QNetworkProxy getHttpProxySettings();
|
QNetworkProxy getHttpProxySettings();
|
||||||
|
|
|
@ -782,6 +782,56 @@ inline QSharedPointer<T> MakeShared(Args&&... args) {
|
||||||
return QSharedPointer<T>(new T(std_::forward<Args>(args)...));
|
return QSharedPointer<T>(new T(std_::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This pointer is used for global non-POD variables that are allocated
|
||||||
|
// on demand by createIfNull(lambda) and are never automatically freed.
|
||||||
|
template <typename T>
|
||||||
|
class NeverFreedPointer {
|
||||||
|
public:
|
||||||
|
explicit NeverFreedPointer() {
|
||||||
|
}
|
||||||
|
NeverFreedPointer(const NeverFreedPointer<T> &other) = delete;
|
||||||
|
NeverFreedPointer &operator=(const NeverFreedPointer<T> &other) = delete;
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
void createIfNull(U creator) {
|
||||||
|
if (isNull()) {
|
||||||
|
reset(creator());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
T *data() const {
|
||||||
|
return _p;
|
||||||
|
}
|
||||||
|
T *release() {
|
||||||
|
return getPointerAndReset(_p);
|
||||||
|
}
|
||||||
|
void reset(T *p = nullptr) {
|
||||||
|
delete _p;
|
||||||
|
_p = p;
|
||||||
|
}
|
||||||
|
bool isNull() const {
|
||||||
|
return data() == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
T *operator->() const {
|
||||||
|
return data();
|
||||||
|
}
|
||||||
|
T &operator*() const {
|
||||||
|
t_assert(!isNull());
|
||||||
|
return *data();
|
||||||
|
}
|
||||||
|
explicit operator bool() const {
|
||||||
|
return !isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T *_p = nullptr;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
template <typename I>
|
template <typename I>
|
||||||
inline void destroyImplementation(I *&ptr) {
|
inline void destroyImplementation(I *&ptr) {
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
|
|
|
@ -19,19 +19,18 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
|
|
||||||
#include "dropdown.h"
|
#include "dropdown.h"
|
||||||
#include "historywidget.h"
|
|
||||||
|
|
||||||
#include "localstorage.h"
|
|
||||||
#include "lang.h"
|
|
||||||
|
|
||||||
#include "window.h"
|
|
||||||
#include "apiwrap.h"
|
|
||||||
#include "mainwidget.h"
|
|
||||||
|
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
#include "boxes/stickersetbox.h"
|
#include "boxes/stickersetbox.h"
|
||||||
|
#include "inline_bots/inline_bot_result.h"
|
||||||
|
#include "inline_bots/inline_bot_layout_item.h"
|
||||||
|
#include "historywidget.h"
|
||||||
|
#include "localstorage.h"
|
||||||
|
#include "lang.h"
|
||||||
|
#include "window.h"
|
||||||
|
#include "apiwrap.h"
|
||||||
|
#include "mainwidget.h"
|
||||||
|
|
||||||
Dropdown::Dropdown(QWidget *parent, const style::dropdown &st) : TWidget(parent)
|
Dropdown::Dropdown(QWidget *parent, const style::dropdown &st) : TWidget(parent)
|
||||||
, _ignore(false)
|
, _ignore(false)
|
||||||
|
@ -457,6 +456,8 @@ void DragArea::step_appearance(float64 ms, bool timer) {
|
||||||
if (timer) update();
|
if (timer) update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
EmojiColorPicker::EmojiColorPicker() : TWidget()
|
EmojiColorPicker::EmojiColorPicker() : TWidget()
|
||||||
, _ignoreShow(false)
|
, _ignoreShow(false)
|
||||||
, _a_selected(animation(this, &EmojiColorPicker::step_selected))
|
, _a_selected(animation(this, &EmojiColorPicker::step_selected))
|
||||||
|
@ -1272,6 +1273,12 @@ int32 StickerPanInner::countHeight(bool plain) {
|
||||||
return qMax(minLastH, result) + st::stickerPanPadding;
|
return qMax(minLastH, result) + st::stickerPanPadding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StickerPanInner::~StickerPanInner() {
|
||||||
|
clearInlineRows(true);
|
||||||
|
deleteUnusedGifLayouts();
|
||||||
|
deleteUnusedInlineLayouts();
|
||||||
|
}
|
||||||
|
|
||||||
QRect StickerPanInner::stickerRect(int tab, int sel) {
|
QRect StickerPanInner::stickerRect(int tab, int sel) {
|
||||||
int x = 0, y = 0;
|
int x = 0, y = 0;
|
||||||
for (int i = 0; i < _sets.size(); ++i) {
|
for (int i = 0; i < _sets.size(); ++i) {
|
||||||
|
@ -1311,7 +1318,7 @@ void StickerPanInner::paintInlineItems(Painter &p, const QRect &r) {
|
||||||
p.drawText(QRect(0, 0, width(), (height() / 3) * 2 + st::normalFont->height), lang(lng_inline_bot_no_results), style::al_center);
|
p.drawText(QRect(0, 0, width(), (height() / 3) * 2 + st::normalFont->height), lang(lng_inline_bot_no_results), style::al_center);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
InlinePaintContext context(getms(), false, Ui::isLayerShown() || Ui::isMediaViewShown() || _previewShown, false);
|
InlineBots::Layout::PaintContext context(getms(), false, Ui::isLayerShown() || Ui::isMediaViewShown() || _previewShown, false);
|
||||||
|
|
||||||
int32 top = st::emojiPanHeader;
|
int32 top = st::emojiPanHeader;
|
||||||
int32 fromx = rtl() ? (width() - r.x() - r.width()) : r.x(), tox = rtl() ? (width() - r.x()) : (r.x() + r.width());
|
int32 fromx = rtl() ? (width() - r.x() - r.width()) : r.x(), tox = rtl() ? (width() - r.x()) : (r.x() + r.width());
|
||||||
|
@ -1324,7 +1331,7 @@ void StickerPanInner::paintInlineItems(Painter &p, const QRect &r) {
|
||||||
for (int32 col = 0, cols = inlineRow.items.size(); col < cols; ++col) {
|
for (int32 col = 0, cols = inlineRow.items.size(); col < cols; ++col) {
|
||||||
if (left >= tox) break;
|
if (left >= tox) break;
|
||||||
|
|
||||||
const LayoutInlineItem *item = inlineRow.items.at(col);
|
const InlineItem *item = inlineRow.items.at(col);
|
||||||
int32 w = item->width();
|
int32 w = item->width();
|
||||||
if (left + w > fromx) {
|
if (left + w > fromx) {
|
||||||
p.translate(left, top);
|
p.translate(left, top);
|
||||||
|
@ -1441,7 +1448,7 @@ void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
|
|
||||||
if (_selected < 0 || _selected != pressed || (_showingInlineItems && !activated)) return;
|
if (_selected < 0 || _selected != pressed || (_showingInlineItems && !activated)) return;
|
||||||
if (_showingInlineItems) {
|
if (_showingInlineItems) {
|
||||||
if (!dynamic_cast<SendInlineItemClickHandler*>(activated.data())) {
|
if (!dynamic_cast<InlineBots::Layout::SendClickHandler*>(activated.data())) {
|
||||||
App::activateClickHandler(activated, e->button());
|
App::activateClickHandler(activated, e->button());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1450,10 +1457,10 @@ void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutInlineItem *item = _inlineRows.at(row).items.at(col);
|
InlineItem *item = _inlineRows.at(row).items.at(col);
|
||||||
PhotoData *photo = item->getPhoto();
|
PhotoData *photo = item->getPhoto();
|
||||||
DocumentData *document = item->getDocument();
|
DocumentData *document = item->getDocument();
|
||||||
InlineResult *inlineResult = item->getInlineResult();
|
InlineResult *inlineResult = item->getResult();
|
||||||
using Type = InlineResult::Type;
|
using Type = InlineResult::Type;
|
||||||
auto getShownPhoto = [photo, inlineResult]() -> PhotoData* {
|
auto getShownPhoto = [photo, inlineResult]() -> PhotoData* {
|
||||||
if (photo) {
|
if (photo) {
|
||||||
|
@ -1495,7 +1502,7 @@ void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
shownPhoto->medium->loadEvenCancelled();
|
shownPhoto->medium->loadEvenCancelled();
|
||||||
}
|
}
|
||||||
} else if (DocumentData *shownDocument = getShownDocument()) {
|
} else if (DocumentData *shownDocument = getShownDocument()) {
|
||||||
if (inlineResult->type == Type::Gif) {
|
if (!inlineResult || inlineResult->type == Type::Gif) {
|
||||||
if (shownDocument->loaded()) {
|
if (shownDocument->loaded()) {
|
||||||
sendInlineItem();
|
sendInlineItem();
|
||||||
} else if (shownDocument->loading()) {
|
} else if (shownDocument->loading()) {
|
||||||
|
@ -1640,17 +1647,28 @@ void StickerPanInner::clearSelection(bool fast) {
|
||||||
|
|
||||||
void StickerPanInner::hideFinish(bool completely) {
|
void StickerPanInner::hideFinish(bool completely) {
|
||||||
if (completely) {
|
if (completely) {
|
||||||
|
auto itemForget = [](const InlineItem *item) {
|
||||||
|
if (DocumentData *document = item->getDocument()) {
|
||||||
|
document->forget();
|
||||||
|
}
|
||||||
|
if (PhotoData *photo = item->getPhoto()) {
|
||||||
|
photo->forget();
|
||||||
|
}
|
||||||
|
if (InlineResult *result = item->getResult()) {
|
||||||
|
if (DocumentData *document = result->document) {
|
||||||
|
document->forget();
|
||||||
|
}
|
||||||
|
if (PhotoData *photo = result->photo) {
|
||||||
|
photo->forget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
clearInlineRows(false);
|
clearInlineRows(false);
|
||||||
for (GifLayouts::const_iterator i = _gifLayouts.cbegin(), e = _gifLayouts.cend(); i != e; ++i) {
|
for_const (InlineItem *item, _gifLayouts) {
|
||||||
i.value()->getDocument()->forget();
|
itemForget(item);
|
||||||
}
|
}
|
||||||
for (InlineLayouts::const_iterator i = _inlineLayouts.cbegin(), e = _inlineLayouts.cend(); i != e; ++i) {
|
for_const (InlineItem *item, _inlineLayouts) {
|
||||||
if (i.value()->getInlineResult()->document) {
|
itemForget(item);
|
||||||
i.value()->getInlineResult()->document->forget();
|
|
||||||
}
|
|
||||||
if (i.value()->getInlineResult()->photo) {
|
|
||||||
i.value()->getInlineResult()->photo->forget();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_setGifCommand && _showingSavedGifs) {
|
if (_setGifCommand && _showingSavedGifs) {
|
||||||
|
@ -1686,7 +1704,7 @@ void StickerPanInner::refreshStickers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StickerPanInner::inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, InlineRow &row, int32 &sumWidth) {
|
bool StickerPanInner::inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, InlineRow &row, int32 &sumWidth) {
|
||||||
LayoutInlineItem *layout = nullptr;
|
InlineItem *layout = nullptr;
|
||||||
if (savedGif) {
|
if (savedGif) {
|
||||||
layout = layoutPrepareSavedGif(savedGif, (_inlineRows.size() * MatrixRowShift) + row.items.size());
|
layout = layoutPrepareSavedGif(savedGif, (_inlineRows.size() * MatrixRowShift) + row.items.size());
|
||||||
} else if (result) {
|
} else if (result) {
|
||||||
|
@ -1711,12 +1729,12 @@ bool StickerPanInner::inlineRowsAddItem(DocumentData *savedGif, InlineResult *re
|
||||||
bool StickerPanInner::inlineRowFinalize(InlineRow &row, int32 &sumWidth, bool force) {
|
bool StickerPanInner::inlineRowFinalize(InlineRow &row, int32 &sumWidth, bool force) {
|
||||||
if (row.items.isEmpty()) return false;
|
if (row.items.isEmpty()) return false;
|
||||||
|
|
||||||
bool full = (row.items.size() >= SavedGifsMaxPerRow);
|
bool full = (row.items.size() >= InlineItemsMaxPerRow);
|
||||||
bool big = (sumWidth >= st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft);
|
bool big = (sumWidth >= st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft);
|
||||||
if (full || big || force) {
|
if (full || big || force) {
|
||||||
_inlineRows.push_back(layoutInlineRow(row, (full || big) ? sumWidth : 0));
|
_inlineRows.push_back(layoutInlineRow(row, (full || big) ? sumWidth : 0));
|
||||||
row = InlineRow();
|
row = InlineRow();
|
||||||
row.items.reserve(SavedGifsMaxPerRow);
|
row.items.reserve(InlineItemsMaxPerRow);
|
||||||
sumWidth = 0;
|
sumWidth = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1735,7 +1753,7 @@ void StickerPanInner::refreshSavedGifs() {
|
||||||
} else {
|
} else {
|
||||||
_inlineRows.reserve(saved.size());
|
_inlineRows.reserve(saved.size());
|
||||||
InlineRow row;
|
InlineRow row;
|
||||||
row.items.reserve(SavedGifsMaxPerRow);
|
row.items.reserve(InlineItemsMaxPerRow);
|
||||||
int32 sumWidth = 0;
|
int32 sumWidth = 0;
|
||||||
for (SavedGifs::const_iterator i = saved.cbegin(), e = saved.cend(); i != e; ++i) {
|
for (SavedGifs::const_iterator i = saved.cbegin(), e = saved.cend(); i != e; ++i) {
|
||||||
inlineRowsAddItem(*i, 0, row, sumWidth);
|
inlineRowsAddItem(*i, 0, row, sumWidth);
|
||||||
|
@ -1779,40 +1797,33 @@ void StickerPanInner::clearInlineRows(bool resultsDeleted) {
|
||||||
_inlineRows.clear();
|
_inlineRows.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutInlineGif *StickerPanInner::layoutPrepareSavedGif(DocumentData *doc, int32 position) {
|
InlineItem *StickerPanInner::layoutPrepareSavedGif(DocumentData *doc, int32 position) {
|
||||||
GifLayouts::const_iterator i = _gifLayouts.constFind(doc);
|
auto i = _gifLayouts.constFind(doc);
|
||||||
if (i == _gifLayouts.cend()) {
|
if (i == _gifLayouts.cend()) {
|
||||||
i = _gifLayouts.insert(doc, new LayoutInlineGif(doc, true));
|
if (auto layout = InlineItem::createLayoutGif(doc)) {
|
||||||
i.value()->initDimensions();
|
i = _gifLayouts.insert(doc, layout.release());
|
||||||
|
i.value()->initDimensions();
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!i.value()->maxWidth()) return 0;
|
if (!i.value()->maxWidth()) return nullptr;
|
||||||
|
|
||||||
i.value()->setPosition(position);
|
i.value()->setPosition(position);
|
||||||
return i.value();
|
return i.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutInlineItem *StickerPanInner::layoutPrepareInlineResult(InlineResult *result, int32 position) {
|
InlineItem *StickerPanInner::layoutPrepareInlineResult(InlineResult *result, int32 position) {
|
||||||
InlineLayouts::const_iterator i = _inlineLayouts.constFind(result);
|
auto i = _inlineLayouts.constFind(result);
|
||||||
if (i == _inlineLayouts.cend()) {
|
if (i == _inlineLayouts.cend()) {
|
||||||
LayoutInlineItem *layout = nullptr;
|
if (auto layout = InlineItem::createLayout(result, _inlineWithThumb)) {
|
||||||
using Type = InlineResult::Type;
|
i = _inlineLayouts.insert(result, layout.release());
|
||||||
switch (result->type) {
|
i.value()->initDimensions();
|
||||||
case Type::Photo: layout = new LayoutInlinePhoto(result); break;
|
} else {
|
||||||
case Type::Audio:
|
return nullptr;
|
||||||
case Type::File: layout = new LayoutInlineFile(result); break;
|
|
||||||
case Type::Video: layout = new LayoutInlineVideo(result); break;
|
|
||||||
case Type::Sticker: layout = new LayoutInlineSticker(result); break;
|
|
||||||
case Type::Gif: layout = new LayoutInlineGif(result); break;
|
|
||||||
case Type::Article:
|
|
||||||
case Type::Contact:
|
|
||||||
case Type::Venue: layout = new LayoutInlineArticle(result, _inlineWithThumb); break;
|
|
||||||
}
|
}
|
||||||
if (!layout) return nullptr;
|
|
||||||
|
|
||||||
i = _inlineLayouts.insert(result, layout);
|
|
||||||
layout->initDimensions();
|
|
||||||
}
|
}
|
||||||
if (!i.value()->maxWidth()) return 0;
|
if (!i.value()->maxWidth()) return nullptr;
|
||||||
|
|
||||||
i.value()->setPosition(position);
|
i.value()->setPosition(position);
|
||||||
return i.value();
|
return i.value();
|
||||||
|
@ -1820,8 +1831,8 @@ LayoutInlineItem *StickerPanInner::layoutPrepareInlineResult(InlineResult *resul
|
||||||
|
|
||||||
void StickerPanInner::deleteUnusedGifLayouts() {
|
void StickerPanInner::deleteUnusedGifLayouts() {
|
||||||
if (_inlineRows.isEmpty() || !_showingSavedGifs) { // delete all
|
if (_inlineRows.isEmpty() || !_showingSavedGifs) { // delete all
|
||||||
for (GifLayouts::const_iterator i = _gifLayouts.cbegin(), e = _gifLayouts.cend(); i != e; ++i) {
|
for_const (const InlineItem *item, _gifLayouts) {
|
||||||
delete i.value();
|
delete item;
|
||||||
}
|
}
|
||||||
_gifLayouts.clear();
|
_gifLayouts.clear();
|
||||||
} else {
|
} else {
|
||||||
|
@ -1838,8 +1849,8 @@ void StickerPanInner::deleteUnusedGifLayouts() {
|
||||||
|
|
||||||
void StickerPanInner::deleteUnusedInlineLayouts() {
|
void StickerPanInner::deleteUnusedInlineLayouts() {
|
||||||
if (_inlineRows.isEmpty() || _showingSavedGifs) { // delete all
|
if (_inlineRows.isEmpty() || _showingSavedGifs) { // delete all
|
||||||
for (InlineLayouts::const_iterator i = _inlineLayouts.cbegin(), e = _inlineLayouts.cend(); i != e; ++i) {
|
for_const (const InlineItem *item, _inlineLayouts) {
|
||||||
delete i.value();
|
delete item;
|
||||||
}
|
}
|
||||||
_inlineLayouts.clear();
|
_inlineLayouts.clear();
|
||||||
} else {
|
} else {
|
||||||
|
@ -1856,11 +1867,11 @@ void StickerPanInner::deleteUnusedInlineLayouts() {
|
||||||
|
|
||||||
StickerPanInner::InlineRow &StickerPanInner::layoutInlineRow(InlineRow &row, int32 sumWidth) {
|
StickerPanInner::InlineRow &StickerPanInner::layoutInlineRow(InlineRow &row, int32 sumWidth) {
|
||||||
int32 count = row.items.size();
|
int32 count = row.items.size();
|
||||||
t_assert(count <= SavedGifsMaxPerRow);
|
t_assert(count <= InlineItemsMaxPerRow);
|
||||||
|
|
||||||
// enumerate items in the order of growing maxWidth()
|
// enumerate items in the order of growing maxWidth()
|
||||||
// for that sort item indices by maxWidth()
|
// for that sort item indices by maxWidth()
|
||||||
int indices[SavedGifsMaxPerRow];
|
int indices[InlineItemsMaxPerRow];
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
indices[i] = i;
|
indices[i] = i;
|
||||||
}
|
}
|
||||||
|
@ -1972,7 +1983,7 @@ int32 StickerPanInner::refreshInlineRows(UserData *bot, const InlineResults &res
|
||||||
if (count) {
|
if (count) {
|
||||||
_inlineRows.reserve(count);
|
_inlineRows.reserve(count);
|
||||||
InlineRow row;
|
InlineRow row;
|
||||||
row.items.reserve(SavedGifsMaxPerRow);
|
row.items.reserve(InlineItemsMaxPerRow);
|
||||||
int32 sumWidth = 0;
|
int32 sumWidth = 0;
|
||||||
for (int32 i = from; i < count; ++i) {
|
for (int32 i = from; i < count; ++i) {
|
||||||
if (inlineRowsAddItem(0, results.at(i), row, sumWidth)) {
|
if (inlineRowsAddItem(0, results.at(i), row, sumWidth)) {
|
||||||
|
@ -1997,7 +2008,7 @@ int32 StickerPanInner::refreshInlineRows(UserData *bot, const InlineResults &res
|
||||||
int32 StickerPanInner::validateExistingInlineRows(const InlineResults &results) {
|
int32 StickerPanInner::validateExistingInlineRows(const InlineResults &results) {
|
||||||
int32 count = results.size(), until = 0, untilrow = 0, untilcol = 0;
|
int32 count = results.size(), until = 0, untilrow = 0, untilcol = 0;
|
||||||
for (; until < count;) {
|
for (; until < count;) {
|
||||||
if (untilrow >= _inlineRows.size() || _inlineRows.at(untilrow).items.at(untilcol)->getInlineResult() != results.at(until)) {
|
if (untilrow >= _inlineRows.size() || _inlineRows.at(untilrow).items.at(untilcol)->getResult() != results.at(until)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
++until;
|
++until;
|
||||||
|
@ -2044,20 +2055,8 @@ int32 StickerPanInner::validateExistingInlineRows(const InlineResults &results)
|
||||||
|
|
||||||
if (_inlineRows.isEmpty()) {
|
if (_inlineRows.isEmpty()) {
|
||||||
_inlineWithThumb = false;
|
_inlineWithThumb = false;
|
||||||
auto hasThumbDisplay = [](InlineResult *inlineResult) -> bool {
|
|
||||||
if (!inlineResult->thumb->isNull()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (inlineResult->type == InlineResult::Type::Contact) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (inlineResult->sendData->hasLocationCoords()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
for (int32 i = until; i < count; ++i) {
|
for (int32 i = until; i < count; ++i) {
|
||||||
if (hasThumbDisplay(results.at(i))) {
|
if (results.at(i)->hasThumbDisplay()) {
|
||||||
_inlineWithThumb = true;
|
_inlineWithThumb = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2066,7 +2065,7 @@ int32 StickerPanInner::validateExistingInlineRows(const InlineResults &results)
|
||||||
return until;
|
return until;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StickerPanInner::ui_repaintInlineItem(const LayoutInlineItem *layout) {
|
void StickerPanInner::ui_repaintInlineItem(const InlineItem *layout) {
|
||||||
uint64 ms = getms();
|
uint64 ms = getms();
|
||||||
if (_lastScrolled + 100 <= ms) {
|
if (_lastScrolled + 100 <= ms) {
|
||||||
update();
|
update();
|
||||||
|
@ -2075,7 +2074,7 @@ void StickerPanInner::ui_repaintInlineItem(const LayoutInlineItem *layout) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StickerPanInner::ui_isInlineItemVisible(const LayoutInlineItem *layout) {
|
bool StickerPanInner::ui_isInlineItemVisible(const InlineItem *layout) {
|
||||||
int32 position = layout->position();
|
int32 position = layout->position();
|
||||||
if (!_showingInlineItems || position < 0) return false;
|
if (!_showingInlineItems || position < 0) return false;
|
||||||
|
|
||||||
|
@ -2614,6 +2613,8 @@ void EmojiSwitchButton::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent)
|
EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent)
|
||||||
, _maxHeight(st::emojiPanMaxHeight)
|
, _maxHeight(st::emojiPanMaxHeight)
|
||||||
, _contentMaxHeight(st::emojiPanMaxHeight)
|
, _contentMaxHeight(st::emojiPanMaxHeight)
|
||||||
|
@ -2708,7 +2709,7 @@ EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent)
|
||||||
connect(&e_inner, SIGNAL(selected(EmojiPtr)), this, SIGNAL(emojiSelected(EmojiPtr)));
|
connect(&e_inner, SIGNAL(selected(EmojiPtr)), this, SIGNAL(emojiSelected(EmojiPtr)));
|
||||||
connect(&s_inner, SIGNAL(selected(DocumentData*)), this, SIGNAL(stickerSelected(DocumentData*)));
|
connect(&s_inner, SIGNAL(selected(DocumentData*)), this, SIGNAL(stickerSelected(DocumentData*)));
|
||||||
connect(&s_inner, SIGNAL(selected(PhotoData*)), this, SIGNAL(photoSelected(PhotoData*)));
|
connect(&s_inner, SIGNAL(selected(PhotoData*)), this, SIGNAL(photoSelected(PhotoData*)));
|
||||||
connect(&s_inner, SIGNAL(selected(InlineResult*,UserData*)), this, SIGNAL(inlineResultSelected(InlineResult*,UserData*)));
|
connect(&s_inner, SIGNAL(selected(InlineBots::Result*,UserData*)), this, SIGNAL(inlineResultSelected(InlineBots::Result*,UserData*)));
|
||||||
|
|
||||||
connect(&s_inner, SIGNAL(emptyInlineRows()), this, SLOT(onEmptyInlineRows()));
|
connect(&s_inner, SIGNAL(emptyInlineRows()), this, SLOT(onEmptyInlineRows()));
|
||||||
|
|
||||||
|
@ -2848,7 +2849,7 @@ void EmojiPan::paintEvent(QPaintEvent *e) {
|
||||||
i += _iconsX.current() / int(st::rbEmoji.width);
|
i += _iconsX.current() / int(st::rbEmoji.width);
|
||||||
x -= _iconsX.current() % int(st::rbEmoji.width);
|
x -= _iconsX.current() % int(st::rbEmoji.width);
|
||||||
for (int32 l = qMin(_icons.size(), i + 8 - skip); i < l; ++i) {
|
for (int32 l = qMin(_icons.size(), i + 8 - skip); i < l; ++i) {
|
||||||
const StickerIcon &s(_icons.at(i));
|
const internal::StickerIcon &s(_icons.at(i));
|
||||||
s.sticker->thumb->load();
|
s.sticker->thumb->load();
|
||||||
QPixmap pix(s.sticker->thumb->pix(s.pixw, s.pixh));
|
QPixmap pix(s.sticker->thumb->pix(s.pixw, s.pixh));
|
||||||
|
|
||||||
|
@ -3393,13 +3394,13 @@ void EmojiPan::stickersInstalled(uint64 setId) {
|
||||||
showStart();
|
showStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiPan::ui_repaintInlineItem(const LayoutInlineItem *layout) {
|
void EmojiPan::ui_repaintInlineItem(const InlineBots::Layout::ItemBase *layout) {
|
||||||
if (_stickersShown && !isHidden()) {
|
if (_stickersShown && !isHidden()) {
|
||||||
s_inner.ui_repaintInlineItem(layout);
|
s_inner.ui_repaintInlineItem(layout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EmojiPan::ui_isInlineItemVisible(const LayoutInlineItem *layout) {
|
bool EmojiPan::ui_isInlineItemVisible(const InlineBots::Layout::ItemBase *layout) {
|
||||||
if (_stickersShown && !isHidden()) {
|
if (_stickersShown && !isHidden()) {
|
||||||
return s_inner.ui_isInlineItemVisible(layout);
|
return s_inner.ui_isInlineItemVisible(layout);
|
||||||
}
|
}
|
||||||
|
@ -3414,9 +3415,9 @@ bool EmojiPan::ui_isInlineItemBeingChosen() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiPan::notify_automaticLoadSettingsChangedGif() {
|
void EmojiPan::notify_automaticLoadSettingsChangedGif() {
|
||||||
for (InlineCache::const_iterator i = _inlineCache.cbegin(), ei = _inlineCache.cend(); i != ei; ++i) {
|
for_const (const InlineCacheEntry *entry, _inlineCache) {
|
||||||
for (InlineResults::const_iterator j = i.value()->results.cbegin(), ej = i.value()->results.cend(); j != ej; ++j) {
|
for_const (InlineBots::Result *l, entry->results) {
|
||||||
(*j)->automaticLoadSettingsChangedGif();
|
l->automaticLoadSettingsChangedGif();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3475,7 +3476,7 @@ void EmojiPan::onTabChange() {
|
||||||
e_inner.showEmojiPack(newTab);
|
e_inner.showEmojiPack(newTab);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiPan::updatePanelsPositions(const QVector<EmojiPanel*> &panels, int32 st) {
|
void EmojiPan::updatePanelsPositions(const QVector<internal::EmojiPanel*> &panels, int32 st) {
|
||||||
for (int32 i = 0, l = panels.size(); i < l; ++i) {
|
for (int32 i = 0, l = panels.size(); i < l; ++i) {
|
||||||
int32 y = panels.at(i)->wantedY() - st;
|
int32 y = panels.at(i)->wantedY() - st;
|
||||||
if (y < 0) {
|
if (y < 0) {
|
||||||
|
@ -3655,6 +3656,13 @@ bool EmojiPan::hideOnNoInlineResults() {
|
||||||
return _inlineBot && _stickersShown && s_inner.inlineResultsShown() && (_shownFromInlineQuery || _inlineBot->username != cInlineGifBotUsername());
|
return _inlineBot && _stickersShown && s_inner.inlineResultsShown() && (_shownFromInlineQuery || _inlineBot->username != cInlineGifBotUsername());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmojiPan::InlineCacheEntry::clearResults() {
|
||||||
|
for_const (const InlineBots::Result *result, results) {
|
||||||
|
delete result;
|
||||||
|
}
|
||||||
|
results.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void EmojiPan::inlineBotChanged() {
|
void EmojiPan::inlineBotChanged() {
|
||||||
if (!_inlineBot) return;
|
if (!_inlineBot) return;
|
||||||
|
|
||||||
|
@ -3677,7 +3685,7 @@ void EmojiPan::inlineBotChanged() {
|
||||||
|
|
||||||
Notify::inlineBotRequesting(false);
|
Notify::inlineBotRequesting(false);
|
||||||
}
|
}
|
||||||
|
#include <memory>
|
||||||
void EmojiPan::inlineResultsDone(const MTPmessages_BotResults &result) {
|
void EmojiPan::inlineResultsDone(const MTPmessages_BotResults &result) {
|
||||||
_inlineRequestId = 0;
|
_inlineRequestId = 0;
|
||||||
Notify::inlineBotRequesting(false);
|
Notify::inlineBotRequesting(false);
|
||||||
|
@ -3699,105 +3707,11 @@ void EmojiPan::inlineResultsDone(const MTPmessages_BotResults &result) {
|
||||||
if (count) {
|
if (count) {
|
||||||
it.value()->results.reserve(it.value()->results.size() + count);
|
it.value()->results.reserve(it.value()->results.size() + count);
|
||||||
}
|
}
|
||||||
auto inlineResultTypes = InlineResult::getTypesMap();
|
|
||||||
auto getInlineResultType = [&inlineResultTypes](const MTPBotInlineResult &inlineResult) -> InlineResult::Type {
|
|
||||||
QString type;
|
|
||||||
switch (inlineResult.type()) {
|
|
||||||
case mtpc_botInlineResult: type = qs(inlineResult.c_botInlineResult().vtype); break;
|
|
||||||
case mtpc_botInlineMediaResult: type = qs(inlineResult.c_botInlineMediaResult().vtype); break;
|
|
||||||
}
|
|
||||||
return inlineResultTypes.value(type, InlineResult::Type::Unknown);
|
|
||||||
};
|
|
||||||
for (int32 i = 0; i < count; ++i) {
|
for (int32 i = 0; i < count; ++i) {
|
||||||
InlineResult::Type type = getInlineResultType(v.at(i));
|
if (UniquePointer<InlineBots::Result> result = InlineBots::Result::create(queryId, v.at(i))) {
|
||||||
if (type == InlineResult::Type::Unknown) continue;
|
++added;
|
||||||
|
it.value()->results.push_back(result.release());
|
||||||
UniquePointer<InlineResult> result = MakeUnique<InlineResult>(queryId, type);
|
|
||||||
|
|
||||||
const MTPBotInlineMessage *message = nullptr;
|
|
||||||
switch (v.at(i).type()) {
|
|
||||||
case mtpc_botInlineResult: {
|
|
||||||
const MTPDbotInlineResult &r(v.at(i).c_botInlineResult());
|
|
||||||
result->id = qs(r.vid);
|
|
||||||
if (r.has_title()) result->title = qs(r.vtitle);
|
|
||||||
if (r.has_description()) result->description = qs(r.vdescription);
|
|
||||||
if (r.has_url()) result->url = qs(r.vurl);
|
|
||||||
if (r.has_thumb_url()) result->thumb_url = qs(r.vthumb_url);
|
|
||||||
if (r.has_content_type()) result->content_type = qs(r.vcontent_type);
|
|
||||||
if (r.has_content_url()) result->content_url = qs(r.vcontent_url);
|
|
||||||
if (r.has_w()) result->width = r.vw.v;
|
|
||||||
if (r.has_h()) result->height = r.vh.v;
|
|
||||||
if (r.has_duration()) result->duration = r.vduration.v;
|
|
||||||
if (!result->thumb_url.isEmpty() && (result->thumb_url.startsWith(qstr("http://"), Qt::CaseInsensitive) || result->thumb_url.startsWith(qstr("https://"), Qt::CaseInsensitive))) {
|
|
||||||
result->thumb = ImagePtr(result->thumb_url);
|
|
||||||
}
|
|
||||||
message = &r.vsend_message;
|
|
||||||
} break;
|
|
||||||
case mtpc_botInlineMediaResult: {
|
|
||||||
const MTPDbotInlineMediaResult &r(v.at(i).c_botInlineMediaResult());
|
|
||||||
result->id = qs(r.vid);
|
|
||||||
if (r.has_title()) result->title = qs(r.vtitle);
|
|
||||||
if (r.has_description()) result->description = qs(r.vdescription);
|
|
||||||
if (r.has_photo()) result->photo = App::feedPhoto(r.vphoto);
|
|
||||||
if (r.has_document()) result->document = App::feedDocument(r.vdocument);
|
|
||||||
message = &r.vsend_message;
|
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
bool badAttachment = (result->photo && !result->photo->access) || (result->document && !result->document->access);
|
|
||||||
|
|
||||||
if (!message) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
switch (message->type()) {
|
|
||||||
case mtpc_botInlineMessageMediaAuto: {
|
|
||||||
const MTPDbotInlineMessageMediaAuto &r(message->c_botInlineMessageMediaAuto());
|
|
||||||
if (result->type == InlineResult::Type::Photo) {
|
|
||||||
result->sendData.reset(new InlineResultSendPhoto(result->photo, result->content_url, qs(r.vcaption)));
|
|
||||||
} else {
|
|
||||||
result->sendData.reset(new InlineResultSendFile(result->document, result->content_url, qs(r.vcaption)));
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case mtpc_botInlineMessageText: {
|
|
||||||
const MTPDbotInlineMessageText &r(message->c_botInlineMessageText());
|
|
||||||
EntitiesInText entities = r.has_entities() ? entitiesFromMTP(r.ventities.c_vector().v) : EntitiesInText();
|
|
||||||
result->sendData.reset(new InlineResultSendText(qs(r.vmessage), entities, r.is_no_webpage()));
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case mtpc_botInlineMessageMediaGeo: {
|
|
||||||
const MTPDbotInlineMessageMediaGeo &r(message->c_botInlineMessageMediaGeo());
|
|
||||||
if (r.vgeo.type() == mtpc_geoPoint) {
|
|
||||||
result->sendData.reset(new InlineResultSendGeo(r.vgeo.c_geoPoint()));
|
|
||||||
} else {
|
|
||||||
badAttachment = true;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case mtpc_botInlineMessageMediaVenue: {
|
|
||||||
const MTPDbotInlineMessageMediaVenue &r(message->c_botInlineMessageMediaVenue());
|
|
||||||
if (r.vgeo.type() == mtpc_geoPoint) {
|
|
||||||
result->sendData.reset(new InlineResultSendVenue(r.vgeo.c_geoPoint(), qs(r.vvenue_id), qs(r.vprovider), qs(r.vtitle), qs(r.vaddress)));
|
|
||||||
} else {
|
|
||||||
badAttachment = true;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case mtpc_botInlineMessageMediaContact: {
|
|
||||||
const MTPDbotInlineMessageMediaContact &r(message->c_botInlineMessageMediaContact());
|
|
||||||
result->sendData.reset(new InlineResultSendContact(qs(r.vfirst_name), qs(r.vlast_name), qs(r.vphone_number)));
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default: {
|
|
||||||
badAttachment = true;
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (badAttachment || !result->sendData || !result->sendData->isValid()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
++added;
|
|
||||||
it.value()->results.push_back(result.release());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!added) {
|
if (!added) {
|
||||||
|
@ -3885,7 +3799,7 @@ bool EmojiPan::refreshInlineRows(int32 *added) {
|
||||||
_inlineNextOffset = i.value()->nextOffset;
|
_inlineNextOffset = i.value()->nextOffset;
|
||||||
}
|
}
|
||||||
if (clear) prepareShowHideCache();
|
if (clear) prepareShowHideCache();
|
||||||
int32 result = s_inner.refreshInlineRows(_inlineBot, clear ? InlineResults() : i.value()->results, false);
|
int32 result = s_inner.refreshInlineRows(_inlineBot, clear ? internal::InlineResults() : i.value()->results, false);
|
||||||
if (added) *added = result;
|
if (added) *added = result;
|
||||||
return !clear;
|
return !clear;
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,8 +157,21 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class EmojiPanel;
|
namespace InlineBots {
|
||||||
static const int EmojiColorsCount = 5;
|
namespace Layout {
|
||||||
|
class ItemBase;
|
||||||
|
} // namespace Layout
|
||||||
|
class Result;
|
||||||
|
} // namespace InlineBots
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
static constexpr int InlineItemsMaxPerRow = 5;
|
||||||
|
static constexpr int EmojiColorsCount = 5;
|
||||||
|
|
||||||
|
using InlineResult = InlineBots::Result;
|
||||||
|
using InlineResults = QList<InlineBots::Result*>;
|
||||||
|
using InlineItem = InlineBots::Layout::ItemBase;
|
||||||
|
|
||||||
class EmojiColorPicker : public TWidget {
|
class EmojiColorPicker : public TWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -222,6 +235,7 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class EmojiPanel;
|
||||||
class EmojiPanInner : public TWidget {
|
class EmojiPanInner : public TWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -314,8 +328,6 @@ struct StickerIcon {
|
||||||
int32 pixw, pixh;
|
int32 pixw, pixh;
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr int SavedGifsMaxPerRow = 5;
|
|
||||||
|
|
||||||
class StickerPanInner : public TWidget {
|
class StickerPanInner : public TWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -361,8 +373,8 @@ public:
|
||||||
|
|
||||||
uint64 currentSet(int yOffset) const;
|
uint64 currentSet(int yOffset) const;
|
||||||
|
|
||||||
void ui_repaintInlineItem(const LayoutInlineItem *layout);
|
void ui_repaintInlineItem(const InlineItem *layout);
|
||||||
bool ui_isInlineItemVisible(const LayoutInlineItem *layout);
|
bool ui_isInlineItemVisible(const InlineItem *layout);
|
||||||
bool ui_isInlineItemBeingChosen();
|
bool ui_isInlineItemBeingChosen();
|
||||||
|
|
||||||
bool inlineResultsShown() const {
|
bool inlineResultsShown() const {
|
||||||
|
@ -370,11 +382,7 @@ public:
|
||||||
}
|
}
|
||||||
int32 countHeight(bool plain = false);
|
int32 countHeight(bool plain = false);
|
||||||
|
|
||||||
~StickerPanInner() {
|
~StickerPanInner();
|
||||||
clearInlineRows(true);
|
|
||||||
deleteUnusedGifLayouts();
|
|
||||||
deleteUnusedInlineLayouts();
|
|
||||||
}
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
|
@ -387,7 +395,7 @@ signals:
|
||||||
|
|
||||||
void selected(DocumentData *sticker);
|
void selected(DocumentData *sticker);
|
||||||
void selected(PhotoData *photo);
|
void selected(PhotoData *photo);
|
||||||
void selected(InlineResult *result, UserData *bot);
|
void selected(InlineBots::Result *result, UserData *bot);
|
||||||
|
|
||||||
void removing(quint64 setId);
|
void removing(quint64 setId);
|
||||||
|
|
||||||
|
@ -441,7 +449,7 @@ private:
|
||||||
QTimer _updateInlineItems;
|
QTimer _updateInlineItems;
|
||||||
bool _inlineWithThumb;
|
bool _inlineWithThumb;
|
||||||
|
|
||||||
typedef QVector<LayoutInlineItem*> InlineItems;
|
typedef QVector<InlineItem*> InlineItems;
|
||||||
struct InlineRow {
|
struct InlineRow {
|
||||||
InlineRow() : height(0) {
|
InlineRow() : height(0) {
|
||||||
}
|
}
|
||||||
|
@ -452,13 +460,13 @@ private:
|
||||||
InlineRows _inlineRows;
|
InlineRows _inlineRows;
|
||||||
void clearInlineRows(bool resultsDeleted);
|
void clearInlineRows(bool resultsDeleted);
|
||||||
|
|
||||||
typedef QMap<DocumentData*, LayoutInlineGif*> GifLayouts;
|
using GifLayouts = QMap<DocumentData*, InlineItem*>;
|
||||||
GifLayouts _gifLayouts;
|
GifLayouts _gifLayouts;
|
||||||
LayoutInlineGif *layoutPrepareSavedGif(DocumentData *doc, int32 position);
|
InlineItem *layoutPrepareSavedGif(DocumentData *doc, int32 position);
|
||||||
|
|
||||||
typedef QMap<InlineResult*, LayoutInlineItem*> InlineLayouts;
|
using InlineLayouts = QMap<InlineResult*, InlineItem*>;
|
||||||
InlineLayouts _inlineLayouts;
|
InlineLayouts _inlineLayouts;
|
||||||
LayoutInlineItem *layoutPrepareInlineResult(InlineResult *result, int32 position);
|
InlineItem *layoutPrepareInlineResult(InlineResult *result, int32 position);
|
||||||
|
|
||||||
bool inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, InlineRow &row, int32 &sumWidth);
|
bool inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, InlineRow &row, int32 &sumWidth);
|
||||||
bool inlineRowFinalize(InlineRow &row, int32 &sumWidth, bool force = false);
|
bool inlineRowFinalize(InlineRow &row, int32 &sumWidth, bool force = false);
|
||||||
|
@ -533,6 +541,8 @@ protected:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
class EmojiPan : public TWidget, public RPCSender {
|
class EmojiPan : public TWidget, public RPCSender {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -581,8 +591,8 @@ public:
|
||||||
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
|
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ui_repaintInlineItem(const LayoutInlineItem *layout);
|
void ui_repaintInlineItem(const InlineBots::Layout::ItemBase *layout);
|
||||||
bool ui_isInlineItemVisible(const LayoutInlineItem *layout);
|
bool ui_isInlineItemVisible(const InlineBots::Layout::ItemBase *layout);
|
||||||
bool ui_isInlineItemBeingChosen();
|
bool ui_isInlineItemBeingChosen();
|
||||||
|
|
||||||
bool inlineResultsShown() const {
|
bool inlineResultsShown() const {
|
||||||
|
@ -623,7 +633,7 @@ signals:
|
||||||
void emojiSelected(EmojiPtr emoji);
|
void emojiSelected(EmojiPtr emoji);
|
||||||
void stickerSelected(DocumentData *sticker);
|
void stickerSelected(DocumentData *sticker);
|
||||||
void photoSelected(PhotoData *photo);
|
void photoSelected(PhotoData *photo);
|
||||||
void inlineResultSelected(InlineResult *result, UserData *bot);
|
void inlineResultSelected(InlineBots::Result *result, UserData *bot);
|
||||||
|
|
||||||
void updateStickers();
|
void updateStickers();
|
||||||
|
|
||||||
|
@ -643,7 +653,7 @@ private:
|
||||||
void updateIcons();
|
void updateIcons();
|
||||||
|
|
||||||
void prepareTab(int32 &left, int32 top, int32 _width, FlatRadiobutton &tab);
|
void prepareTab(int32 &left, int32 top, int32 _width, FlatRadiobutton &tab);
|
||||||
void updatePanelsPositions(const QVector<EmojiPanel*> &panels, int32 st);
|
void updatePanelsPositions(const QVector<internal::EmojiPanel*> &panels, int32 st);
|
||||||
|
|
||||||
void showAll();
|
void showAll();
|
||||||
void hideAll();
|
void hideAll();
|
||||||
|
@ -662,7 +672,7 @@ private:
|
||||||
BoxShadow _shadow;
|
BoxShadow _shadow;
|
||||||
|
|
||||||
FlatRadiobutton _recent, _people, _nature, _food, _activity, _travel, _objects, _symbols;
|
FlatRadiobutton _recent, _people, _nature, _food, _activity, _travel, _objects, _symbols;
|
||||||
QList<StickerIcon> _icons;
|
QList<internal::StickerIcon> _icons;
|
||||||
QVector<float64> _iconHovers;
|
QVector<float64> _iconHovers;
|
||||||
int32 _iconOver, _iconSel, _iconDown;
|
int32 _iconOver, _iconSel, _iconDown;
|
||||||
bool _iconsDragging;
|
bool _iconsDragging;
|
||||||
|
@ -682,13 +692,13 @@ private:
|
||||||
Animation _a_slide;
|
Animation _a_slide;
|
||||||
|
|
||||||
ScrollArea e_scroll;
|
ScrollArea e_scroll;
|
||||||
EmojiPanInner e_inner;
|
internal::EmojiPanInner e_inner;
|
||||||
QVector<EmojiPanel*> e_panels;
|
QVector<internal::EmojiPanel*> e_panels;
|
||||||
EmojiSwitchButton e_switch;
|
internal::EmojiSwitchButton e_switch;
|
||||||
ScrollArea s_scroll;
|
ScrollArea s_scroll;
|
||||||
StickerPanInner s_inner;
|
internal::StickerPanInner s_inner;
|
||||||
QVector<EmojiPanel*> s_panels;
|
QVector<internal::EmojiPanel*> s_panels;
|
||||||
EmojiSwitchButton s_switch;
|
internal::EmojiSwitchButton s_switch;
|
||||||
|
|
||||||
uint64 _removingSetId;
|
uint64 _removingSetId;
|
||||||
|
|
||||||
|
@ -700,13 +710,8 @@ private:
|
||||||
clearResults();
|
clearResults();
|
||||||
}
|
}
|
||||||
QString nextOffset;
|
QString nextOffset;
|
||||||
InlineResults results;
|
internal::InlineResults results;
|
||||||
void clearResults() {
|
void clearResults();
|
||||||
for (int32 i = 0, l = results.size(); i < l; ++i) {
|
|
||||||
delete results.at(i);
|
|
||||||
}
|
|
||||||
results.clear();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
typedef QMap<QString, InlineCacheEntry*> InlineCache;
|
typedef QMap<QString, InlineCacheEntry*> InlineCache;
|
||||||
InlineCache _inlineCache;
|
InlineCache _inlineCache;
|
||||||
|
|
|
@ -175,12 +175,12 @@ namespace Ui {
|
||||||
if (MainWidget *m = App::main()) m->ui_repaintHistoryItem(item);
|
if (MainWidget *m = App::main()) m->ui_repaintHistoryItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
void repaintInlineItem(const LayoutInlineItem *layout) {
|
void repaintInlineItem(const InlineBots::Layout::ItemBase *layout) {
|
||||||
if (!layout) return;
|
if (!layout) return;
|
||||||
if (MainWidget *m = App::main()) m->ui_repaintInlineItem(layout);
|
if (MainWidget *m = App::main()) m->ui_repaintInlineItem(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isInlineItemVisible(const LayoutInlineItem *layout) {
|
bool isInlineItemVisible(const InlineBots::Layout::ItemBase *layout) {
|
||||||
if (MainWidget *m = App::main()) return m->ui_isInlineItemVisible(layout);
|
if (MainWidget *m = App::main()) return m->ui_isInlineItemVisible(layout);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,14 @@ namespace App {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace InlineBots {
|
||||||
|
namespace Layout {
|
||||||
|
|
||||||
|
class ItemBase;
|
||||||
|
|
||||||
|
} // namespace Layout
|
||||||
|
} // namespace InlineBots
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
|
||||||
void showStickerPreview(DocumentData *sticker);
|
void showStickerPreview(DocumentData *sticker);
|
||||||
|
@ -55,8 +63,8 @@ namespace Ui {
|
||||||
bool isInlineItemBeingChosen();
|
bool isInlineItemBeingChosen();
|
||||||
|
|
||||||
void repaintHistoryItem(const HistoryItem *item);
|
void repaintHistoryItem(const HistoryItem *item);
|
||||||
void repaintInlineItem(const LayoutInlineItem *layout);
|
void repaintInlineItem(const InlineBots::Layout::ItemBase *layout);
|
||||||
bool isInlineItemVisible(const LayoutInlineItem *reader);
|
bool isInlineItemVisible(const InlineBots::Layout::ItemBase *reader);
|
||||||
void autoplayMediaInlineAsync(const FullMsgId &msgId);
|
void autoplayMediaInlineAsync(const FullMsgId &msgId);
|
||||||
|
|
||||||
void showPeerHistory(const PeerId &peer, MsgId msgId, bool back = false);
|
void showPeerHistory(const PeerId &peer, MsgId msgId, bool back = false);
|
||||||
|
|
|
@ -19,9 +19,9 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "gui/style.h"
|
|
||||||
|
|
||||||
#include "flattextarea.h"
|
#include "flattextarea.h"
|
||||||
|
|
||||||
|
#include "gui/style.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
|
|
||||||
FlatTextarea::FlatTextarea(QWidget *parent, const style::flatTextarea &st, const QString &pholder, const QString &v) : QTextEdit(parent)
|
FlatTextarea::FlatTextarea(QWidget *parent, const style::flatTextarea &st, const QString &pholder, const QString &v) : QTextEdit(parent)
|
||||||
|
@ -298,10 +298,10 @@ QString FlatTextarea::getInlineBotQuery(UserData *&inlineBot, QString &inlineBot
|
||||||
inlineBot = 0;
|
inlineBot = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
inlineBot = InlineBotLookingUpData;
|
inlineBot = LookingUpInlineBot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (inlineBot == InlineBotLookingUpData) return QString();
|
if (inlineBot == LookingUpInlineBot) return QString();
|
||||||
|
|
||||||
if (inlineBot && (!inlineBot->botInfo || inlineBot->botInfo->inlinePlaceholder.isEmpty())) {
|
if (inlineBot && (!inlineBot->botInfo || inlineBot->botInfo->inlinePlaceholder.isEmpty())) {
|
||||||
inlineBot = 0;
|
inlineBot = 0;
|
||||||
|
|
|
@ -25,6 +25,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "animation.h"
|
#include "animation.h"
|
||||||
|
|
||||||
class UserData;
|
class UserData;
|
||||||
|
static UserData * const LookingUpInlineBot = SharedMemoryLocation<UserData, 0>();
|
||||||
|
|
||||||
class FlatTextarea : public QTextEdit {
|
class FlatTextarea : public QTextEdit {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
T_WIDGET
|
T_WIDGET
|
||||||
|
|
|
@ -555,6 +555,14 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline TextClickHandlerPtr clickHandlerFromUrl(const QString &url) {
|
||||||
|
int32 at = url.indexOf('@'), slash = url.indexOf('/');
|
||||||
|
if ((at > 0) && (slash < 0 || slash > at)) {
|
||||||
|
return MakeShared<EmailClickHandler>(url);
|
||||||
|
}
|
||||||
|
return MakeShared<UrlClickHandler>(url);
|
||||||
|
}
|
||||||
|
|
||||||
struct LocationCoords {
|
struct LocationCoords {
|
||||||
LocationCoords() : lat(0), lon(0) {
|
LocationCoords() : lat(0), lon(0) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,21 +19,21 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "gui/style.h"
|
|
||||||
#include "lang.h"
|
|
||||||
|
|
||||||
#include "application.h"
|
|
||||||
#include "boxes/confirmbox.h"
|
|
||||||
#include "historywidget.h"
|
#include "historywidget.h"
|
||||||
#include "gui/filedialog.h"
|
|
||||||
|
#include "boxes/confirmbox.h"
|
||||||
#include "boxes/photosendbox.h"
|
#include "boxes/photosendbox.h"
|
||||||
|
#include "gui/filedialog.h"
|
||||||
|
#include "gui/style.h"
|
||||||
|
#include "inline_bots/inline_bot_result.h"
|
||||||
|
#include "lang.h"
|
||||||
|
#include "application.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "passcodewidget.h"
|
#include "passcodewidget.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "fileuploader.h"
|
#include "fileuploader.h"
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
|
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
|
|
||||||
// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
|
// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
|
||||||
|
@ -2733,7 +2733,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
|
||||||
connect(&_emojiPan, SIGNAL(emojiSelected(EmojiPtr)), &_field, SLOT(onEmojiInsert(EmojiPtr)));
|
connect(&_emojiPan, SIGNAL(emojiSelected(EmojiPtr)), &_field, SLOT(onEmojiInsert(EmojiPtr)));
|
||||||
connect(&_emojiPan, SIGNAL(stickerSelected(DocumentData*)), this, SLOT(onStickerSend(DocumentData*)));
|
connect(&_emojiPan, SIGNAL(stickerSelected(DocumentData*)), this, SLOT(onStickerSend(DocumentData*)));
|
||||||
connect(&_emojiPan, SIGNAL(photoSelected(PhotoData*)), this, SLOT(onPhotoSend(PhotoData*)));
|
connect(&_emojiPan, SIGNAL(photoSelected(PhotoData*)), this, SLOT(onPhotoSend(PhotoData*)));
|
||||||
connect(&_emojiPan, SIGNAL(inlineResultSelected(InlineResult*,UserData*)), this, SLOT(onInlineResultSend(InlineResult*,UserData*)));
|
connect(&_emojiPan, SIGNAL(inlineResultSelected(InlineBots::Result*,UserData*)), this, SLOT(onInlineResultSend(InlineBots::Result*,UserData*)));
|
||||||
connect(&_emojiPan, SIGNAL(updateStickers()), this, SLOT(updateStickers()));
|
connect(&_emojiPan, SIGNAL(updateStickers()), this, SLOT(updateStickers()));
|
||||||
connect(&_sendActionStopTimer, SIGNAL(timeout()), this, SLOT(onCancelSendAction()));
|
connect(&_sendActionStopTimer, SIGNAL(timeout()), this, SLOT(onCancelSendAction()));
|
||||||
connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreviewTimeout()));
|
connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreviewTimeout()));
|
||||||
|
@ -2861,12 +2861,12 @@ void HistoryWidget::updateInlineBotQuery() {
|
||||||
MTP::cancel(_inlineBotResolveRequestId);
|
MTP::cancel(_inlineBotResolveRequestId);
|
||||||
_inlineBotResolveRequestId = 0;
|
_inlineBotResolveRequestId = 0;
|
||||||
}
|
}
|
||||||
if (_inlineBot == InlineBotLookingUpData) {
|
if (_inlineBot == LookingUpInlineBot) {
|
||||||
// Notify::inlineBotRequesting(true);
|
// Notify::inlineBotRequesting(true);
|
||||||
_inlineBotResolveRequestId = MTP::send(MTPcontacts_ResolveUsername(MTP_string(_inlineBotUsername)), rpcDone(&HistoryWidget::inlineBotResolveDone), rpcFail(&HistoryWidget::inlineBotResolveFail, _inlineBotUsername));
|
_inlineBotResolveRequestId = MTP::send(MTPcontacts_ResolveUsername(MTP_string(_inlineBotUsername)), rpcDone(&HistoryWidget::inlineBotResolveDone), rpcFail(&HistoryWidget::inlineBotResolveFail, _inlineBotUsername));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (_inlineBot == InlineBotLookingUpData) {
|
} else if (_inlineBot == LookingUpInlineBot) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5748,7 +5748,7 @@ void HistoryWidget::updateFieldPlaceholder() {
|
||||||
_field.setPlaceholder(lang(lng_edit_message_text));
|
_field.setPlaceholder(lang(lng_edit_message_text));
|
||||||
_send.setText(lang(lng_settings_save));
|
_send.setText(lang(lng_settings_save));
|
||||||
} else {
|
} else {
|
||||||
if (_inlineBot && _inlineBot != InlineBotLookingUpData) {
|
if (_inlineBot && _inlineBot != LookingUpInlineBot) {
|
||||||
_field.setPlaceholder(_inlineBot->botInfo->inlinePlaceholder.mid(1), _inlineBot->username.size() + 2);
|
_field.setPlaceholder(_inlineBot->botInfo->inlinePlaceholder.mid(1), _inlineBot->username.size() + 2);
|
||||||
} else if (hasBroadcastToggle()) {
|
} else if (hasBroadcastToggle()) {
|
||||||
_field.setPlaceholder(lang(_broadcast.checked() ? (_silent.checked() ? lng_broadcast_silent_ph : lng_broadcast_ph) : lng_comment_ph));
|
_field.setPlaceholder(lang(_broadcast.checked() ? (_silent.checked() ? lng_broadcast_silent_ph : lng_broadcast_ph) : lng_comment_ph));
|
||||||
|
@ -6172,11 +6172,11 @@ void HistoryWidget::onUpdateHistoryItems() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::ui_repaintInlineItem(const LayoutInlineItem *layout) {
|
void HistoryWidget::ui_repaintInlineItem(const InlineBots::Layout::ItemBase *layout) {
|
||||||
_emojiPan.ui_repaintInlineItem(layout);
|
_emojiPan.ui_repaintInlineItem(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HistoryWidget::ui_isInlineItemVisible(const LayoutInlineItem *layout) {
|
bool HistoryWidget::ui_isInlineItemVisible(const InlineBots::Layout::ItemBase *layout) {
|
||||||
return _emojiPan.ui_isInlineItemVisible(layout);
|
return _emojiPan.ui_isInlineItemVisible(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6729,7 +6729,7 @@ void HistoryWidget::onPhotoSend(PhotoData *photo) {
|
||||||
sendExistingPhoto(photo, QString());
|
sendExistingPhoto(photo, QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::onInlineResultSend(InlineResult *result, UserData *bot) {
|
void HistoryWidget::onInlineResultSend(InlineBots::Result *result, UserData *bot) {
|
||||||
if (!_history || !result || !canSendMessages(_peer)) return;
|
if (!_history || !result || !canSendMessages(_peer)) return;
|
||||||
|
|
||||||
App::main()->readServerHistory(_history, false);
|
App::main()->readServerHistory(_history, false);
|
||||||
|
@ -6769,17 +6769,8 @@ void HistoryWidget::onInlineResultSend(InlineResult *result, UserData *bot) {
|
||||||
MTPint messageDate = MTP_int(unixtime());
|
MTPint messageDate = MTP_int(unixtime());
|
||||||
UserId messageViaBotId = bot ? peerToUser(bot->id) : 0;
|
UserId messageViaBotId = bot ? peerToUser(bot->id) : 0;
|
||||||
MsgId messageId = newId.msg;
|
MsgId messageId = newId.msg;
|
||||||
if (DocumentData *document = result->sendData->getSentDocument()) {
|
|
||||||
_history->addNewDocument(messageId, flags, messageViaBotId, replyToId(), date(messageDate), messageFromId, document, result->sendData->getSentCaption());
|
result->addToHistory(_history, flags, messageId, messageFromId, messageDate, messageViaBotId, replyToId());
|
||||||
} else if (PhotoData *photo = result->sendData->getSentPhoto()) {
|
|
||||||
_history->addNewPhoto(messageId, flags, messageViaBotId, replyToId(), date(messageDate), messageFromId, photo, result->sendData->getSentCaption());
|
|
||||||
} else {
|
|
||||||
InlineResultSendData::SentMTPMessageFields fields = result->sendData->getSentMessageFields(result);
|
|
||||||
if (!fields.entities.c_vector().v.isEmpty()) {
|
|
||||||
flags |= MTPDmessage::Flag::f_entities;
|
|
||||||
}
|
|
||||||
_history->addNewMessage(MTP_message(MTP_flags(flags), MTP_int(messageId), MTP_int(messageFromId), peerToMTP(_history->peer->id), MTPnullFwdHeader, MTP_int(messageViaBotId), MTP_int(replyToId()), messageDate, fields.text, fields.media, MTPnullMarkup, fields.entities, MTP_int(1), MTPint()), NewMessageUnread);
|
|
||||||
}
|
|
||||||
|
|
||||||
_history->sendRequestId = MTP::send(MTPmessages_SendInlineBotResult(MTP_flags(sendFlags), _peer->input, MTP_int(replyToId()), MTP_long(randomId), MTP_long(result->queryId), MTP_string(result->id)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), 0, 0, _history->sendRequestId);
|
_history->sendRequestId = MTP::send(MTPmessages_SendInlineBotResult(MTP_flags(sendFlags), _peer->input, MTP_int(replyToId()), MTP_long(randomId), MTP_long(result->queryId), MTP_string(result->id)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), 0, 0, _history->sendRequestId);
|
||||||
App::main()->finishForwarding(_history, _broadcast.checked(), _silent.checked());
|
App::main()->finishForwarding(_history, _broadcast.checked(), _silent.checked());
|
||||||
|
|
|
@ -473,6 +473,17 @@ enum TextUpdateEventsFlags {
|
||||||
TextUpdateEventsSendTyping = 0x02,
|
TextUpdateEventsSendTyping = 0x02,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace InlineBots {
|
||||||
|
namespace Layout {
|
||||||
|
|
||||||
|
class ItemBase;
|
||||||
|
|
||||||
|
} // namespace Layout
|
||||||
|
|
||||||
|
class Result;
|
||||||
|
|
||||||
|
} // namespace InlineBots
|
||||||
|
|
||||||
class HistoryWidget : public TWidget, public RPCSender {
|
class HistoryWidget : public TWidget, public RPCSender {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -653,8 +664,8 @@ public:
|
||||||
bool isItemVisible(HistoryItem *item);
|
bool isItemVisible(HistoryItem *item);
|
||||||
|
|
||||||
void ui_repaintHistoryItem(const HistoryItem *item);
|
void ui_repaintHistoryItem(const HistoryItem *item);
|
||||||
void ui_repaintInlineItem(const LayoutInlineItem *gif);
|
void ui_repaintInlineItem(const InlineBots::Layout::ItemBase *gif);
|
||||||
bool ui_isInlineItemVisible(const LayoutInlineItem *layout);
|
bool ui_isInlineItemVisible(const InlineBots::Layout::ItemBase *layout);
|
||||||
bool ui_isInlineItemBeingChosen();
|
bool ui_isInlineItemBeingChosen();
|
||||||
PeerData *ui_getPeerForMouseAction();
|
PeerData *ui_getPeerForMouseAction();
|
||||||
|
|
||||||
|
@ -745,7 +756,7 @@ public slots:
|
||||||
void onFieldTabbed();
|
void onFieldTabbed();
|
||||||
void onStickerSend(DocumentData *sticker);
|
void onStickerSend(DocumentData *sticker);
|
||||||
void onPhotoSend(PhotoData *photo);
|
void onPhotoSend(PhotoData *photo);
|
||||||
void onInlineResultSend(InlineResult *result, UserData *bot);
|
void onInlineResultSend(InlineBots::Result *result, UserData *bot);
|
||||||
|
|
||||||
void onWindowVisibleChanged();
|
void onWindowVisibleChanged();
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,325 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "inline_bots/inline_bot_layout_item.h"
|
||||||
|
#include "gui/text.h"
|
||||||
|
|
||||||
|
namespace InlineBots {
|
||||||
|
namespace Layout {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
class FileBase : public ItemBase {
|
||||||
|
public:
|
||||||
|
FileBase(Result *result);
|
||||||
|
// for saved gif layouts
|
||||||
|
FileBase(DocumentData *doc);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
DocumentData *getShownDocument() const;
|
||||||
|
|
||||||
|
int content_width() const;
|
||||||
|
int content_height() const;
|
||||||
|
bool content_loading() const;
|
||||||
|
bool content_displayLoading() const;
|
||||||
|
bool content_loaded() const;
|
||||||
|
float64 content_progress() const;
|
||||||
|
void content_automaticLoad() const;
|
||||||
|
void content_forget();
|
||||||
|
FileLocation content_location() const;
|
||||||
|
QByteArray content_data() const;
|
||||||
|
ImagePtr content_thumb() const;
|
||||||
|
int content_duration() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DeleteSavedGifClickHandler : public LeftButtonClickHandler {
|
||||||
|
public:
|
||||||
|
DeleteSavedGifClickHandler(DocumentData *data) : _data(data) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onClickImpl() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
DocumentData *_data;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class Gif : public FileBase {
|
||||||
|
public:
|
||||||
|
Gif(Result *result);
|
||||||
|
Gif(DocumentData *doc, bool hasDeleteButton);
|
||||||
|
|
||||||
|
void setPosition(int32 position) override;
|
||||||
|
void initDimensions() override;
|
||||||
|
|
||||||
|
bool isFullLine() const override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool hasRightSkip() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override;
|
||||||
|
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
||||||
|
|
||||||
|
// ClickHandlerHost interface
|
||||||
|
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
||||||
|
|
||||||
|
~Gif();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
QSize countFrameSize() const;
|
||||||
|
|
||||||
|
enum class StateFlag {
|
||||||
|
Over = 0x01,
|
||||||
|
DeleteOver = 0x02,
|
||||||
|
};
|
||||||
|
Q_DECLARE_FLAGS(StateFlags, StateFlag);
|
||||||
|
StateFlags _state;
|
||||||
|
friend inline StateFlags operator~(StateFlag flag) {
|
||||||
|
return ~StateFlags(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClipReader *_gif = nullptr;
|
||||||
|
ClickHandlerPtr _delete;
|
||||||
|
bool gif() const {
|
||||||
|
return (!_gif || _gif == BadClipReader) ? false : true;
|
||||||
|
}
|
||||||
|
mutable QPixmap _thumb;
|
||||||
|
void prepareThumb(int32 width, int32 height, const QSize &frame) const;
|
||||||
|
|
||||||
|
void ensureAnimation() const;
|
||||||
|
bool isRadialAnimation(uint64 ms) const;
|
||||||
|
void step_radial(uint64 ms, bool timer);
|
||||||
|
|
||||||
|
void clipCallback(ClipReaderNotification notification);
|
||||||
|
|
||||||
|
struct AnimationData {
|
||||||
|
AnimationData(AnimationCreator creator)
|
||||||
|
: over(false)
|
||||||
|
, radial(creator) {
|
||||||
|
}
|
||||||
|
bool over;
|
||||||
|
FloatAnimation _a_over;
|
||||||
|
RadialAnimation radial;
|
||||||
|
};
|
||||||
|
mutable AnimationData *_animation = nullptr;
|
||||||
|
mutable FloatAnimation _a_deleteOver;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class Photo : public ItemBase {
|
||||||
|
public:
|
||||||
|
Photo(Result *result);
|
||||||
|
// Not used anywhere currently.
|
||||||
|
//LayoutInlinePhoto(PhotoData *photo);
|
||||||
|
|
||||||
|
void initDimensions() override;
|
||||||
|
|
||||||
|
bool isFullLine() const override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool hasRightSkip() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override;
|
||||||
|
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
PhotoData *getShownPhoto() const;
|
||||||
|
|
||||||
|
QSize countFrameSize() const;
|
||||||
|
|
||||||
|
int content_width() const;
|
||||||
|
int content_height() const;
|
||||||
|
bool content_loaded() const;
|
||||||
|
void content_forget();
|
||||||
|
|
||||||
|
mutable QPixmap _thumb;
|
||||||
|
mutable bool _thumbLoaded = false;
|
||||||
|
void prepareThumb(int32 width, int32 height, const QSize &frame) const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class Sticker : public FileBase {
|
||||||
|
public:
|
||||||
|
Sticker(Result *result);
|
||||||
|
// Not used anywhere currently.
|
||||||
|
//LayoutInlineSticker(DocumentData *document);
|
||||||
|
|
||||||
|
void initDimensions() override;
|
||||||
|
|
||||||
|
bool isFullLine() const override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool hasRightSkip() const override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void preload() const override;
|
||||||
|
|
||||||
|
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override;
|
||||||
|
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
||||||
|
|
||||||
|
// ClickHandlerHost interface
|
||||||
|
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
QSize getThumbSize() const;
|
||||||
|
|
||||||
|
mutable FloatAnimation _a_over;
|
||||||
|
mutable bool _active = false;
|
||||||
|
|
||||||
|
mutable QPixmap _thumb;
|
||||||
|
mutable bool _thumbLoaded = false;
|
||||||
|
void prepareThumb() const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class Video : public FileBase {
|
||||||
|
public:
|
||||||
|
Video(Result *result);
|
||||||
|
|
||||||
|
void initDimensions() override;
|
||||||
|
|
||||||
|
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override;
|
||||||
|
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
ClickHandlerPtr _link;
|
||||||
|
|
||||||
|
mutable QPixmap _thumb;
|
||||||
|
Text _title, _description;
|
||||||
|
QString _duration;
|
||||||
|
int32 _durationWidth;
|
||||||
|
|
||||||
|
void prepareThumb(int32 width, int32 height) const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpenFileClickHandler : public LeftButtonClickHandler {
|
||||||
|
public:
|
||||||
|
OpenFileClickHandler(Result *result) : _result(result) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onClickImpl() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Result *_result;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class CancelFileClickHandler : public LeftButtonClickHandler {
|
||||||
|
public:
|
||||||
|
CancelFileClickHandler(Result *result) : _result(result) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onClickImpl() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Result *_result;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class File : public FileBase {
|
||||||
|
public:
|
||||||
|
File(Result *result);
|
||||||
|
|
||||||
|
void initDimensions() override;
|
||||||
|
|
||||||
|
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override;
|
||||||
|
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
||||||
|
|
||||||
|
// ClickHandlerHost interface
|
||||||
|
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Text _title, _description;
|
||||||
|
ClickHandlerPtr _open, _cancel;
|
||||||
|
|
||||||
|
void step_thumbOver(float64 ms, bool timer);
|
||||||
|
void step_radial(uint64 ms, bool timer);
|
||||||
|
|
||||||
|
void ensureAnimation() const;
|
||||||
|
void checkAnimationFinished();
|
||||||
|
|
||||||
|
bool isRadialAnimation(uint64 ms) const {
|
||||||
|
if (!_animation || !_animation->radial.animating()) return false;
|
||||||
|
|
||||||
|
_animation->radial.step(ms);
|
||||||
|
return _animation && _animation->radial.animating();
|
||||||
|
}
|
||||||
|
bool isThumbAnimation(uint64 ms) const {
|
||||||
|
if (!_animation || !_animation->_a_thumbOver.animating()) return false;
|
||||||
|
|
||||||
|
_animation->_a_thumbOver.step(ms);
|
||||||
|
return _animation && _animation->_a_thumbOver.animating();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AnimationData {
|
||||||
|
AnimationData(AnimationCreator thumbOverCallbacks, AnimationCreator radialCallbacks) : a_thumbOver(0, 0)
|
||||||
|
, _a_thumbOver(thumbOverCallbacks)
|
||||||
|
, radial(radialCallbacks) {
|
||||||
|
}
|
||||||
|
anim::fvalue a_thumbOver;
|
||||||
|
Animation _a_thumbOver;
|
||||||
|
|
||||||
|
RadialAnimation radial;
|
||||||
|
};
|
||||||
|
mutable UniquePointer<AnimationData> _animation;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class Article : public ItemBase {
|
||||||
|
public:
|
||||||
|
Article(Result *result, bool withThumb);
|
||||||
|
|
||||||
|
void initDimensions() override;
|
||||||
|
int32 resizeGetHeight(int32 width) override;
|
||||||
|
|
||||||
|
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override;
|
||||||
|
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
ClickHandlerPtr _url, _link;
|
||||||
|
|
||||||
|
bool _withThumb;
|
||||||
|
mutable QPixmap _thumb;
|
||||||
|
Text _title, _description;
|
||||||
|
QString _letter, _urlText;
|
||||||
|
int32 _urlWidth;
|
||||||
|
|
||||||
|
void prepareThumb(int32 width, int32 height) const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace Layout
|
||||||
|
} // namespace InlineBots
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "inline_bots/inline_bot_layout_item.h"
|
||||||
|
|
||||||
|
#include "inline_bots/inline_bot_result.h"
|
||||||
|
#include "inline_bots/inline_bot_layout_internal.h"
|
||||||
|
#include "localstorage.h"
|
||||||
|
#include "mainwidget.h"
|
||||||
|
|
||||||
|
namespace InlineBots {
|
||||||
|
namespace Layout {
|
||||||
|
|
||||||
|
void ItemBase::setPosition(int32 position) {
|
||||||
|
_position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 ItemBase::position() const {
|
||||||
|
return _position;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result *ItemBase::getResult() const {
|
||||||
|
return _result;
|
||||||
|
}
|
||||||
|
|
||||||
|
DocumentData *ItemBase::getDocument() const {
|
||||||
|
return _doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhotoData *ItemBase::getPhoto() const {
|
||||||
|
return _photo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemBase::preload() const {
|
||||||
|
if (_result) {
|
||||||
|
if (_result->photo) {
|
||||||
|
_result->photo->thumb->load();
|
||||||
|
} else if (_result->document) {
|
||||||
|
_result->document->thumb->load();
|
||||||
|
} else if (!_result->thumb->isNull()) {
|
||||||
|
_result->thumb->load();
|
||||||
|
}
|
||||||
|
} else if (_doc) {
|
||||||
|
_doc->thumb->load();
|
||||||
|
} else if (_photo) {
|
||||||
|
_photo->medium->load();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemBase::update() {
|
||||||
|
if (_position >= 0) {
|
||||||
|
Ui::repaintInlineItem(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UniquePointer<ItemBase> ItemBase::createLayout(Result *result, bool forceThumb) {
|
||||||
|
using Type = Result::Type;
|
||||||
|
|
||||||
|
switch (result->type) {
|
||||||
|
case Type::Photo: return MakeUnique<internal::Photo>(result); break;
|
||||||
|
case Type::Audio:
|
||||||
|
case Type::File: return MakeUnique<internal::File>(result); break;
|
||||||
|
case Type::Video: return MakeUnique<internal::Video>(result); break;
|
||||||
|
case Type::Sticker: return MakeUnique<internal::Sticker>(result); break;
|
||||||
|
case Type::Gif: return MakeUnique<internal::Gif>(result); break;
|
||||||
|
case Type::Article:
|
||||||
|
case Type::Contact:
|
||||||
|
case Type::Venue: return MakeUnique<internal::Article>(result, forceThumb); break;
|
||||||
|
}
|
||||||
|
return UniquePointer<ItemBase>();
|
||||||
|
}
|
||||||
|
|
||||||
|
UniquePointer<ItemBase> ItemBase::createLayoutGif(DocumentData *document) {
|
||||||
|
return MakeUnique<internal::Gif>(document, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Layout
|
||||||
|
} // namespace InlineBots
|
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "layout.h"
|
||||||
|
#include "structs.h"
|
||||||
|
#include "gui/text.h"
|
||||||
|
|
||||||
|
namespace InlineBots {
|
||||||
|
class Result;
|
||||||
|
|
||||||
|
namespace Layout {
|
||||||
|
|
||||||
|
class PaintContext : public PaintContextBase {
|
||||||
|
public:
|
||||||
|
PaintContext(uint64 ms, bool selecting, bool paused, bool lastRow)
|
||||||
|
: PaintContextBase(ms, selecting)
|
||||||
|
, paused(paused)
|
||||||
|
, lastRow(lastRow) {
|
||||||
|
}
|
||||||
|
bool paused, lastRow;
|
||||||
|
};
|
||||||
|
|
||||||
|
// this type used as a flag, we dynamic_cast<> to it
|
||||||
|
class SendClickHandler : public ClickHandler {
|
||||||
|
public:
|
||||||
|
void onClick(Qt::MouseButton) const override {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ItemBase : public LayoutItemBase {
|
||||||
|
public:
|
||||||
|
|
||||||
|
ItemBase(Result *result) : _result(result) {
|
||||||
|
}
|
||||||
|
ItemBase(DocumentData *doc) : _doc(doc) {
|
||||||
|
}
|
||||||
|
// Not used anywhere currently.
|
||||||
|
//ItemBase(PhotoData *photo) : _photo(photo) {
|
||||||
|
//}
|
||||||
|
|
||||||
|
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const = 0;
|
||||||
|
|
||||||
|
virtual void setPosition(int32 position);
|
||||||
|
int32 position() const;
|
||||||
|
|
||||||
|
virtual bool isFullLine() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual bool hasRightSkip() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result *getResult() const;
|
||||||
|
DocumentData *getDocument() const;
|
||||||
|
PhotoData *getPhoto() const;
|
||||||
|
|
||||||
|
virtual void preload() const;
|
||||||
|
|
||||||
|
void update();
|
||||||
|
|
||||||
|
// ClickHandlerHost interface
|
||||||
|
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
static UniquePointer<ItemBase> createLayout(Result *result, bool forceThumb);
|
||||||
|
static UniquePointer<ItemBase> createLayoutGif(DocumentData *document);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Result *_result = nullptr;
|
||||||
|
DocumentData *_doc = nullptr;
|
||||||
|
PhotoData *_photo = nullptr;
|
||||||
|
|
||||||
|
ClickHandlerPtr _send = ClickHandlerPtr{ new SendClickHandler() };
|
||||||
|
|
||||||
|
int _position = 0; // < 0 means removed from layout
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Layout
|
||||||
|
} // namespace InlineBots
|
|
@ -0,0 +1,320 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "inline_bots/inline_bot_result.h"
|
||||||
|
|
||||||
|
#include "inline_bots/inline_bot_layout_item.h"
|
||||||
|
#include "inline_bots/inline_bot_send_data.h"
|
||||||
|
#include "mtproto/file_download.h"
|
||||||
|
#include "mainwidget.h"
|
||||||
|
|
||||||
|
namespace InlineBots {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using ResultsByLoaderMap = QMap<FileLoader*, Result*>;
|
||||||
|
NeverFreedPointer<ResultsByLoaderMap> ResultsByLoader;
|
||||||
|
|
||||||
|
void regLoader(FileLoader *loader, Result *result) {
|
||||||
|
ResultsByLoader.createIfNull([]() -> ResultsByLoaderMap* {
|
||||||
|
return new ResultsByLoaderMap();
|
||||||
|
});
|
||||||
|
ResultsByLoader->insert(loader, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unregLoader(FileLoader *loader) {
|
||||||
|
if (!ResultsByLoader) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ResultsByLoader->remove(loader);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Result *getResultFromLoader(FileLoader *loader) {
|
||||||
|
if (!ResultsByLoader) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return ResultsByLoader->value(loader, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using StringToTypeMap = QMap<QString, Result::Type>;
|
||||||
|
NeverFreedPointer<StringToTypeMap> stringToTypeMap;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Result::Result(const Creator &creator) : queryId(creator.queryId), type(creator.type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
UniquePointer<Result> Result::create(uint64 queryId, const MTPBotInlineResult &mtpData) {
|
||||||
|
stringToTypeMap.createIfNull([]() -> StringToTypeMap* {
|
||||||
|
auto result = MakeUnique<StringToTypeMap>();
|
||||||
|
result->insert(qsl("photo"), Result::Type::Photo);
|
||||||
|
result->insert(qsl("video"), Result::Type::Video);
|
||||||
|
result->insert(qsl("audio"), Result::Type::Audio);
|
||||||
|
result->insert(qsl("sticker"), Result::Type::Sticker);
|
||||||
|
result->insert(qsl("file"), Result::Type::File);
|
||||||
|
result->insert(qsl("gif"), Result::Type::Gif);
|
||||||
|
result->insert(qsl("article"), Result::Type::Article);
|
||||||
|
result->insert(qsl("contact"), Result::Type::Contact);
|
||||||
|
result->insert(qsl("venue"), Result::Type::Venue);
|
||||||
|
return result.release();
|
||||||
|
});
|
||||||
|
auto getInlineResultType = [](const MTPBotInlineResult &inlineResult) -> Type {
|
||||||
|
QString type;
|
||||||
|
switch (inlineResult.type()) {
|
||||||
|
case mtpc_botInlineResult: type = qs(inlineResult.c_botInlineResult().vtype); break;
|
||||||
|
case mtpc_botInlineMediaResult: type = qs(inlineResult.c_botInlineMediaResult().vtype); break;
|
||||||
|
}
|
||||||
|
return stringToTypeMap->value(type, Type::Unknown);
|
||||||
|
};
|
||||||
|
Type type = getInlineResultType(mtpData);
|
||||||
|
if (type == Type::Unknown) {
|
||||||
|
return UniquePointer<Result>();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = MakeUnique<Result>(Creator{ queryId, type });
|
||||||
|
const MTPBotInlineMessage *message = nullptr;
|
||||||
|
switch (mtpData.type()) {
|
||||||
|
case mtpc_botInlineResult: {
|
||||||
|
const MTPDbotInlineResult &r(mtpData.c_botInlineResult());
|
||||||
|
result->id = qs(r.vid);
|
||||||
|
if (r.has_title()) result->title = qs(r.vtitle);
|
||||||
|
if (r.has_description()) result->description = qs(r.vdescription);
|
||||||
|
if (r.has_url()) result->url = qs(r.vurl);
|
||||||
|
if (r.has_thumb_url()) result->thumb_url = qs(r.vthumb_url);
|
||||||
|
if (r.has_content_type()) result->content_type = qs(r.vcontent_type);
|
||||||
|
if (r.has_content_url()) result->content_url = qs(r.vcontent_url);
|
||||||
|
if (r.has_w()) result->width = r.vw.v;
|
||||||
|
if (r.has_h()) result->height = r.vh.v;
|
||||||
|
if (r.has_duration()) result->duration = r.vduration.v;
|
||||||
|
if (!result->thumb_url.isEmpty() && (result->thumb_url.startsWith(qstr("http://"), Qt::CaseInsensitive) || result->thumb_url.startsWith(qstr("https://"), Qt::CaseInsensitive))) {
|
||||||
|
result->thumb = ImagePtr(result->thumb_url);
|
||||||
|
}
|
||||||
|
message = &r.vsend_message;
|
||||||
|
} break;
|
||||||
|
case mtpc_botInlineMediaResult: {
|
||||||
|
const MTPDbotInlineMediaResult &r(mtpData.c_botInlineMediaResult());
|
||||||
|
result->id = qs(r.vid);
|
||||||
|
if (r.has_title()) result->title = qs(r.vtitle);
|
||||||
|
if (r.has_description()) result->description = qs(r.vdescription);
|
||||||
|
if (r.has_photo()) result->photo = App::feedPhoto(r.vphoto);
|
||||||
|
if (r.has_document()) result->document = App::feedDocument(r.vdocument);
|
||||||
|
message = &r.vsend_message;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
bool badAttachment = (result->photo && !result->photo->access) || (result->document && !result->document->access);
|
||||||
|
|
||||||
|
if (!message) {
|
||||||
|
return UniquePointer<Result>();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (message->type()) {
|
||||||
|
case mtpc_botInlineMessageMediaAuto: {
|
||||||
|
const MTPDbotInlineMessageMediaAuto &r(message->c_botInlineMessageMediaAuto());
|
||||||
|
if (result->type == Type::Photo) {
|
||||||
|
result->sendData.reset(new internal::SendPhoto(result->photo, result->content_url, qs(r.vcaption)));
|
||||||
|
} else {
|
||||||
|
result->sendData.reset(new internal::SendFile(result->document, result->content_url, qs(r.vcaption)));
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case mtpc_botInlineMessageText: {
|
||||||
|
const MTPDbotInlineMessageText &r(message->c_botInlineMessageText());
|
||||||
|
EntitiesInText entities = r.has_entities() ? entitiesFromMTP(r.ventities.c_vector().v) : EntitiesInText();
|
||||||
|
result->sendData.reset(new internal::SendText(qs(r.vmessage), entities, r.is_no_webpage()));
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case mtpc_botInlineMessageMediaGeo: {
|
||||||
|
const MTPDbotInlineMessageMediaGeo &r(message->c_botInlineMessageMediaGeo());
|
||||||
|
if (r.vgeo.type() == mtpc_geoPoint) {
|
||||||
|
result->sendData.reset(new internal::SendGeo(r.vgeo.c_geoPoint()));
|
||||||
|
} else {
|
||||||
|
badAttachment = true;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case mtpc_botInlineMessageMediaVenue: {
|
||||||
|
const MTPDbotInlineMessageMediaVenue &r(message->c_botInlineMessageMediaVenue());
|
||||||
|
if (r.vgeo.type() == mtpc_geoPoint) {
|
||||||
|
result->sendData.reset(new internal::SendVenue(r.vgeo.c_geoPoint(), qs(r.vvenue_id), qs(r.vprovider), qs(r.vtitle), qs(r.vaddress)));
|
||||||
|
} else {
|
||||||
|
badAttachment = true;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case mtpc_botInlineMessageMediaContact: {
|
||||||
|
const MTPDbotInlineMessageMediaContact &r(message->c_botInlineMessageMediaContact());
|
||||||
|
result->sendData.reset(new internal::SendContact(qs(r.vfirst_name), qs(r.vlast_name), qs(r.vphone_number)));
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
badAttachment = true;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (badAttachment || !result->sendData || !result->sendData->isValid()) {
|
||||||
|
return UniquePointer<Result>();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Result::automaticLoadGif() {
|
||||||
|
if (loaded() || type != Type::Gif || (content_type != qstr("video/mp4") && content_type != "image/gif")) return;
|
||||||
|
|
||||||
|
if (_loader != CancelledWebFileLoader) {
|
||||||
|
// if load at least anywhere
|
||||||
|
bool loadFromCloud = !(cAutoDownloadGif() & dbiadNoPrivate) || !(cAutoDownloadGif() & dbiadNoGroups);
|
||||||
|
saveFile(QString(), loadFromCloud ? LoadFromCloudOrLocal : LoadFromLocalOnly, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Result::automaticLoadSettingsChangedGif() {
|
||||||
|
if (loaded() || _loader != CancelledWebFileLoader) return;
|
||||||
|
_loader = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Result::saveFile(const QString &toFile, LoadFromCloudSetting fromCloud, bool autoLoading) {
|
||||||
|
if (loaded()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_loader == CancelledWebFileLoader) _loader = 0;
|
||||||
|
if (_loader) {
|
||||||
|
if (!_loader->setFileName(toFile)) {
|
||||||
|
cancelFile();
|
||||||
|
_loader = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_loader) {
|
||||||
|
if (fromCloud == LoadFromCloudOrLocal) _loader->permitLoadFromCloud();
|
||||||
|
} else {
|
||||||
|
_loader = new webFileLoader(content_url, toFile, fromCloud, autoLoading);
|
||||||
|
regLoader(_loader, this);
|
||||||
|
|
||||||
|
_loader->connect(_loader, SIGNAL(progress(FileLoader*)), App::main(), SLOT(inlineResultLoadProgress(FileLoader*)));
|
||||||
|
_loader->connect(_loader, SIGNAL(failed(FileLoader*, bool)), App::main(), SLOT(inlineResultLoadFailed(FileLoader*, bool)));
|
||||||
|
_loader->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Result::cancelFile() {
|
||||||
|
if (!loading()) return;
|
||||||
|
|
||||||
|
unregLoader(_loader);
|
||||||
|
|
||||||
|
webFileLoader *l = _loader;
|
||||||
|
_loader = CancelledWebFileLoader;
|
||||||
|
if (l) {
|
||||||
|
l->cancel();
|
||||||
|
l->deleteLater();
|
||||||
|
l->stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray Result::data() const {
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Result::loading() const {
|
||||||
|
return _loader && _loader != CancelledWebFileLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Result::loaded() const {
|
||||||
|
if (loading() && _loader->done()) {
|
||||||
|
unregLoader(_loader);
|
||||||
|
if (_loader->fileType() == mtpc_storage_fileUnknown) {
|
||||||
|
_loader->deleteLater();
|
||||||
|
_loader->stop();
|
||||||
|
_loader = CancelledWebFileLoader;
|
||||||
|
} else {
|
||||||
|
Result *that = const_cast<Result*>(this);
|
||||||
|
that->_data = _loader->bytes();
|
||||||
|
|
||||||
|
_loader->deleteLater();
|
||||||
|
_loader->stop();
|
||||||
|
_loader = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !_data.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Result::displayLoading() const {
|
||||||
|
return loading() ? (!_loader->loadingLocal() || !_loader->autoLoading()) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Result::forget() {
|
||||||
|
thumb->forget();
|
||||||
|
_data.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
float64 Result::progress() const {
|
||||||
|
return loading() ? _loader->currentProgress() : (loaded() ? 1 : 0); return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Result::hasThumbDisplay() const {
|
||||||
|
if (!thumb->isNull()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (type == Type::Contact) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (sendData->hasLocationCoords()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
void Result::addToHistory(History *history, MTPDmessage::Flags flags, MsgId msgId, UserId fromId, MTPint mtpDate, UserId viaBotId, MsgId replyToId) const {
|
||||||
|
if (DocumentData *document = sendData->getSentDocument()) {
|
||||||
|
history->addNewDocument(msgId, flags, viaBotId, replyToId, date(mtpDate), fromId, document, sendData->getSentCaption());
|
||||||
|
} else if (PhotoData *photo = sendData->getSentPhoto()) {
|
||||||
|
history->addNewPhoto(msgId, flags, viaBotId, replyToId, date(mtpDate), fromId, photo, sendData->getSentCaption());
|
||||||
|
} else {
|
||||||
|
internal::SendData::SentMTPMessageFields fields = sendData->getSentMessageFields(this);
|
||||||
|
if (!fields.entities.c_vector().v.isEmpty()) {
|
||||||
|
flags |= MTPDmessage::Flag::f_entities;
|
||||||
|
}
|
||||||
|
history->addNewMessage(MTP_message(MTP_flags(flags), MTP_int(msgId), MTP_int(fromId), peerToMTP(history->peer->id), MTPnullFwdHeader, MTP_int(viaBotId), MTP_int(replyToId), mtpDate, fields.text, fields.media, MTPnullMarkup, fields.entities, MTP_int(1), MTPint()), NewMessageUnread);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Result::getLocationCoords(LocationCoords *outLocation) const {
|
||||||
|
return sendData->getLocationCoords(outLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Result::getLayoutTitle() const {
|
||||||
|
return sendData->getLayoutTitle(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Result::getLayoutDescription() const {
|
||||||
|
return sendData->getLayoutDescription(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result::~Result() {
|
||||||
|
cancelFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace InlineBots
|
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "basic_types.h"
|
||||||
|
#include "structs.h"
|
||||||
|
#include "mtproto/core_types.h"
|
||||||
|
|
||||||
|
class FileLoader;
|
||||||
|
|
||||||
|
namespace InlineBots {
|
||||||
|
|
||||||
|
namespace Layout {
|
||||||
|
class ItemBase;
|
||||||
|
} // namespace Layout
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
class SendData;
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
class Result {
|
||||||
|
private:
|
||||||
|
// See http://stackoverflow.com/a/8147326
|
||||||
|
struct Creator;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum class Type {
|
||||||
|
Unknown,
|
||||||
|
Photo,
|
||||||
|
Video,
|
||||||
|
Audio,
|
||||||
|
Sticker,
|
||||||
|
File,
|
||||||
|
Gif,
|
||||||
|
Article,
|
||||||
|
Contact,
|
||||||
|
Venue,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Constructor is public only for MakeUnique<>() to work.
|
||||||
|
// You should use create() static method instead.
|
||||||
|
explicit Result(const Creator &creator);
|
||||||
|
static UniquePointer<Result> create(uint64 queryId, const MTPBotInlineResult &mtpData);
|
||||||
|
Result(const Result &other) = delete;
|
||||||
|
Result &operator=(const Result &other) = delete;
|
||||||
|
|
||||||
|
uint64 queryId;
|
||||||
|
QString id;
|
||||||
|
Type type;
|
||||||
|
DocumentData *document = nullptr;
|
||||||
|
PhotoData *photo = nullptr;
|
||||||
|
QString title, description, url, thumb_url;
|
||||||
|
QString content_type, content_url;
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
int duration = 0;
|
||||||
|
|
||||||
|
ImagePtr thumb;
|
||||||
|
|
||||||
|
void automaticLoadGif();
|
||||||
|
void automaticLoadSettingsChangedGif();
|
||||||
|
void saveFile(const QString &toFile, LoadFromCloudSetting fromCloud, bool autoLoading);
|
||||||
|
void cancelFile();
|
||||||
|
|
||||||
|
QByteArray data() const;
|
||||||
|
bool loading() const;
|
||||||
|
bool loaded() const;
|
||||||
|
bool displayLoading() const;
|
||||||
|
void forget();
|
||||||
|
float64 progress() const;
|
||||||
|
|
||||||
|
bool hasThumbDisplay() const;
|
||||||
|
|
||||||
|
void addToHistory(History *history, MTPDmessage::Flags flags, MsgId msgId, UserId fromId, MTPint mtpDate, UserId viaBotId, MsgId replyToId) const;
|
||||||
|
|
||||||
|
// interface for Layout:: usage
|
||||||
|
bool getLocationCoords(LocationCoords *outLocation) const;
|
||||||
|
QString getLayoutTitle() const;
|
||||||
|
QString getLayoutDescription() const;
|
||||||
|
|
||||||
|
~Result();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Creator {
|
||||||
|
uint64 queryId;
|
||||||
|
Type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
UniquePointer<internal::SendData> sendData;
|
||||||
|
|
||||||
|
QByteArray _data;
|
||||||
|
mutable webFileLoader *_loader = nullptr;
|
||||||
|
|
||||||
|
};
|
||||||
|
Result *getResultFromLoader(FileLoader *loader);
|
||||||
|
|
||||||
|
} // namespace InlineBots
|
|
@ -0,0 +1,146 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "inline_bots/inline_bot_send_data.h"
|
||||||
|
|
||||||
|
#include "inline_bots/inline_bot_result.h"
|
||||||
|
#include "localstorage.h"
|
||||||
|
|
||||||
|
namespace InlineBots {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
QString SendData::getLayoutTitle(const Result *owner) const {
|
||||||
|
return owner->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SendData::getLayoutDescription(const Result *owner) const {
|
||||||
|
return owner->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
SendData::SentMTPMessageFields SendText::getSentMessageFields(const Result*) const {
|
||||||
|
SentMTPMessageFields result;
|
||||||
|
result.text = MTP_string(_message);
|
||||||
|
result.entities = linksToMTP(_entities);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
SendData::SentMTPMessageFields SendGeo::getSentMessageFields(const Result*) const {
|
||||||
|
SentMTPMessageFields result;
|
||||||
|
result.media = MTP_messageMediaGeo(MTP_geoPoint(MTP_double(_location.lon), MTP_double(_location.lat)));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
SendData::SentMTPMessageFields SendVenue::getSentMessageFields(const Result*) const {
|
||||||
|
SentMTPMessageFields result;
|
||||||
|
result.media = MTP_messageMediaVenue(MTP_geoPoint(MTP_double(_location.lon), MTP_double(_location.lat)), MTP_string(_title), MTP_string(_address), MTP_string(_provider), MTP_string(_venueId));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
SendData::SentMTPMessageFields SendContact::getSentMessageFields(const Result*) const {
|
||||||
|
SentMTPMessageFields result;
|
||||||
|
result.media = MTP_messageMediaContact(MTP_string(_phoneNumber), MTP_string(_firstName), MTP_string(_lastName), MTP_int(0));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SendContact::getLayoutDescription(const Result *owner) const {
|
||||||
|
return App::formatPhone(_phoneNumber) + '\n' + owner->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
SendData::SentMTPMessageFields SendPhoto::getSentMessageFields(const Result *owner) const {
|
||||||
|
SentMTPMessageFields result;
|
||||||
|
|
||||||
|
QImage fileThumb(owner->thumb->pix().toImage());
|
||||||
|
|
||||||
|
QVector<MTPPhotoSize> photoSizes;
|
||||||
|
|
||||||
|
QPixmap thumb = (fileThumb.width() > 100 || fileThumb.height() > 100) ? QPixmap::fromImage(fileThumb.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(fileThumb);
|
||||||
|
ImagePtr thumbPtr = ImagePtr(thumb, "JPG");
|
||||||
|
photoSizes.push_back(MTP_photoSize(MTP_string("s"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(thumb.width()), MTP_int(thumb.height()), MTP_int(0)));
|
||||||
|
|
||||||
|
QSize medium = resizeKeepAspect(owner->width, owner->height, 320, 320);
|
||||||
|
photoSizes.push_back(MTP_photoSize(MTP_string("m"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(medium.width()), MTP_int(medium.height()), MTP_int(0)));
|
||||||
|
|
||||||
|
photoSizes.push_back(MTP_photoSize(MTP_string("x"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(owner->width), MTP_int(owner->height), MTP_int(0)));
|
||||||
|
|
||||||
|
uint64 photoId = rand_value<uint64>();
|
||||||
|
PhotoData *ph = App::photoSet(photoId, 0, 0, unixtime(), thumbPtr, ImagePtr(medium.width(), medium.height()), ImagePtr(owner->width, owner->height));
|
||||||
|
MTPPhoto photo = MTP_photo(MTP_long(photoId), MTP_long(0), MTP_int(ph->date), MTP_vector<MTPPhotoSize>(photoSizes));
|
||||||
|
|
||||||
|
result.media = MTP_messageMediaPhoto(photo, MTP_string(_caption));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
SendData::SentMTPMessageFields SendFile::getSentMessageFields(const Result *owner) const {
|
||||||
|
SentMTPMessageFields result;
|
||||||
|
|
||||||
|
MTPPhotoSize thumbSize;
|
||||||
|
QPixmap thumb;
|
||||||
|
int32 tw = owner->thumb->width(), th = owner->thumb->height();
|
||||||
|
if (tw > 0 && th > 0 && tw < 20 * th && th < 20 * tw && owner->thumb->loaded()) {
|
||||||
|
if (tw > th) {
|
||||||
|
if (tw > 90) {
|
||||||
|
th = th * 90 / tw;
|
||||||
|
tw = 90;
|
||||||
|
}
|
||||||
|
} else if (th > 90) {
|
||||||
|
tw = tw * 90 / th;
|
||||||
|
th = 90;
|
||||||
|
}
|
||||||
|
thumbSize = MTP_photoSize(MTP_string(""), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(tw), MTP_int(th), MTP_int(0));
|
||||||
|
thumb = owner->thumb->pixNoCache(tw, th, ImagePixSmooth);
|
||||||
|
} else {
|
||||||
|
tw = th = 0;
|
||||||
|
thumbSize = MTP_photoSizeEmpty(MTP_string(""));
|
||||||
|
}
|
||||||
|
uint64 docId = rand_value<uint64>();
|
||||||
|
QVector<MTPDocumentAttribute> attributes;
|
||||||
|
|
||||||
|
int duration = getSentDuration(owner);
|
||||||
|
QSize dimensions = getSentDimensions(owner);
|
||||||
|
using Type = Result::Type;
|
||||||
|
if (owner->type == Type::Gif) {
|
||||||
|
attributes.push_back(MTP_documentAttributeFilename(MTP_string((owner->content_type == qstr("video/mp4") ? "animation.gif.mp4" : "animation.gif"))));
|
||||||
|
attributes.push_back(MTP_documentAttributeAnimated());
|
||||||
|
attributes.push_back(MTP_documentAttributeVideo(MTP_int(duration), MTP_int(dimensions.width()), MTP_int(dimensions.height())));
|
||||||
|
} else if (owner->type == Type::Video) {
|
||||||
|
attributes.push_back(MTP_documentAttributeVideo(MTP_int(duration), MTP_int(dimensions.width()), MTP_int(dimensions.height())));
|
||||||
|
}
|
||||||
|
MTPDocument document = MTP_document(MTP_long(docId), MTP_long(0), MTP_int(unixtime()), MTP_string(owner->content_type), MTP_int(owner->data().size()), thumbSize, MTP_int(MTP::maindc()), MTP_vector<MTPDocumentAttribute>(attributes));
|
||||||
|
if (tw > 0 && th > 0) {
|
||||||
|
App::feedDocument(document, thumb);
|
||||||
|
}
|
||||||
|
Local::writeStickerImage(mediaKey(DocumentFileLocation, MTP::maindc(), docId), owner->data());
|
||||||
|
|
||||||
|
result.media = MTP_messageMediaDocument(document, MTP_string(_caption));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SendFile::getSentDuration(const Result *owner) const {
|
||||||
|
return (_document && _document->duration()) ? _document->duration() : owner->duration;
|
||||||
|
}
|
||||||
|
QSize SendFile::getSentDimensions(const Result *owner) const {
|
||||||
|
return (!_document || _document->dimensions.isEmpty()) ? QSize(owner->width, owner->height) : _document->dimensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace InlineBots
|
|
@ -0,0 +1,233 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "basic_types.h"
|
||||||
|
#include "structs.h"
|
||||||
|
#include "mtproto/core_types.h"
|
||||||
|
|
||||||
|
namespace InlineBots {
|
||||||
|
|
||||||
|
class Result;
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
// Abstract class describing the message that will be
|
||||||
|
// sent if the user chooses this inline bot result.
|
||||||
|
// For each type of message that can be sent there will be a subclass.
|
||||||
|
class SendData {
|
||||||
|
public:
|
||||||
|
SendData() = default;
|
||||||
|
SendData(const SendData &other) = delete;
|
||||||
|
SendData &operator=(const SendData &other) = delete;
|
||||||
|
virtual ~SendData() = default;
|
||||||
|
|
||||||
|
virtual bool isValid() const = 0;
|
||||||
|
|
||||||
|
virtual DocumentData *getSentDocument() const {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
virtual PhotoData *getSentPhoto() const {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
virtual QString getSentCaption() const {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
struct SentMTPMessageFields {
|
||||||
|
MTPString text = MTP_string("");
|
||||||
|
MTPVector<MTPMessageEntity> entities = MTPnullEntities;
|
||||||
|
MTPMessageMedia media = MTP_messageMediaEmpty();
|
||||||
|
};
|
||||||
|
virtual SentMTPMessageFields getSentMessageFields(const Result *owner) const = 0;
|
||||||
|
|
||||||
|
virtual bool hasLocationCoords() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
virtual bool getLocationCoords(LocationCoords *outLocation) const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
virtual QString getLayoutTitle(const Result *owner) const;
|
||||||
|
virtual QString getLayoutDescription(const Result *owner) const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Plain text message.
|
||||||
|
class SendText : public SendData {
|
||||||
|
public:
|
||||||
|
SendText(const QString &message, const EntitiesInText &entities, bool noWebPage)
|
||||||
|
: _message(message)
|
||||||
|
, _entities(entities)
|
||||||
|
, _noWebPage(noWebPage) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid() const override {
|
||||||
|
return !_message.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
SentMTPMessageFields getSentMessageFields(const Result *owner) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString _message;
|
||||||
|
EntitiesInText _entities;
|
||||||
|
bool _noWebPage;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Message with geo location point media.
|
||||||
|
class SendGeo : public SendData {
|
||||||
|
public:
|
||||||
|
SendGeo(const MTPDgeoPoint &point) : _location(point) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SentMTPMessageFields getSentMessageFields(const Result *owner) const override;
|
||||||
|
|
||||||
|
bool hasLocationCoords() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool getLocationCoords(LocationCoords *outLocation) const override {
|
||||||
|
t_assert(outLocation != nullptr);
|
||||||
|
*outLocation = _location;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
LocationCoords _location;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Message with venue media.
|
||||||
|
class SendVenue : public SendData {
|
||||||
|
public:
|
||||||
|
SendVenue(const MTPDgeoPoint &point, const QString &venueId,
|
||||||
|
const QString &provider, const QString &title, const QString &address)
|
||||||
|
: _location(point)
|
||||||
|
, _venueId(venueId)
|
||||||
|
, _provider(provider)
|
||||||
|
, _title(title)
|
||||||
|
, _address(address) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SentMTPMessageFields getSentMessageFields(const Result *owner) const override;
|
||||||
|
|
||||||
|
bool hasLocationCoords() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool getLocationCoords(LocationCoords *outLocation) const override {
|
||||||
|
t_assert(outLocation != nullptr);
|
||||||
|
*outLocation = _location;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
LocationCoords _location;
|
||||||
|
QString _venueId, _provider, _title, _address;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Message with shared contact media.
|
||||||
|
class SendContact : public SendData {
|
||||||
|
public:
|
||||||
|
SendContact(const QString &firstName, const QString &lastName, const QString &phoneNumber)
|
||||||
|
: _firstName(firstName)
|
||||||
|
, _lastName(lastName)
|
||||||
|
, _phoneNumber(phoneNumber) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid() const override {
|
||||||
|
return (!_firstName.isEmpty() || !_lastName.isEmpty()) && !_phoneNumber.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
SentMTPMessageFields getSentMessageFields(const Result *owner) const override;
|
||||||
|
|
||||||
|
QString getLayoutDescription(const Result *owner) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString _firstName, _lastName, _phoneNumber;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Message with photo.
|
||||||
|
class SendPhoto : public SendData {
|
||||||
|
public:
|
||||||
|
SendPhoto(PhotoData *photo, const QString &url, const QString &caption)
|
||||||
|
: _photo(photo)
|
||||||
|
, _url(url)
|
||||||
|
, _caption(caption) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid() const override {
|
||||||
|
return _photo || !_url.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
PhotoData *getSentPhoto() const override {
|
||||||
|
return _photo;
|
||||||
|
}
|
||||||
|
QString getSentCaption() const override {
|
||||||
|
return _caption;
|
||||||
|
}
|
||||||
|
SentMTPMessageFields getSentMessageFields(const Result *owner) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
PhotoData *_photo;
|
||||||
|
QString _url, _caption;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Message with file.
|
||||||
|
class SendFile : public SendData {
|
||||||
|
public:
|
||||||
|
SendFile(DocumentData *document, const QString &url, const QString &caption)
|
||||||
|
: _document(document)
|
||||||
|
, _url(url)
|
||||||
|
, _caption(caption) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid() const override {
|
||||||
|
return _document || !_url.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
DocumentData *getSentDocument() const override {
|
||||||
|
return _document;
|
||||||
|
}
|
||||||
|
QString getSentCaption() const override {
|
||||||
|
return _caption;
|
||||||
|
}
|
||||||
|
SentMTPMessageFields getSentMessageFields(const Result *owner) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
DocumentData *_document;
|
||||||
|
QString _url, _caption;
|
||||||
|
|
||||||
|
int getSentDuration(const Result *owner) const;
|
||||||
|
QSize getSentDimensions(const Result *owner) const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace InlineBots
|
File diff suppressed because it is too large
Load Diff
|
@ -82,31 +82,22 @@ style::color documentSelectedColor(int32 colorIndex);
|
||||||
style::sprite documentCorner(int32 colorIndex);
|
style::sprite documentCorner(int32 colorIndex);
|
||||||
RoundCorners documentCorners(int32 colorIndex);
|
RoundCorners documentCorners(int32 colorIndex);
|
||||||
|
|
||||||
class OverviewPaintContext;
|
class PaintContextBase {
|
||||||
class InlinePaintContext;
|
|
||||||
class PaintContext {
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
PaintContext(uint64 ms, bool selecting) : ms(ms), selecting(selecting) {
|
PaintContextBase(uint64 ms, bool selecting) : ms(ms), selecting(selecting) {
|
||||||
}
|
}
|
||||||
uint64 ms;
|
uint64 ms;
|
||||||
bool selecting;
|
bool selecting;
|
||||||
|
|
||||||
virtual const OverviewPaintContext *toOverviewPaintContext() const {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
virtual const InlinePaintContext *toInlinePaintContext() const {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class LayoutMediaItem;
|
class LayoutMediaItemBase;
|
||||||
class LayoutItem : public Composer, public ClickHandlerHost {
|
class LayoutItemBase : public Composer, public ClickHandlerHost {
|
||||||
public:
|
public:
|
||||||
LayoutItem() {
|
LayoutItemBase() {
|
||||||
}
|
}
|
||||||
LayoutItem &operator=(const LayoutItem &) = delete;
|
LayoutItemBase &operator=(const LayoutItemBase &) = delete;
|
||||||
|
|
||||||
int32 maxWidth() const {
|
int32 maxWidth() const {
|
||||||
return _maxw;
|
return _maxw;
|
||||||
|
@ -121,7 +112,6 @@ public:
|
||||||
return _height;
|
return _height;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const = 0;
|
|
||||||
virtual void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const {
|
virtual void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const {
|
||||||
link.clear();
|
link.clear();
|
||||||
cursor = HistoryDefaultCursorState;
|
cursor = HistoryDefaultCursorState;
|
||||||
|
@ -143,13 +133,34 @@ public:
|
||||||
return (x >= 0 && y >= 0 && x < width() && y < height());
|
return (x >= 0 && y >= 0 && x < width() && y < height());
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~LayoutItem() {
|
virtual ~LayoutItemBase() {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual LayoutMediaItem *toLayoutMediaItem() {
|
protected:
|
||||||
|
int _width = 0;
|
||||||
|
int _height = 0;
|
||||||
|
int _maxw = 0;
|
||||||
|
int _minh = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class PaintContextOverview : public PaintContextBase {
|
||||||
|
public:
|
||||||
|
PaintContextOverview(uint64 ms, bool selecting) : PaintContextBase(ms, selecting), isAfterDate(false) {
|
||||||
|
}
|
||||||
|
bool isAfterDate;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class LayoutOverviewItemBase : public LayoutItemBase {
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContextOverview *context) const = 0;
|
||||||
|
|
||||||
|
virtual LayoutMediaItemBase *toLayoutMediaItem() {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
virtual const LayoutMediaItem *toLayoutMediaItem() const {
|
virtual const LayoutMediaItemBase *toLayoutMediaItem() const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,23 +175,17 @@ public:
|
||||||
return item ? item->id : 0;
|
return item ? item->id : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
|
||||||
int _width = 0;
|
|
||||||
int _height = 0;
|
|
||||||
int _maxw = 0;
|
|
||||||
int _minh = 0;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class LayoutMediaItem : public LayoutItem {
|
class LayoutMediaItemBase : public LayoutOverviewItemBase {
|
||||||
public:
|
public:
|
||||||
LayoutMediaItem(HistoryItem *parent) : _parent(parent) {
|
LayoutMediaItemBase(HistoryItem *parent) : _parent(parent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutMediaItem *toLayoutMediaItem() override {
|
LayoutMediaItemBase *toLayoutMediaItem() override {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
const LayoutMediaItem *toLayoutMediaItem() const override {
|
const LayoutMediaItemBase *toLayoutMediaItem() const override {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
HistoryItem *getItem() const override {
|
HistoryItem *getItem() const override {
|
||||||
|
@ -195,9 +200,9 @@ protected:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class LayoutRadialProgressItem : public LayoutMediaItem {
|
class LayoutRadialProgressItem : public LayoutMediaItemBase {
|
||||||
public:
|
public:
|
||||||
LayoutRadialProgressItem(HistoryItem *parent) : LayoutMediaItem(parent)
|
LayoutRadialProgressItem(HistoryItem *parent) : LayoutMediaItemBase(parent)
|
||||||
, _radial(0)
|
, _radial(0)
|
||||||
, a_iconOver(0, 0)
|
, a_iconOver(0, 0)
|
||||||
, _a_iconOver(animation(this, &LayoutRadialProgressItem::step_iconOver)) {
|
, _a_iconOver(animation(this, &LayoutRadialProgressItem::step_iconOver)) {
|
||||||
|
@ -269,27 +274,16 @@ protected:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class OverviewPaintContext : public PaintContext {
|
|
||||||
public:
|
|
||||||
OverviewPaintContext(uint64 ms, bool selecting) : PaintContext(ms, selecting), isAfterDate(false) {
|
|
||||||
}
|
|
||||||
const OverviewPaintContext *toOverviewPaintContext() const {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
bool isAfterDate;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct OverviewItemInfo : public BaseComponent<OverviewItemInfo> {
|
struct OverviewItemInfo : public BaseComponent<OverviewItemInfo> {
|
||||||
int top = 0;
|
int top = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class LayoutOverviewDate : public LayoutItem {
|
class LayoutOverviewDate : public LayoutOverviewItemBase {
|
||||||
public:
|
public:
|
||||||
LayoutOverviewDate(const QDate &date, bool month);
|
LayoutOverviewDate(const QDate &date, bool month);
|
||||||
|
|
||||||
void initDimensions() override;
|
void initDimensions() override;
|
||||||
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override;
|
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContextOverview *context) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QDate _date;
|
QDate _date;
|
||||||
|
@ -297,13 +291,13 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class LayoutOverviewPhoto : public LayoutMediaItem {
|
class LayoutOverviewPhoto : public LayoutMediaItemBase {
|
||||||
public:
|
public:
|
||||||
LayoutOverviewPhoto(PhotoData *photo, HistoryItem *parent);
|
LayoutOverviewPhoto(PhotoData *photo, HistoryItem *parent);
|
||||||
|
|
||||||
void initDimensions() override;
|
void initDimensions() override;
|
||||||
int32 resizeGetHeight(int32 width) override;
|
int32 resizeGetHeight(int32 width) override;
|
||||||
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override;
|
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContextOverview *context) const override;
|
||||||
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -321,7 +315,7 @@ public:
|
||||||
|
|
||||||
void initDimensions() override;
|
void initDimensions() override;
|
||||||
int32 resizeGetHeight(int32 width) override;
|
int32 resizeGetHeight(int32 width) override;
|
||||||
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override;
|
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContextOverview *context) const override;
|
||||||
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -354,7 +348,7 @@ public:
|
||||||
LayoutOverviewVoice(DocumentData *voice, HistoryItem *parent);
|
LayoutOverviewVoice(DocumentData *voice, HistoryItem *parent);
|
||||||
|
|
||||||
void initDimensions() override;
|
void initDimensions() override;
|
||||||
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override;
|
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContextOverview *context) const override;
|
||||||
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -388,7 +382,7 @@ public:
|
||||||
LayoutOverviewDocument(DocumentData *document, HistoryItem *parent);
|
LayoutOverviewDocument(DocumentData *document, HistoryItem *parent);
|
||||||
|
|
||||||
void initDimensions() override;
|
void initDimensions() override;
|
||||||
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override;
|
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContextOverview *context) const override;
|
||||||
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
||||||
|
|
||||||
virtual DocumentData *getDocument() const {
|
virtual DocumentData *getDocument() const {
|
||||||
|
@ -427,13 +421,13 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class LayoutOverviewLink : public LayoutMediaItem {
|
class LayoutOverviewLink : public LayoutMediaItemBase {
|
||||||
public:
|
public:
|
||||||
LayoutOverviewLink(HistoryMedia *media, HistoryItem *parent);
|
LayoutOverviewLink(HistoryMedia *media, HistoryItem *parent);
|
||||||
|
|
||||||
void initDimensions() override;
|
void initDimensions() override;
|
||||||
int32 resizeGetHeight(int32 width) override;
|
int32 resizeGetHeight(int32 width) override;
|
||||||
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override;
|
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContextOverview *context) const override;
|
||||||
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -457,316 +451,3 @@ private:
|
||||||
QVector<Link> _links;
|
QVector<Link> _links;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class InlinePaintContext : public PaintContext {
|
|
||||||
public:
|
|
||||||
InlinePaintContext(uint64 ms, bool selecting, bool paused, bool lastRow)
|
|
||||||
: PaintContext(ms, selecting)
|
|
||||||
, paused(paused)
|
|
||||||
, lastRow(lastRow) {
|
|
||||||
}
|
|
||||||
const InlinePaintContext *toInlinePaintContext() const override {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
bool paused, lastRow;
|
|
||||||
};
|
|
||||||
|
|
||||||
// this type used as a flag, we dynamic_cast<> to it
|
|
||||||
class SendInlineItemClickHandler : public ClickHandler {
|
|
||||||
public:
|
|
||||||
void onClick(Qt::MouseButton) const override {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class LayoutInlineItem : public LayoutItem {
|
|
||||||
public:
|
|
||||||
|
|
||||||
LayoutInlineItem(InlineResult *result) : _result(result) {
|
|
||||||
}
|
|
||||||
LayoutInlineItem(DocumentData *doc) : _doc(doc) {
|
|
||||||
}
|
|
||||||
// Not used anywhere currently.
|
|
||||||
//LayoutInlineItem(PhotoData *photo) : _photo(photo) {
|
|
||||||
//}
|
|
||||||
|
|
||||||
virtual void setPosition(int32 position);
|
|
||||||
int32 position() const;
|
|
||||||
|
|
||||||
virtual bool isFullLine() const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
virtual bool hasRightSkip() const {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
InlineResult *getInlineResult() const;
|
|
||||||
DocumentData *getDocument() const;
|
|
||||||
PhotoData *getPhoto() const;
|
|
||||||
|
|
||||||
virtual void preload() const;
|
|
||||||
|
|
||||||
void update();
|
|
||||||
|
|
||||||
// ClickHandlerHost interface
|
|
||||||
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override {
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override {
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
InlineResult *_result = nullptr;
|
|
||||||
DocumentData *_doc = nullptr;
|
|
||||||
PhotoData *_photo = nullptr;
|
|
||||||
|
|
||||||
ClickHandlerPtr _send = ClickHandlerPtr{ new SendInlineItemClickHandler() };
|
|
||||||
|
|
||||||
int _position = 0; // < 0 means removed from layout
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class LayoutInlineAbstractFile : public LayoutInlineItem {
|
|
||||||
public:
|
|
||||||
LayoutInlineAbstractFile(InlineResult *result);
|
|
||||||
// for saved gif layouts
|
|
||||||
LayoutInlineAbstractFile(DocumentData *doc);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
DocumentData *getShownDocument() const {
|
|
||||||
if (DocumentData *result = getDocument()) {
|
|
||||||
return result;
|
|
||||||
} else if (InlineResult *result = getInlineResult()) {
|
|
||||||
return result->document;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int content_width() const;
|
|
||||||
int content_height() const;
|
|
||||||
bool content_loading() const;
|
|
||||||
bool content_displayLoading() const;
|
|
||||||
bool content_loaded() const;
|
|
||||||
float64 content_progress() const;
|
|
||||||
void content_automaticLoad() const;
|
|
||||||
void content_forget();
|
|
||||||
FileLocation content_location() const;
|
|
||||||
QByteArray content_data() const;
|
|
||||||
ImagePtr content_thumb() const;
|
|
||||||
int content_duration() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DeleteSavedGifClickHandler : public LeftButtonClickHandler {
|
|
||||||
public:
|
|
||||||
DeleteSavedGifClickHandler(DocumentData *data) : _data(data) {
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void onClickImpl() const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
DocumentData *_data;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class LayoutInlineGif : public LayoutInlineAbstractFile {
|
|
||||||
public:
|
|
||||||
LayoutInlineGif(InlineResult *result);
|
|
||||||
LayoutInlineGif(DocumentData *doc, bool hasDeleteButton);
|
|
||||||
|
|
||||||
void setPosition(int32 position) override;
|
|
||||||
void initDimensions() override;
|
|
||||||
|
|
||||||
bool isFullLine() const override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool hasRightSkip() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override;
|
|
||||||
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
|
||||||
|
|
||||||
// ClickHandlerHost interface
|
|
||||||
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
|
||||||
|
|
||||||
~LayoutInlineGif();
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
QSize countFrameSize() const;
|
|
||||||
|
|
||||||
enum class StateFlag {
|
|
||||||
Over = 0x01,
|
|
||||||
DeleteOver = 0x02,
|
|
||||||
};
|
|
||||||
Q_DECLARE_FLAGS(StateFlags, StateFlag);
|
|
||||||
StateFlags _state;
|
|
||||||
friend inline StateFlags operator~(StateFlag flag) {
|
|
||||||
return ~StateFlags(flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
ClipReader *_gif = nullptr;
|
|
||||||
ClickHandlerPtr _delete;
|
|
||||||
bool gif() const {
|
|
||||||
return (!_gif || _gif == BadClipReader) ? false : true;
|
|
||||||
}
|
|
||||||
mutable QPixmap _thumb;
|
|
||||||
void prepareThumb(int32 width, int32 height, const QSize &frame) const;
|
|
||||||
|
|
||||||
void ensureAnimation() const;
|
|
||||||
bool isRadialAnimation(uint64 ms) const;
|
|
||||||
void step_radial(uint64 ms, bool timer);
|
|
||||||
|
|
||||||
void clipCallback(ClipReaderNotification notification);
|
|
||||||
|
|
||||||
struct AnimationData {
|
|
||||||
AnimationData(AnimationCreator creator)
|
|
||||||
: over(false)
|
|
||||||
, radial(creator) {
|
|
||||||
}
|
|
||||||
bool over;
|
|
||||||
FloatAnimation _a_over;
|
|
||||||
RadialAnimation radial;
|
|
||||||
};
|
|
||||||
mutable AnimationData *_animation = nullptr;
|
|
||||||
mutable FloatAnimation _a_deleteOver;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class LayoutInlinePhoto : public LayoutInlineItem {
|
|
||||||
public:
|
|
||||||
LayoutInlinePhoto(InlineResult *result);
|
|
||||||
// Not used anywhere currently.
|
|
||||||
//LayoutInlinePhoto(PhotoData *photo);
|
|
||||||
|
|
||||||
void initDimensions() override;
|
|
||||||
|
|
||||||
bool isFullLine() const override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool hasRightSkip() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override;
|
|
||||||
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
PhotoData *getShownPhoto() const {
|
|
||||||
if (PhotoData *result = getPhoto()) {
|
|
||||||
return result;
|
|
||||||
} else if (InlineResult *result = getInlineResult()) {
|
|
||||||
return result->photo;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
QSize countFrameSize() const;
|
|
||||||
|
|
||||||
int content_width() const;
|
|
||||||
int content_height() const;
|
|
||||||
bool content_loaded() const;
|
|
||||||
void content_forget();
|
|
||||||
|
|
||||||
mutable QPixmap _thumb;
|
|
||||||
mutable bool _thumbLoaded = false;
|
|
||||||
void prepareThumb(int32 width, int32 height, const QSize &frame) const;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class LayoutInlineSticker : public LayoutInlineAbstractFile {
|
|
||||||
public:
|
|
||||||
LayoutInlineSticker(InlineResult *result);
|
|
||||||
// Not used anywhere currently.
|
|
||||||
//LayoutInlineSticker(DocumentData *document);
|
|
||||||
|
|
||||||
void initDimensions() override;
|
|
||||||
|
|
||||||
bool isFullLine() const override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool hasRightSkip() const override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void preload() const override;
|
|
||||||
|
|
||||||
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override;
|
|
||||||
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
|
||||||
|
|
||||||
// ClickHandlerHost interface
|
|
||||||
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
QSize getThumbSize() const;
|
|
||||||
|
|
||||||
mutable FloatAnimation _a_over;
|
|
||||||
mutable bool _active = false;
|
|
||||||
|
|
||||||
mutable QPixmap _thumb;
|
|
||||||
mutable bool _thumbLoaded = false;
|
|
||||||
void prepareThumb() const;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class LayoutInlineVideo : public LayoutInlineAbstractFile {
|
|
||||||
public:
|
|
||||||
LayoutInlineVideo(InlineResult *result);
|
|
||||||
|
|
||||||
void initDimensions() override;
|
|
||||||
|
|
||||||
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override;
|
|
||||||
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
ClickHandlerPtr _link;
|
|
||||||
|
|
||||||
mutable QPixmap _thumb;
|
|
||||||
Text _title, _description;
|
|
||||||
QString _duration;
|
|
||||||
int32 _durationWidth;
|
|
||||||
|
|
||||||
void prepareThumb(int32 width, int32 height) const;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class LayoutInlineFile : public LayoutInlineAbstractFile {
|
|
||||||
public:
|
|
||||||
LayoutInlineFile(InlineResult *result);
|
|
||||||
|
|
||||||
void initDimensions() override;
|
|
||||||
|
|
||||||
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override;
|
|
||||||
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
Text _title, _description;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class LayoutInlineArticle : public LayoutInlineItem {
|
|
||||||
public:
|
|
||||||
LayoutInlineArticle(InlineResult *result, bool withThumb);
|
|
||||||
|
|
||||||
void initDimensions() override;
|
|
||||||
int32 resizeGetHeight(int32 width) override;
|
|
||||||
|
|
||||||
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override;
|
|
||||||
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
ClickHandlerPtr _url, _link;
|
|
||||||
|
|
||||||
bool _withThumb;
|
|
||||||
mutable QPixmap _thumb;
|
|
||||||
Text _title, _description;
|
|
||||||
QString _letter, _urlText;
|
|
||||||
int32 _urlWidth;
|
|
||||||
|
|
||||||
void prepareThumb(int32 width, int32 height) const;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
|
@ -812,11 +812,11 @@ void MainWidget::ui_repaintHistoryItem(const HistoryItem *item) {
|
||||||
if (overview) overview->ui_repaintHistoryItem(item);
|
if (overview) overview->ui_repaintHistoryItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::ui_repaintInlineItem(const LayoutInlineItem *layout) {
|
void MainWidget::ui_repaintInlineItem(const InlineBots::Layout::ItemBase *layout) {
|
||||||
history.ui_repaintInlineItem(layout);
|
history.ui_repaintInlineItem(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MainWidget::ui_isInlineItemVisible(const LayoutInlineItem *layout) {
|
bool MainWidget::ui_isInlineItemVisible(const InlineBots::Layout::ItemBase *layout) {
|
||||||
return history.ui_isInlineItemVisible(layout);
|
return history.ui_isInlineItemVisible(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1895,7 +1895,7 @@ void MainWidget::documentLoadRetry() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::inlineResultLoadProgress(FileLoader *loader) {
|
void MainWidget::inlineResultLoadProgress(FileLoader *loader) {
|
||||||
//InlineResult *result = App::inlineResultFromLoader(loader);
|
//InlineBots::Result *result = InlineBots::resultFromLoader(loader);
|
||||||
//if (!result) return;
|
//if (!result) return;
|
||||||
|
|
||||||
//result->loaded();
|
//result->loaded();
|
||||||
|
@ -1904,7 +1904,7 @@ void MainWidget::inlineResultLoadProgress(FileLoader *loader) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::inlineResultLoadFailed(FileLoader *loader, bool started) {
|
void MainWidget::inlineResultLoadFailed(FileLoader *loader, bool started) {
|
||||||
//InlineResult *result = App::inlineResultFromLoader(loader);
|
//InlineBots::Result *result = InlineBots::resultFromLoader(loader);
|
||||||
//if (!result) return;
|
//if (!result) return;
|
||||||
|
|
||||||
//result->loaded();
|
//result->loaded();
|
||||||
|
|
|
@ -197,6 +197,14 @@ enum NotifySettingStatus {
|
||||||
NotifySettingSetNotify,
|
NotifySettingSetNotify,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace InlineBots {
|
||||||
|
namespace Layout {
|
||||||
|
|
||||||
|
class ItemBase;
|
||||||
|
|
||||||
|
} // namespace Layout
|
||||||
|
} // namespace InlineBots
|
||||||
|
|
||||||
class MainWidget : public TWidget, public RPCSender {
|
class MainWidget : public TWidget, public RPCSender {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -435,8 +443,8 @@ public:
|
||||||
bool isItemVisible(HistoryItem *item);
|
bool isItemVisible(HistoryItem *item);
|
||||||
|
|
||||||
void ui_repaintHistoryItem(const HistoryItem *item);
|
void ui_repaintHistoryItem(const HistoryItem *item);
|
||||||
void ui_repaintInlineItem(const LayoutInlineItem *layout);
|
void ui_repaintInlineItem(const InlineBots::Layout::ItemBase *layout);
|
||||||
bool ui_isInlineItemVisible(const LayoutInlineItem *layout);
|
bool ui_isInlineItemVisible(const InlineBots::Layout::ItemBase *layout);
|
||||||
bool ui_isInlineItemBeingChosen();
|
bool ui_isInlineItemBeingChosen();
|
||||||
void ui_showPeerHistory(quint64 peer, qint32 msgId, bool back);
|
void ui_showPeerHistory(quint64 peer, qint32 msgId, bool back);
|
||||||
PeerData *ui_getPeerForMouseAction();
|
PeerData *ui_getPeerForMouseAction();
|
||||||
|
|
|
@ -809,7 +809,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
|
||||||
p.setClipRect(r);
|
p.setClipRect(r);
|
||||||
}
|
}
|
||||||
uint64 ms = getms();
|
uint64 ms = getms();
|
||||||
OverviewPaintContext context(ms, _selMode);
|
PaintContextOverview context(ms, _selMode);
|
||||||
|
|
||||||
if (_history->overview[_type].isEmpty() && (!_migrated || !_history->overviewLoaded(_type) || _migrated->overview[_type].isEmpty())) {
|
if (_history->overview[_type].isEmpty() && (!_migrated || !_history->overviewLoaded(_type) || _migrated->overview[_type].isEmpty())) {
|
||||||
QPoint dogPos((_width - st::msgDogImg.pxWidth()) / 2, ((height() - st::msgDogImg.pxHeight()) * 4) / 9);
|
QPoint dogPos((_width - st::msgDogImg.pxWidth()) / 2, ((height() - st::msgDogImg.pxHeight()) * 4) / 9);
|
||||||
|
@ -908,7 +908,7 @@ void OverviewInner::onUpdateSelected() {
|
||||||
upon = false;
|
upon = false;
|
||||||
}
|
}
|
||||||
if (i >= 0) {
|
if (i >= 0) {
|
||||||
if (LayoutMediaItem *media = _items.at(i)->toLayoutMediaItem()) {
|
if (LayoutMediaItemBase *media = _items.at(i)->toLayoutMediaItem()) {
|
||||||
item = media->getItem();
|
item = media->getItem();
|
||||||
index = i;
|
index = i;
|
||||||
if (upon) {
|
if (upon) {
|
||||||
|
@ -945,7 +945,7 @@ void OverviewInner::onUpdateSelected() {
|
||||||
j = _reversed ? (l - i - 1) : i;
|
j = _reversed ? (l - i - 1) : i;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LayoutMediaItem *media = _items.at(i)->toLayoutMediaItem()) {
|
if (LayoutMediaItemBase *media = _items.at(i)->toLayoutMediaItem()) {
|
||||||
item = media->getItem();
|
item = media->getItem();
|
||||||
index = i;
|
index = i;
|
||||||
media->getState(lnk, cursorState, m.x() - _rowsLeft, m.y() - _marginTop - top);
|
media->getState(lnk, cursorState, m.x() - _rowsLeft, m.y() - _marginTop - top);
|
||||||
|
@ -1632,7 +1632,7 @@ void OverviewInner::mediaOverviewUpdated() {
|
||||||
allGood = false;
|
allGood = false;
|
||||||
}
|
}
|
||||||
HistoryItem *item = App::histItemById(itemChannel(msgid), itemMsgId(msgid));
|
HistoryItem *item = App::histItemById(itemChannel(msgid), itemMsgId(msgid));
|
||||||
LayoutMediaItem *layout = layoutPrepare(item);
|
LayoutMediaItemBase *layout = layoutPrepare(item);
|
||||||
if (!layout) continue;
|
if (!layout) continue;
|
||||||
|
|
||||||
setLayoutItem(index, layout, 0);
|
setLayoutItem(index, layout, 0);
|
||||||
|
@ -1678,7 +1678,7 @@ void OverviewInner::mediaOverviewUpdated() {
|
||||||
allGood = false;
|
allGood = false;
|
||||||
}
|
}
|
||||||
HistoryItem *item = App::histItemById(itemChannel(msgid), itemMsgId(msgid));
|
HistoryItem *item = App::histItemById(itemChannel(msgid), itemMsgId(msgid));
|
||||||
LayoutMediaItem *layout = layoutPrepare(item);
|
LayoutMediaItemBase *layout = layoutPrepare(item);
|
||||||
if (!layout) continue;
|
if (!layout) continue;
|
||||||
|
|
||||||
if (withDates) {
|
if (withDates) {
|
||||||
|
@ -1840,8 +1840,8 @@ void OverviewInner::recountMargins() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutMediaItem *OverviewInner::layoutPrepare(HistoryItem *item) {
|
LayoutMediaItemBase *OverviewInner::layoutPrepare(HistoryItem *item) {
|
||||||
if (!item) return 0;
|
if (!item) return nullptr;
|
||||||
|
|
||||||
LayoutItems::const_iterator i = _layoutItems.cend();
|
LayoutItems::const_iterator i = _layoutItems.cend();
|
||||||
HistoryMedia *media = item->getMedia();
|
HistoryMedia *media = item->getMedia();
|
||||||
|
@ -1879,10 +1879,10 @@ LayoutMediaItem *OverviewInner::layoutPrepare(HistoryItem *item) {
|
||||||
i.value()->initDimensions();
|
i.value()->initDimensions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (i == _layoutItems.cend()) ? 0 : i.value();
|
return (i == _layoutItems.cend()) ? nullptr : i.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutItem *OverviewInner::layoutPrepare(const QDate &date, bool month) {
|
LayoutOverviewItemBase *OverviewInner::layoutPrepare(const QDate &date, bool month) {
|
||||||
int32 key = date.year() * 100 + date.month();
|
int32 key = date.year() * 100 + date.month();
|
||||||
if (!month) key = key * 100 + date.day();
|
if (!month) key = key * 100 + date.day();
|
||||||
LayoutDates::const_iterator i = _layoutDates.constFind(key);
|
LayoutDates::const_iterator i = _layoutDates.constFind(key);
|
||||||
|
@ -1893,7 +1893,7 @@ LayoutItem *OverviewInner::layoutPrepare(const QDate &date, bool month) {
|
||||||
return i.value();
|
return i.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 OverviewInner::setLayoutItem(int32 index, LayoutItem *item, int32 top) {
|
int32 OverviewInner::setLayoutItem(int32 index, LayoutOverviewItemBase *item, int32 top) {
|
||||||
if (_items.size() > index) {
|
if (_items.size() > index) {
|
||||||
_items[index] = item;
|
_items[index] = item;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -152,15 +152,15 @@ private:
|
||||||
|
|
||||||
int32 _rowsLeft, _rowWidth;
|
int32 _rowsLeft, _rowWidth;
|
||||||
|
|
||||||
typedef QVector<LayoutItem*> Items;
|
typedef QVector<LayoutOverviewItemBase*> Items;
|
||||||
Items _items;
|
Items _items;
|
||||||
typedef QMap<HistoryItem*, LayoutMediaItem*> LayoutItems;
|
typedef QMap<HistoryItem*, LayoutMediaItemBase*> LayoutItems;
|
||||||
LayoutItems _layoutItems;
|
LayoutItems _layoutItems;
|
||||||
typedef QMap<int32, LayoutOverviewDate*> LayoutDates;
|
typedef QMap<int32, LayoutOverviewDate*> LayoutDates;
|
||||||
LayoutDates _layoutDates;
|
LayoutDates _layoutDates;
|
||||||
LayoutMediaItem *layoutPrepare(HistoryItem *item);
|
LayoutMediaItemBase *layoutPrepare(HistoryItem *item);
|
||||||
LayoutItem *layoutPrepare(const QDate &date, bool month);
|
LayoutOverviewItemBase *layoutPrepare(const QDate &date, bool month);
|
||||||
int32 setLayoutItem(int32 index, LayoutItem *item, int32 top);
|
int32 setLayoutItem(int32 index, LayoutOverviewItemBase *item, int32 top);
|
||||||
|
|
||||||
FlatInput _search;
|
FlatInput _search;
|
||||||
IconedButton _cancelSearch;
|
IconedButton _cancelSearch;
|
||||||
|
|
|
@ -1442,219 +1442,6 @@ WebPageData::WebPageData(const WebPageId &id, WebPageType type, const QString &u
|
||||||
, pendingTill(pendingTill) {
|
, pendingTill(pendingTill) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QString InlineResultSendData::getLayoutTitle(InlineResult *owner) const {
|
|
||||||
return owner->title;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString InlineResultSendData::getLayoutDescription(InlineResult *owner) const {
|
|
||||||
return owner->description;
|
|
||||||
}
|
|
||||||
|
|
||||||
InlineResultSendData::SentMTPMessageFields InlineResultSendText::getSentMessageFields(InlineResult*) const {
|
|
||||||
SentMTPMessageFields result;
|
|
||||||
result.text = MTP_string(_message);
|
|
||||||
result.entities = linksToMTP(_entities);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
InlineResultSendData::SentMTPMessageFields InlineResultSendGeo::getSentMessageFields(InlineResult*) const {
|
|
||||||
SentMTPMessageFields result;
|
|
||||||
result.media = MTP_messageMediaGeo(MTP_geoPoint(MTP_double(_location.lon), MTP_double(_location.lat)));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
InlineResultSendData::SentMTPMessageFields InlineResultSendVenue::getSentMessageFields(InlineResult*) const {
|
|
||||||
SentMTPMessageFields result;
|
|
||||||
result.media = MTP_messageMediaVenue(MTP_geoPoint(MTP_double(_location.lon), MTP_double(_location.lat)), MTP_string(_title), MTP_string(_address), MTP_string(_provider), MTP_string(_venueId));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
InlineResultSendData::SentMTPMessageFields InlineResultSendContact::getSentMessageFields(InlineResult*) const {
|
|
||||||
SentMTPMessageFields result;
|
|
||||||
result.media = MTP_messageMediaContact(MTP_string(_phoneNumber), MTP_string(_firstName), MTP_string(_lastName), MTP_int(0));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString InlineResultSendContact::getLayoutDescription(InlineResult *owner) const {
|
|
||||||
return App::formatPhone(_phoneNumber) + '\n' + owner->description;
|
|
||||||
}
|
|
||||||
|
|
||||||
InlineResultSendData::SentMTPMessageFields InlineResultSendPhoto::getSentMessageFields(InlineResult *owner) const {
|
|
||||||
SentMTPMessageFields result;
|
|
||||||
|
|
||||||
QImage fileThumb(owner->thumb->pix().toImage());
|
|
||||||
|
|
||||||
QVector<MTPPhotoSize> photoSizes;
|
|
||||||
|
|
||||||
QPixmap thumb = (fileThumb.width() > 100 || fileThumb.height() > 100) ? QPixmap::fromImage(fileThumb.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(fileThumb);
|
|
||||||
ImagePtr thumbPtr = ImagePtr(thumb, "JPG");
|
|
||||||
photoSizes.push_back(MTP_photoSize(MTP_string("s"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(thumb.width()), MTP_int(thumb.height()), MTP_int(0)));
|
|
||||||
|
|
||||||
QSize medium = resizeKeepAspect(owner->width, owner->height, 320, 320);
|
|
||||||
photoSizes.push_back(MTP_photoSize(MTP_string("m"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(medium.width()), MTP_int(medium.height()), MTP_int(0)));
|
|
||||||
|
|
||||||
photoSizes.push_back(MTP_photoSize(MTP_string("x"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(owner->width), MTP_int(owner->height), MTP_int(0)));
|
|
||||||
|
|
||||||
uint64 photoId = rand_value<uint64>();
|
|
||||||
PhotoData *ph = App::photoSet(photoId, 0, 0, unixtime(), thumbPtr, ImagePtr(medium.width(), medium.height()), ImagePtr(owner->width, owner->height));
|
|
||||||
MTPPhoto photo = MTP_photo(MTP_long(photoId), MTP_long(0), MTP_int(ph->date), MTP_vector<MTPPhotoSize>(photoSizes));
|
|
||||||
|
|
||||||
result.media = MTP_messageMediaPhoto(photo, MTP_string(_caption));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
InlineResultSendData::SentMTPMessageFields InlineResultSendFile::getSentMessageFields(InlineResult *owner) const {
|
|
||||||
SentMTPMessageFields result;
|
|
||||||
|
|
||||||
MTPPhotoSize thumbSize;
|
|
||||||
QPixmap thumb;
|
|
||||||
int32 tw = owner->thumb->width(), th = owner->thumb->height();
|
|
||||||
if (tw > 0 && th > 0 && tw < 20 * th && th < 20 * tw && owner->thumb->loaded()) {
|
|
||||||
if (tw > th) {
|
|
||||||
if (tw > 90) {
|
|
||||||
th = th * 90 / tw;
|
|
||||||
tw = 90;
|
|
||||||
}
|
|
||||||
} else if (th > 90) {
|
|
||||||
tw = tw * 90 / th;
|
|
||||||
th = 90;
|
|
||||||
}
|
|
||||||
thumbSize = MTP_photoSize(MTP_string(""), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(tw), MTP_int(th), MTP_int(0));
|
|
||||||
thumb = owner->thumb->pixNoCache(tw, th, ImagePixSmooth);
|
|
||||||
} else {
|
|
||||||
tw = th = 0;
|
|
||||||
thumbSize = MTP_photoSizeEmpty(MTP_string(""));
|
|
||||||
}
|
|
||||||
uint64 docId = rand_value<uint64>();
|
|
||||||
QVector<MTPDocumentAttribute> attributes;
|
|
||||||
|
|
||||||
int duration = getSentDuration(owner);
|
|
||||||
QSize dimensions = getSentDimensions(owner);
|
|
||||||
using Type = InlineResult::Type;
|
|
||||||
if (owner->type == Type::Gif) {
|
|
||||||
attributes.push_back(MTP_documentAttributeFilename(MTP_string((owner->content_type == qstr("video/mp4") ? "animation.gif.mp4" : "animation.gif"))));
|
|
||||||
attributes.push_back(MTP_documentAttributeAnimated());
|
|
||||||
attributes.push_back(MTP_documentAttributeVideo(MTP_int(duration), MTP_int(dimensions.width()), MTP_int(dimensions.height())));
|
|
||||||
} else if (owner->type == Type::Video) {
|
|
||||||
attributes.push_back(MTP_documentAttributeVideo(MTP_int(duration), MTP_int(dimensions.width()), MTP_int(dimensions.height())));
|
|
||||||
}
|
|
||||||
MTPDocument document = MTP_document(MTP_long(docId), MTP_long(0), MTP_int(unixtime()), MTP_string(owner->content_type), MTP_int(owner->data().size()), thumbSize, MTP_int(MTP::maindc()), MTP_vector<MTPDocumentAttribute>(attributes));
|
|
||||||
if (tw > 0 && th > 0) {
|
|
||||||
App::feedDocument(document, thumb);
|
|
||||||
}
|
|
||||||
Local::writeStickerImage(mediaKey(DocumentFileLocation, MTP::maindc(), docId), owner->data());
|
|
||||||
|
|
||||||
result.media = MTP_messageMediaDocument(document, MTP_string(_caption));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int InlineResultSendFile::getSentDuration(InlineResult *owner) const {
|
|
||||||
return (_document && _document->duration()) ? _document->duration() : owner->duration;
|
|
||||||
}
|
|
||||||
QSize InlineResultSendFile::getSentDimensions(InlineResult *owner) const {
|
|
||||||
return (!_document || _document->dimensions.isEmpty()) ? QSize(owner->width, owner->height) : _document->dimensions;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InlineResult::automaticLoadGif() {
|
|
||||||
if (loaded() || type != Type::Gif || (content_type != qstr("video/mp4") && content_type != "image/gif")) return;
|
|
||||||
|
|
||||||
if (_loader != CancelledWebFileLoader) {
|
|
||||||
// if load at least anywhere
|
|
||||||
bool loadFromCloud = !(cAutoDownloadGif() & dbiadNoPrivate) || !(cAutoDownloadGif() & dbiadNoGroups);
|
|
||||||
saveFile(QString(), loadFromCloud ? LoadFromCloudOrLocal : LoadFromLocalOnly, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InlineResult::automaticLoadSettingsChangedGif() {
|
|
||||||
if (loaded() || _loader != CancelledWebFileLoader) return;
|
|
||||||
_loader = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InlineResult::saveFile(const QString &toFile, LoadFromCloudSetting fromCloud, bool autoLoading) {
|
|
||||||
if (loaded()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_loader == CancelledWebFileLoader) _loader = 0;
|
|
||||||
if (_loader) {
|
|
||||||
if (!_loader->setFileName(toFile)) {
|
|
||||||
cancelFile();
|
|
||||||
_loader = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_loader) {
|
|
||||||
if (fromCloud == LoadFromCloudOrLocal) _loader->permitLoadFromCloud();
|
|
||||||
} else {
|
|
||||||
_loader = new webFileLoader(content_url, toFile, fromCloud, autoLoading);
|
|
||||||
App::regInlineResultLoader(_loader, this);
|
|
||||||
|
|
||||||
_loader->connect(_loader, SIGNAL(progress(FileLoader*)), App::main(), SLOT(inlineResultLoadProgress(FileLoader*)));
|
|
||||||
_loader->connect(_loader, SIGNAL(failed(FileLoader*,bool)), App::main(), SLOT(inlineResultLoadFailed(FileLoader*,bool)));
|
|
||||||
_loader->start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InlineResult::cancelFile() {
|
|
||||||
if (!loading()) return;
|
|
||||||
|
|
||||||
App::unregInlineResultLoader(_loader);
|
|
||||||
|
|
||||||
webFileLoader *l = _loader;
|
|
||||||
_loader = CancelledWebFileLoader;
|
|
||||||
if (l) {
|
|
||||||
l->cancel();
|
|
||||||
l->deleteLater();
|
|
||||||
l->stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray InlineResult::data() const {
|
|
||||||
return _data;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InlineResult::loading() const {
|
|
||||||
return _loader && _loader != CancelledWebFileLoader;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InlineResult::loaded() const {
|
|
||||||
if (loading() && _loader->done()) {
|
|
||||||
App::unregInlineResultLoader(_loader);
|
|
||||||
if (_loader->fileType() == mtpc_storage_fileUnknown) {
|
|
||||||
_loader->deleteLater();
|
|
||||||
_loader->stop();
|
|
||||||
_loader = CancelledWebFileLoader;
|
|
||||||
} else {
|
|
||||||
InlineResult *that = const_cast<InlineResult*>(this);
|
|
||||||
that->_data = _loader->bytes();
|
|
||||||
|
|
||||||
_loader->deleteLater();
|
|
||||||
_loader->stop();
|
|
||||||
_loader = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return !_data.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InlineResult::displayLoading() const {
|
|
||||||
return loading() ? (!_loader->loadingLocal() || !_loader->autoLoading()) : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InlineResult::forget() {
|
|
||||||
thumb->forget();
|
|
||||||
_data.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
float64 InlineResult::progress() const {
|
|
||||||
return loading() ? _loader->currentProgress() : (loaded() ? 1 : 0); return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
InlineResult::~InlineResult() {
|
|
||||||
cancelFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PeerOpenClickHandler::onClickImpl() const {
|
void PeerOpenClickHandler::onClickImpl() const {
|
||||||
if (App::main()) {
|
if (App::main()) {
|
||||||
if (peer() && peer()->isChannel() && App::main()->historyPeer() != peer()) {
|
if (peer() && peer()->isChannel() && App::main()->historyPeer() != peer()) {
|
||||||
|
|
|
@ -452,7 +452,6 @@ private:
|
||||||
QString _restrictionReason;
|
QString _restrictionReason;
|
||||||
|
|
||||||
};
|
};
|
||||||
static UserData * const InlineBotLookingUpData = SharedMemoryLocation<UserData, 0>();
|
|
||||||
|
|
||||||
class ChatData : public PeerData {
|
class ChatData : public PeerData {
|
||||||
public:
|
public:
|
||||||
|
@ -1246,274 +1245,6 @@ struct WebPageData {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class InlineResult;
|
|
||||||
|
|
||||||
// Abstract class describing the message that will be
|
|
||||||
// sent if the user chooses this inline bot result.
|
|
||||||
// For each type of message that can be sent there will be a subclass.
|
|
||||||
class InlineResultSendData {
|
|
||||||
public:
|
|
||||||
InlineResultSendData() = default;
|
|
||||||
InlineResultSendData(const InlineResultSendData &other) = delete;
|
|
||||||
InlineResultSendData &operator=(const InlineResultSendData &other) = delete;
|
|
||||||
virtual ~InlineResultSendData() = default;
|
|
||||||
|
|
||||||
virtual bool isValid() const = 0;
|
|
||||||
|
|
||||||
virtual DocumentData *getSentDocument() const {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
virtual PhotoData *getSentPhoto() const {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
virtual QString getSentCaption() const {
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
struct SentMTPMessageFields {
|
|
||||||
MTPString text = MTP_string("");
|
|
||||||
MTPVector<MTPMessageEntity> entities = MTPnullEntities;
|
|
||||||
MTPMessageMedia media = MTP_messageMediaEmpty();
|
|
||||||
};
|
|
||||||
virtual SentMTPMessageFields getSentMessageFields(InlineResult *owner) const = 0;
|
|
||||||
|
|
||||||
virtual bool hasLocationCoords() const {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
virtual bool getLocationCoords(LocationCoords *location) const {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
virtual QString getLayoutTitle(InlineResult *owner) const;
|
|
||||||
virtual QString getLayoutDescription(InlineResult *owner) const;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// Plain text message.
|
|
||||||
class InlineResultSendText : public InlineResultSendData {
|
|
||||||
public:
|
|
||||||
InlineResultSendText(const QString &message, const EntitiesInText &entities, bool noWebPage)
|
|
||||||
: _message(message)
|
|
||||||
, _entities(entities)
|
|
||||||
, _noWebPage(noWebPage) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isValid() const override {
|
|
||||||
return !_message.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
SentMTPMessageFields getSentMessageFields(InlineResult *owner) const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString _message;
|
|
||||||
EntitiesInText _entities;
|
|
||||||
bool _noWebPage;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// Message with geo location point media.
|
|
||||||
class InlineResultSendGeo : public InlineResultSendData {
|
|
||||||
public:
|
|
||||||
InlineResultSendGeo(const MTPDgeoPoint &point) : _location(point) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isValid() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
SentMTPMessageFields getSentMessageFields(InlineResult *owner) const override;
|
|
||||||
|
|
||||||
bool hasLocationCoords() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool getLocationCoords(LocationCoords *location) const override {
|
|
||||||
t_assert(location != nullptr);
|
|
||||||
*location = _location;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
LocationCoords _location;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// Message with venue media.
|
|
||||||
class InlineResultSendVenue : public InlineResultSendData {
|
|
||||||
public:
|
|
||||||
InlineResultSendVenue(const MTPDgeoPoint &point, const QString &venueId,
|
|
||||||
const QString &provider, const QString &title, const QString &address)
|
|
||||||
: _location(point)
|
|
||||||
, _venueId(venueId)
|
|
||||||
, _provider(provider)
|
|
||||||
, _title(title)
|
|
||||||
, _address(address) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isValid() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
SentMTPMessageFields getSentMessageFields(InlineResult *owner) const override;
|
|
||||||
|
|
||||||
bool getLocationCoords(LocationCoords *location) const override {
|
|
||||||
if (location) {
|
|
||||||
*location = _location;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
LocationCoords _location;
|
|
||||||
QString _venueId, _provider, _title, _address;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// Message with shared contact media.
|
|
||||||
class InlineResultSendContact : public InlineResultSendData {
|
|
||||||
public:
|
|
||||||
InlineResultSendContact(const QString &firstName, const QString &lastName, const QString &phoneNumber)
|
|
||||||
: _firstName(firstName)
|
|
||||||
, _lastName(lastName)
|
|
||||||
, _phoneNumber(phoneNumber) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isValid() const override {
|
|
||||||
return (!_firstName.isEmpty() || !_lastName.isEmpty()) && !_phoneNumber.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
SentMTPMessageFields getSentMessageFields(InlineResult *owner) const override;
|
|
||||||
|
|
||||||
QString getLayoutDescription(InlineResult *owner) const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString _firstName, _lastName, _phoneNumber;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// Message with photo.
|
|
||||||
class InlineResultSendPhoto : public InlineResultSendData {
|
|
||||||
public:
|
|
||||||
InlineResultSendPhoto(PhotoData *photo, const QString &url, const QString &caption)
|
|
||||||
: _photo(photo)
|
|
||||||
, _url(url)
|
|
||||||
, _caption(caption) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isValid() const override {
|
|
||||||
return _photo || !_url.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
PhotoData *getSentPhoto() const override {
|
|
||||||
return _photo;
|
|
||||||
}
|
|
||||||
QString getSentCaption() const override {
|
|
||||||
return _caption;
|
|
||||||
}
|
|
||||||
SentMTPMessageFields getSentMessageFields(InlineResult *owner) const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
PhotoData *_photo;
|
|
||||||
QString _url, _caption;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// Message with file.
|
|
||||||
class InlineResultSendFile : public InlineResultSendData {
|
|
||||||
public:
|
|
||||||
InlineResultSendFile(DocumentData *document, const QString &url, const QString &caption)
|
|
||||||
: _document(document)
|
|
||||||
, _url(url)
|
|
||||||
, _caption(caption) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isValid() const override {
|
|
||||||
return _document || !_url.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
DocumentData *getSentDocument() const override {
|
|
||||||
return _document;
|
|
||||||
}
|
|
||||||
QString getSentCaption() const override {
|
|
||||||
return _caption;
|
|
||||||
}
|
|
||||||
SentMTPMessageFields getSentMessageFields(InlineResult *owner) const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
DocumentData *_document;
|
|
||||||
QString _url, _caption;
|
|
||||||
|
|
||||||
int getSentDuration(InlineResult *owner) const;
|
|
||||||
QSize getSentDimensions(InlineResult *owner) const;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class InlineResult {
|
|
||||||
public:
|
|
||||||
enum class Type {
|
|
||||||
Unknown,
|
|
||||||
Photo,
|
|
||||||
Video,
|
|
||||||
Audio,
|
|
||||||
Sticker,
|
|
||||||
File,
|
|
||||||
Gif,
|
|
||||||
Article,
|
|
||||||
Contact,
|
|
||||||
Venue,
|
|
||||||
};
|
|
||||||
static QMap<QString, Type> getTypesMap() {
|
|
||||||
QMap<QString, Type> result;
|
|
||||||
result.insert(qsl("photo"), Type::Photo);
|
|
||||||
result.insert(qsl("video"), Type::Video);
|
|
||||||
result.insert(qsl("audio"), Type::Audio);
|
|
||||||
result.insert(qsl("sticker"), Type::Sticker);
|
|
||||||
result.insert(qsl("file"), Type::File);
|
|
||||||
result.insert(qsl("gif"), Type::Gif);
|
|
||||||
result.insert(qsl("article"), Type::Article);
|
|
||||||
result.insert(qsl("contact"), Type::Contact);
|
|
||||||
result.insert(qsl("venue"), Type::Venue);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
InlineResult(uint64 queryId, Type type) : queryId(queryId), type(type) {
|
|
||||||
}
|
|
||||||
InlineResult(const InlineResult &other) = delete;
|
|
||||||
InlineResult &operator=(const InlineResult &other) = delete;
|
|
||||||
|
|
||||||
uint64 queryId;
|
|
||||||
QString id;
|
|
||||||
Type type;
|
|
||||||
DocumentData *document = nullptr;
|
|
||||||
PhotoData *photo = nullptr;
|
|
||||||
QString title, description, url, thumb_url;
|
|
||||||
QString content_type, content_url;
|
|
||||||
int width = 0;
|
|
||||||
int height = 0;
|
|
||||||
int duration = 0;
|
|
||||||
|
|
||||||
UniquePointer<InlineResultSendData> sendData;
|
|
||||||
|
|
||||||
ImagePtr thumb;
|
|
||||||
|
|
||||||
void automaticLoadGif();
|
|
||||||
void automaticLoadSettingsChangedGif();
|
|
||||||
void saveFile(const QString &toFile, LoadFromCloudSetting fromCloud, bool autoLoading);
|
|
||||||
void cancelFile();
|
|
||||||
|
|
||||||
QByteArray data() const;
|
|
||||||
bool loading() const;
|
|
||||||
bool loaded() const;
|
|
||||||
bool displayLoading() const;
|
|
||||||
void forget();
|
|
||||||
float64 progress() const;
|
|
||||||
|
|
||||||
~InlineResult();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QByteArray _data;
|
|
||||||
mutable webFileLoader *_loader = nullptr;
|
|
||||||
|
|
||||||
};
|
|
||||||
typedef QList<InlineResult*> InlineResults;
|
|
||||||
|
|
||||||
QString saveFileName(const QString &title, const QString &filter, const QString &prefix, QString name, bool savingAs, const QDir &dir = QDir());
|
QString saveFileName(const QString &title, const QString &filter, const QString &prefix, QString name, bool savingAs, const QDir &dir = QDir());
|
||||||
MsgId clientMsgId();
|
MsgId clientMsgId();
|
||||||
|
|
||||||
|
|
|
@ -1075,6 +1075,10 @@
|
||||||
<ClCompile Include="SourceFiles\gui\twidget.cpp" />
|
<ClCompile Include="SourceFiles\gui\twidget.cpp" />
|
||||||
<ClCompile Include="SourceFiles\history.cpp" />
|
<ClCompile Include="SourceFiles\history.cpp" />
|
||||||
<ClCompile Include="SourceFiles\historywidget.cpp" />
|
<ClCompile Include="SourceFiles\historywidget.cpp" />
|
||||||
|
<ClCompile Include="SourceFiles\inline_bots\inline_bot_layout_internal.cpp" />
|
||||||
|
<ClCompile Include="SourceFiles\inline_bots\inline_bot_layout_item.cpp" />
|
||||||
|
<ClCompile Include="SourceFiles\inline_bots\inline_bot_result.cpp" />
|
||||||
|
<ClCompile Include="SourceFiles\inline_bots\inline_bot_send_data.cpp" />
|
||||||
<ClCompile Include="SourceFiles\intro\introwidget.cpp" />
|
<ClCompile Include="SourceFiles\intro\introwidget.cpp" />
|
||||||
<ClCompile Include="SourceFiles\intro\introcode.cpp" />
|
<ClCompile Include="SourceFiles\intro\introcode.cpp" />
|
||||||
<ClCompile Include="SourceFiles\intro\introphone.cpp" />
|
<ClCompile Include="SourceFiles\intro\introphone.cpp" />
|
||||||
|
@ -1204,6 +1208,10 @@
|
||||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/basic_types.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui"</Command>
|
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/basic_types.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui"</Command>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
<ClInclude Include="SourceFiles\gui\style.h" />
|
<ClInclude Include="SourceFiles\gui\style.h" />
|
||||||
|
<ClInclude Include="SourceFiles\inline_bots\inline_bot_layout_internal.h" />
|
||||||
|
<ClInclude Include="SourceFiles\inline_bots\inline_bot_layout_item.h" />
|
||||||
|
<ClInclude Include="SourceFiles\inline_bots\inline_bot_result.h" />
|
||||||
|
<ClInclude Include="SourceFiles\inline_bots\inline_bot_send_data.h" />
|
||||||
<ClInclude Include="SourceFiles\mtproto\auth_key.h" />
|
<ClInclude Include="SourceFiles\mtproto\auth_key.h" />
|
||||||
<CustomBuild Include="SourceFiles\mtproto\connection.h">
|
<CustomBuild Include="SourceFiles\mtproto\connection.h">
|
||||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||||
|
|
|
@ -52,6 +52,9 @@
|
||||||
<Filter Include="ThirdParty\minizip">
|
<Filter Include="ThirdParty\minizip">
|
||||||
<UniqueIdentifier>{1abe710c-3c36-484c-b2a5-881c29a051c2}</UniqueIdentifier>
|
<UniqueIdentifier>{1abe710c-3c36-484c-b2a5-881c29a051c2}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="inline_bots">
|
||||||
|
<UniqueIdentifier>{da3d0334-a011-41dd-a8e0-9b701afacfb3}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="SourceFiles\main.cpp">
|
<ClCompile Include="SourceFiles\main.cpp">
|
||||||
|
@ -972,6 +975,18 @@
|
||||||
<ClCompile Include="GeneratedFiles\Release\moc_basic_types.cpp">
|
<ClCompile Include="GeneratedFiles\Release\moc_basic_types.cpp">
|
||||||
<Filter>Generated Files\Release</Filter>
|
<Filter>Generated Files\Release</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="SourceFiles\inline_bots\inline_bot_result.cpp">
|
||||||
|
<Filter>inline_bots</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="SourceFiles\inline_bots\inline_bot_layout_item.cpp">
|
||||||
|
<Filter>inline_bots</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="SourceFiles\inline_bots\inline_bot_send_data.cpp">
|
||||||
|
<Filter>inline_bots</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="SourceFiles\inline_bots\inline_bot_layout_internal.cpp">
|
||||||
|
<Filter>inline_bots</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="SourceFiles\stdafx.h">
|
<ClInclude Include="SourceFiles\stdafx.h">
|
||||||
|
@ -1067,6 +1082,18 @@
|
||||||
<ClInclude Include="SourceFiles\gui\style.h">
|
<ClInclude Include="SourceFiles\gui\style.h">
|
||||||
<Filter>gui</Filter>
|
<Filter>gui</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="SourceFiles\inline_bots\inline_bot_layout_item.h">
|
||||||
|
<Filter>inline_bots</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="SourceFiles\inline_bots\inline_bot_result.h">
|
||||||
|
<Filter>inline_bots</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="SourceFiles\inline_bots\inline_bot_send_data.h">
|
||||||
|
<Filter>inline_bots</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="SourceFiles\inline_bots\inline_bot_layout_internal.h">
|
||||||
|
<Filter>inline_bots</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<CustomBuild Include="SourceFiles\application.h">
|
<CustomBuild Include="SourceFiles\application.h">
|
||||||
|
|
Loading…
Reference in New Issue