mirror of https://github.com/procxx/kepka.git
Display round video messages using HistoryGif.
Use autodownload and autoplay options from GIFs. Also improve EditCaptionBox code.
This commit is contained in:
parent
8d28d0691f
commit
8eb7f1f1aa
|
@ -484,11 +484,6 @@ autoDownloadTopDelta: 10px;
|
||||||
autoDownloadTitlePosition: point(23px, 18px);
|
autoDownloadTitlePosition: point(23px, 18px);
|
||||||
autoDownloadTitleFont: font(15px semibold);
|
autoDownloadTitleFont: font(15px semibold);
|
||||||
|
|
||||||
editTextArea: InputField(defaultInputField) {
|
|
||||||
textMargins: margins(1px, 26px, 1px, 4px);
|
|
||||||
heightMax: 276px;
|
|
||||||
}
|
|
||||||
|
|
||||||
confirmCaptionArea: InputField(defaultInputField) {
|
confirmCaptionArea: InputField(defaultInputField) {
|
||||||
textMargins: margins(1px, 26px, 1px, 4px);
|
textMargins: margins(1px, 26px, 1px, 4px);
|
||||||
heightMax: 78px;
|
heightMax: 78px;
|
||||||
|
|
|
@ -269,10 +269,9 @@ void AutoDownloadBox::onSave() {
|
||||||
bool enabledGroups = ((cAutoDownloadAudio() & dbiadNoGroups) && !(autoDownloadAudio & dbiadNoGroups));
|
bool enabledGroups = ((cAutoDownloadAudio() & dbiadNoGroups) && !(autoDownloadAudio & dbiadNoGroups));
|
||||||
cSetAutoDownloadAudio(autoDownloadAudio);
|
cSetAutoDownloadAudio(autoDownloadAudio);
|
||||||
if (enabledPrivate || enabledGroups) {
|
if (enabledPrivate || enabledGroups) {
|
||||||
const DocumentsData &data(App::documentsData());
|
for (auto document : App::documentsData()) {
|
||||||
for (DocumentsData::const_iterator i = data.cbegin(), e = data.cend(); i != e; ++i) {
|
if (document->voice()) {
|
||||||
if (i.value()->voice()) {
|
document->automaticLoadSettingsChanged();
|
||||||
i.value()->automaticLoadSettingsChanged();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -284,10 +283,9 @@ void AutoDownloadBox::onSave() {
|
||||||
bool enabledGroups = ((cAutoDownloadGif() & dbiadNoGroups) && !(autoDownloadGif & dbiadNoGroups));
|
bool enabledGroups = ((cAutoDownloadGif() & dbiadNoGroups) && !(autoDownloadGif & dbiadNoGroups));
|
||||||
cSetAutoDownloadGif(autoDownloadGif);
|
cSetAutoDownloadGif(autoDownloadGif);
|
||||||
if (enabledPrivate || enabledGroups) {
|
if (enabledPrivate || enabledGroups) {
|
||||||
const DocumentsData &data(App::documentsData());
|
for (auto document : App::documentsData()) {
|
||||||
for (DocumentsData::const_iterator i = data.cbegin(), e = data.cend(); i != e; ++i) {
|
if (document->isAnimation()) {
|
||||||
if (i.value()->isAnimation()) {
|
document->automaticLoadSettingsChanged();
|
||||||
i.value()->automaticLoadSettingsChanged();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -450,46 +450,46 @@ void SendFilesBox::closeHook() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EditCaptionBox::EditCaptionBox(QWidget*, HistoryItem *msg)
|
EditCaptionBox::EditCaptionBox(QWidget*, HistoryMedia *media, FullMsgId msgId) : _msgId(msgId) {
|
||||||
: _msgId(msg->fullId()) {
|
Expects(media->canEditCaption());
|
||||||
|
|
||||||
QSize dimensions;
|
QSize dimensions;
|
||||||
ImagePtr image;
|
ImagePtr image;
|
||||||
QString caption;
|
QString caption;
|
||||||
DocumentData *doc = nullptr;
|
DocumentData *doc = nullptr;
|
||||||
if (auto media = msg->getMedia()) {
|
|
||||||
auto t = media->type();
|
|
||||||
switch (t) {
|
|
||||||
case MediaTypeGif: {
|
|
||||||
_animated = true;
|
|
||||||
doc = static_cast<HistoryGif*>(media)->getDocument();
|
|
||||||
dimensions = doc->dimensions;
|
|
||||||
image = doc->thumb;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case MediaTypePhoto: {
|
switch (media->type()) {
|
||||||
_photo = true;
|
case MediaTypeGif: {
|
||||||
PhotoData *photo = static_cast<HistoryPhoto*>(media)->photo();
|
_animated = true;
|
||||||
dimensions = QSize(photo->full->width(), photo->full->height());
|
doc = static_cast<HistoryGif*>(media)->getDocument();
|
||||||
image = photo->full;
|
dimensions = doc->dimensions;
|
||||||
} break;
|
image = doc->thumb;
|
||||||
|
} break;
|
||||||
|
|
||||||
case MediaTypeVideo: {
|
case MediaTypePhoto: {
|
||||||
_animated = true;
|
_photo = true;
|
||||||
doc = static_cast<HistoryVideo*>(media)->getDocument();
|
auto photo = static_cast<HistoryPhoto*>(media)->photo();
|
||||||
dimensions = doc->dimensions;
|
dimensions = QSize(photo->full->width(), photo->full->height());
|
||||||
image = doc->thumb;
|
image = photo->full;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case MediaTypeFile:
|
case MediaTypeVideo: {
|
||||||
case MediaTypeMusicFile:
|
_animated = true;
|
||||||
case MediaTypeVoiceFile: {
|
doc = static_cast<HistoryVideo*>(media)->getDocument();
|
||||||
_doc = true;
|
dimensions = doc->dimensions;
|
||||||
doc = static_cast<HistoryDocument*>(media)->getDocument();
|
image = doc->thumb;
|
||||||
image = doc->thumb;
|
} break;
|
||||||
} break;
|
|
||||||
}
|
case MediaTypeFile:
|
||||||
caption = media->getCaption().text;
|
case MediaTypeMusicFile:
|
||||||
|
case MediaTypeVoiceFile: {
|
||||||
|
_doc = true;
|
||||||
|
doc = static_cast<HistoryDocument*>(media)->getDocument();
|
||||||
|
image = doc->thumb;
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
|
caption = media->getCaption().text;
|
||||||
|
|
||||||
if ((!_animated && (dimensions.isEmpty() || doc)) || image->isNull()) {
|
if ((!_animated && (dimensions.isEmpty() || doc)) || image->isNull()) {
|
||||||
_animated = false;
|
_animated = false;
|
||||||
if (image->isNull()) {
|
if (image->isNull()) {
|
||||||
|
@ -563,17 +563,11 @@ EditCaptionBox::EditCaptionBox(QWidget*, HistoryItem *msg)
|
||||||
_thumb = App::pixmapFromImageInPlace(_thumb.toImage().scaled(_thumbw * cIntRetinaFactor(), _thumbh * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
_thumb = App::pixmapFromImageInPlace(_thumb.toImage().scaled(_thumbw * cIntRetinaFactor(), _thumbh * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
||||||
_thumb.setDevicePixelRatio(cRetinaFactor());
|
_thumb.setDevicePixelRatio(cRetinaFactor());
|
||||||
}
|
}
|
||||||
if (_animated || _photo || _doc) {
|
t_assert(_animated || _photo || _doc);
|
||||||
_field.create(this, st::confirmCaptionArea, lang(lng_photo_caption), caption);
|
|
||||||
_field->setMaxLength(MaxPhotoCaption);
|
_field.create(this, st::confirmCaptionArea, lang(lng_photo_caption), caption);
|
||||||
_field->setCtrlEnterSubmit(Ui::CtrlEnterSubmit::Both);
|
_field->setMaxLength(MaxPhotoCaption);
|
||||||
} else {
|
_field->setCtrlEnterSubmit(Ui::CtrlEnterSubmit::Both);
|
||||||
auto original = msg->originalText();
|
|
||||||
auto text = textApplyEntities(original.text, original.entities);
|
|
||||||
_field.create(this, st::editTextArea, lang(lng_photo_caption), text);
|
|
||||||
// _field->setMaxLength(MaxMessageSize); // entities can make text in input field larger but still valid
|
|
||||||
_field->setCtrlEnterSubmit(cCtrlEnter() ? Ui::CtrlEnterSubmit::CtrlEnter : Ui::CtrlEnterSubmit::Enter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditCaptionBox::prepareGifPreview(DocumentData *document) {
|
void EditCaptionBox::prepareGifPreview(DocumentData *document) {
|
||||||
|
@ -613,20 +607,6 @@ void EditCaptionBox::clipCallback(Media::Clip::Notification notification) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EditCaptionBox::canEdit(HistoryItem *message) {
|
|
||||||
if (auto media = message->getMedia()) {
|
|
||||||
switch (media->type()) {
|
|
||||||
case MediaTypeGif:
|
|
||||||
case MediaTypePhoto:
|
|
||||||
case MediaTypeVideo:
|
|
||||||
case MediaTypeFile:
|
|
||||||
case MediaTypeMusicFile:
|
|
||||||
case MediaTypeVoiceFile: return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditCaptionBox::prepare() {
|
void EditCaptionBox::prepare() {
|
||||||
addButton(lang(lng_settings_save), [this] { onSave(); });
|
addButton(lang(lng_settings_save), [this] { onSave(); });
|
||||||
addButton(lang(lng_cancel), [this] { closeBox(); });
|
addButton(lang(lng_cancel), [this] { closeBox(); });
|
||||||
|
|
|
@ -115,8 +115,7 @@ class EditCaptionBox : public BoxContent, public RPCSender {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EditCaptionBox(QWidget*, HistoryItem *msg);
|
EditCaptionBox(QWidget*, HistoryMedia *media, FullMsgId msgId);
|
||||||
static bool canEdit(HistoryItem *message);
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onCaptionResized();
|
void onCaptionResized();
|
||||||
|
|
|
@ -756,20 +756,19 @@ void HistoryItem::setId(MsgId newId) {
|
||||||
bool HistoryItem::canEdit(const QDateTime &cur) const {
|
bool HistoryItem::canEdit(const QDateTime &cur) const {
|
||||||
auto messageToMyself = (_history->peer->id == AuthSession::CurrentUserPeerId());
|
auto messageToMyself = (_history->peer->id == AuthSession::CurrentUserPeerId());
|
||||||
auto messageTooOld = messageToMyself ? false : (date.secsTo(cur) >= Global::EditTimeLimit());
|
auto messageTooOld = messageToMyself ? false : (date.secsTo(cur) >= Global::EditTimeLimit());
|
||||||
if (id < 0 || messageTooOld) return false;
|
if (id < 0 || messageTooOld) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (auto msg = toHistoryMessage()) {
|
if (auto msg = toHistoryMessage()) {
|
||||||
if (msg->Has<HistoryMessageVia>() || msg->Has<HistoryMessageForwarded>()) return false;
|
if (msg->Has<HistoryMessageVia>() || msg->Has<HistoryMessageForwarded>()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (auto media = msg->getMedia()) {
|
if (auto media = msg->getMedia()) {
|
||||||
auto type = media->type();
|
if (media->canEditCaption()) {
|
||||||
if (type != MediaTypePhoto &&
|
return true;
|
||||||
type != MediaTypeVideo &&
|
} else if (media->type() != MediaTypeWebPage) {
|
||||||
type != MediaTypeFile &&
|
|
||||||
type != MediaTypeGif &&
|
|
||||||
type != MediaTypeMusicFile &&
|
|
||||||
type != MediaTypeVoiceFile &&
|
|
||||||
type != MediaTypeWebPage) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -785,8 +784,12 @@ bool HistoryItem::canEdit(const QDateTime &cur) const {
|
||||||
bool HistoryItem::canDeleteForEveryone(const QDateTime &cur) const {
|
bool HistoryItem::canDeleteForEveryone(const QDateTime &cur) const {
|
||||||
auto messageToMyself = (_history->peer->id == AuthSession::CurrentUserPeerId());
|
auto messageToMyself = (_history->peer->id == AuthSession::CurrentUserPeerId());
|
||||||
auto messageTooOld = messageToMyself ? false : (date.secsTo(cur) >= Global::EditTimeLimit());
|
auto messageTooOld = messageToMyself ? false : (date.secsTo(cur) >= Global::EditTimeLimit());
|
||||||
if (id < 0 || messageToMyself || messageTooOld) return false;
|
if (id < 0 || messageToMyself || messageTooOld) {
|
||||||
if (history()->peer->isChannel()) return false;
|
return false;
|
||||||
|
}
|
||||||
|
if (history()->peer->isChannel()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (auto msg = toHistoryMessage()) {
|
if (auto msg = toHistoryMessage()) {
|
||||||
return !isPost() && out();
|
return !isPost() && out();
|
||||||
|
@ -803,21 +806,31 @@ bool HistoryItem::unread() const {
|
||||||
|
|
||||||
if (out()) {
|
if (out()) {
|
||||||
// Outgoing messages in converted chats are always read.
|
// Outgoing messages in converted chats are always read.
|
||||||
if (history()->peer->migrateTo()) return false;
|
if (history()->peer->migrateTo()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (id > 0) {
|
if (id > 0) {
|
||||||
if (id < history()->outboxReadBefore) return false;
|
if (id < history()->outboxReadBefore) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (auto user = history()->peer->asUser()) {
|
if (auto user = history()->peer->asUser()) {
|
||||||
if (user->botInfo) return false;
|
if (user->botInfo) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else if (auto channel = history()->peer->asChannel()) {
|
} else if (auto channel = history()->peer->asChannel()) {
|
||||||
if (!channel->isMegagroup()) return false;
|
if (!channel->isMegagroup()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id > 0) {
|
if (id > 0) {
|
||||||
if (id < history()->inboxReadBefore) return false;
|
if (id < history()->inboxReadBefore) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return (_flags & MTPDmessage_ClientFlag::f_clientside_unread);
|
return (_flags & MTPDmessage_ClientFlag::f_clientside_unread);
|
||||||
|
@ -867,11 +880,15 @@ void HistoryItem::setUnreadBarFreezed() {
|
||||||
void HistoryItem::clipCallback(Media::Clip::Notification notification) {
|
void HistoryItem::clipCallback(Media::Clip::Notification notification) {
|
||||||
using namespace Media::Clip;
|
using namespace Media::Clip;
|
||||||
|
|
||||||
HistoryMedia *media = getMedia();
|
auto media = getMedia();
|
||||||
if (!media) return;
|
if (!media) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Reader *reader = media ? media->getClipReader() : 0;
|
auto reader = media ? media->getClipReader() : nullptr;
|
||||||
if (!reader) return;
|
if (!reader) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (notification) {
|
switch (notification) {
|
||||||
case NotificationReinit: {
|
case NotificationReinit: {
|
||||||
|
@ -903,7 +920,9 @@ void HistoryItem::clipCallback(Media::Clip::Notification notification) {
|
||||||
|
|
||||||
void HistoryItem::recountDisplayDate() {
|
void HistoryItem::recountDisplayDate() {
|
||||||
bool displayingDate = ([this]() {
|
bool displayingDate = ([this]() {
|
||||||
if (isEmpty()) return false;
|
if (isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (auto previous = previousItem()) {
|
if (auto previous = previousItem()) {
|
||||||
return previous->isEmpty() || (previous->date.date() != date.date());
|
return previous->isEmpty() || (previous->date.date() != date.date());
|
||||||
|
@ -930,7 +949,9 @@ QString HistoryItem::notificationText() const {
|
||||||
};
|
};
|
||||||
|
|
||||||
auto result = getText();
|
auto result = getText();
|
||||||
if (result.size() > 0xFF) result = result.mid(0, 0xFF) + qsl("...");
|
if (result.size() > 0xFF) {
|
||||||
|
result = result.mid(0, 0xFF) + qsl("...");
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -171,6 +171,10 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool canEditCaption() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Sometimes click on media in message is overloaded by the messsage:
|
// Sometimes click on media in message is overloaded by the messsage:
|
||||||
// (for example it can open a link or a game instead of opening media)
|
// (for example it can open a link or a game instead of opening media)
|
||||||
// But the overloading click handler should be used only when media
|
// But the overloading click handler should be used only when media
|
||||||
|
|
|
@ -175,6 +175,9 @@ public:
|
||||||
bool skipBubbleTail() const override {
|
bool skipBubbleTail() const override {
|
||||||
return isBubbleBottom() && _caption.isEmpty();
|
return isBubbleBottom() && _caption.isEmpty();
|
||||||
}
|
}
|
||||||
|
bool canEditCaption() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
bool isReadyForOpen() const override {
|
bool isReadyForOpen() const override {
|
||||||
return _data->loaded();
|
return _data->loaded();
|
||||||
}
|
}
|
||||||
|
@ -191,7 +194,7 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PhotoData *_data;
|
gsl::not_null<PhotoData*> _data;
|
||||||
int16 _pixw = 1;
|
int16 _pixw = 1;
|
||||||
int16 _pixh = 1;
|
int16 _pixh = 1;
|
||||||
Text _caption;
|
Text _caption;
|
||||||
|
@ -266,6 +269,9 @@ public:
|
||||||
bool skipBubbleTail() const override {
|
bool skipBubbleTail() const override {
|
||||||
return isBubbleBottom() && _caption.isEmpty();
|
return isBubbleBottom() && _caption.isEmpty();
|
||||||
}
|
}
|
||||||
|
bool canEditCaption() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
float64 dataProgress() const override {
|
float64 dataProgress() const override {
|
||||||
|
@ -279,7 +285,7 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DocumentData *_data;
|
gsl::not_null<DocumentData*> _data;
|
||||||
int32 _thumbw;
|
int32 _thumbw;
|
||||||
Text _caption;
|
Text _caption;
|
||||||
|
|
||||||
|
@ -417,6 +423,9 @@ public:
|
||||||
bool hideForwardedFrom() const override {
|
bool hideForwardedFrom() const override {
|
||||||
return _data->song();
|
return _data->song();
|
||||||
}
|
}
|
||||||
|
bool canEditCaption() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void step_voiceProgress(float64 ms, bool timer);
|
void step_voiceProgress(float64 ms, bool timer);
|
||||||
|
|
||||||
|
@ -445,7 +454,7 @@ private:
|
||||||
template <typename Callback>
|
template <typename Callback>
|
||||||
void buildStringRepresentation(Callback callback) const;
|
void buildStringRepresentation(Callback callback) const;
|
||||||
|
|
||||||
DocumentData *_data;
|
gsl::not_null<DocumentData*> _data;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -523,6 +532,9 @@ public:
|
||||||
bool skipBubbleTail() const override {
|
bool skipBubbleTail() const override {
|
||||||
return isBubbleBottom() && _caption.isEmpty();
|
return isBubbleBottom() && _caption.isEmpty();
|
||||||
}
|
}
|
||||||
|
bool canEditCaption() const override {
|
||||||
|
return !_data->isRoundVideo();
|
||||||
|
}
|
||||||
bool isReadyForOpen() const override {
|
bool isReadyForOpen() const override {
|
||||||
return _data->loaded();
|
return _data->loaded();
|
||||||
}
|
}
|
||||||
|
@ -535,7 +547,7 @@ protected:
|
||||||
bool dataLoaded() const override;
|
bool dataLoaded() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DocumentData *_data;
|
gsl::not_null<DocumentData*> _data;
|
||||||
int32 _thumbw = 1;
|
int32 _thumbw = 1;
|
||||||
int32 _thumbh = 1;
|
int32 _thumbh = 1;
|
||||||
Text _caption;
|
Text _caption;
|
||||||
|
@ -606,7 +618,7 @@ private:
|
||||||
int16 _pixw = 1;
|
int16 _pixw = 1;
|
||||||
int16 _pixh = 1;
|
int16 _pixh = 1;
|
||||||
ClickHandlerPtr _packLink;
|
ClickHandlerPtr _packLink;
|
||||||
DocumentData *_data;
|
gsl::not_null<DocumentData*> _data;
|
||||||
QString _emoji;
|
QString _emoji;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -659,8 +671,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
int32 _userId = 0;
|
||||||
int32 _userId;
|
|
||||||
UserData *_contact = nullptr;
|
UserData *_contact = nullptr;
|
||||||
|
|
||||||
int _phonew = 0;
|
int _phonew = 0;
|
||||||
|
@ -671,6 +682,7 @@ private:
|
||||||
ClickHandlerPtr _linkl;
|
ClickHandlerPtr _linkl;
|
||||||
int _linkw = 0;
|
int _linkw = 0;
|
||||||
QString _link;
|
QString _link;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class HistoryWebPage : public HistoryMedia {
|
class HistoryWebPage : public HistoryMedia {
|
||||||
|
@ -769,6 +781,7 @@ private:
|
||||||
|
|
||||||
int16 _pixw = 0;
|
int16 _pixw = 0;
|
||||||
int16 _pixh = 0;
|
int16 _pixh = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class HistoryGame : public HistoryMedia {
|
class HistoryGame : public HistoryMedia {
|
||||||
|
|
|
@ -434,8 +434,8 @@ MTPDmessage::Flags newForwardedFlags(PeerData *p, int32 from, HistoryMessage *fw
|
||||||
if (HistoryMedia *media = fwd->getMedia()) {
|
if (HistoryMedia *media = fwd->getMedia()) {
|
||||||
if (media->type() == MediaTypeVoiceFile) {
|
if (media->type() == MediaTypeVoiceFile) {
|
||||||
result |= MTPDmessage::Flag::f_media_unread;
|
result |= MTPDmessage::Flag::f_media_unread;
|
||||||
// } else if (media->type() == MediaTypeVideo) {
|
// } else if (media->type() == MediaTypeVideo) {
|
||||||
// result |= MTPDmessage::flag_media_unread;
|
// result |= MTPDmessage::flag_media_unread;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,11 @@ MTPVector<MTPDocumentAttribute> composeDocumentAttributes(DocumentData *document
|
||||||
if (document->dimensions.width() > 0 && document->dimensions.height() > 0) {
|
if (document->dimensions.width() > 0 && document->dimensions.height() > 0) {
|
||||||
int32 duration = document->duration();
|
int32 duration = document->duration();
|
||||||
if (duration >= 0) {
|
if (duration >= 0) {
|
||||||
attributes.push_back(MTP_documentAttributeVideo(MTP_flags(0), MTP_int(duration), MTP_int(document->dimensions.width()), MTP_int(document->dimensions.height())));
|
auto flags = MTPDdocumentAttributeVideo::Flags(0);
|
||||||
|
if (document->isRoundVideo()) {
|
||||||
|
flags |= MTPDdocumentAttributeVideo::Flag::f_round_message;
|
||||||
|
}
|
||||||
|
attributes.push_back(MTP_documentAttributeVideo(MTP_flags(flags), MTP_int(duration), MTP_int(document->dimensions.width()), MTP_int(document->dimensions.height())));
|
||||||
} else {
|
} else {
|
||||||
attributes.push_back(MTP_documentAttributeImageSize(MTP_int(document->dimensions.width()), MTP_int(document->dimensions.height())));
|
attributes.push_back(MTP_documentAttributeImageSize(MTP_int(document->dimensions.width()), MTP_int(document->dimensions.height())));
|
||||||
}
|
}
|
||||||
|
@ -1449,20 +1453,20 @@ void HistoryWidget::savedGifsGot(const MTPmessages_SavedGifs &gifs) {
|
||||||
if (gifs.type() != mtpc_messages_savedGifs) return;
|
if (gifs.type() != mtpc_messages_savedGifs) return;
|
||||||
auto &d = gifs.c_messages_savedGifs();
|
auto &d = gifs.c_messages_savedGifs();
|
||||||
|
|
||||||
auto &d_gifs = d.vgifs.v;
|
auto &gifsList = d.vgifs.v;
|
||||||
|
|
||||||
SavedGifs &saved(cRefSavedGifs());
|
auto &saved = cRefSavedGifs();
|
||||||
saved.clear();
|
saved.clear();
|
||||||
|
|
||||||
saved.reserve(d_gifs.size());
|
saved.reserve(gifsList.size());
|
||||||
for (int32 i = 0, l = d_gifs.size(); i != l; ++i) {
|
for (auto &gif : gifsList) {
|
||||||
DocumentData *doc = App::feedDocument(d_gifs.at(i));
|
auto document = App::feedDocument(gif);
|
||||||
if (!doc || !doc->isAnimation()) {
|
if (!document || !document->isGifv()) {
|
||||||
LOG(("API Error: bad document returned in HistoryWidget::savedGifsGot!"));
|
LOG(("API Error: bad document returned in HistoryWidget::savedGifsGot!"));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
saved.push_back(doc);
|
saved.push_back(document);
|
||||||
}
|
}
|
||||||
if (Local::countSavedGifsHash() != d.vhash.v) {
|
if (Local::countSavedGifsHash() != d.vhash.v) {
|
||||||
LOG(("API Error: received saved gifs hash %1 while counted hash is %2").arg(d.vhash.v).arg(Local::countSavedGifsHash()));
|
LOG(("API Error: received saved gifs hash %1 while counted hash is %2").arg(d.vhash.v).arg(Local::countSavedGifsHash()));
|
||||||
|
@ -5315,55 +5319,58 @@ void HistoryWidget::onEditMessage() {
|
||||||
auto to = App::contextItem();
|
auto to = App::contextItem();
|
||||||
if (!to) return;
|
if (!to) return;
|
||||||
|
|
||||||
if (EditCaptionBox::canEdit(to)) {
|
if (auto media = to->getMedia()) {
|
||||||
Ui::show(Box<EditCaptionBox>(to));
|
if (media->canEditCaption()) {
|
||||||
} else {
|
Ui::show(Box<EditCaptionBox>(media, to->fullId()));
|
||||||
if (_recording) {
|
return;
|
||||||
// Just fix some strange inconsistency.
|
|
||||||
_send->clearState();
|
|
||||||
}
|
}
|
||||||
if (!_editMsgId) {
|
|
||||||
if (_replyToId || !_field->isEmpty()) {
|
|
||||||
_history->setLocalDraft(std::make_unique<Data::Draft>(_field, _replyToId, _previewCancelled));
|
|
||||||
} else {
|
|
||||||
_history->clearLocalDraft();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto original = to->originalText();
|
|
||||||
auto editText = textApplyEntities(original.text, original.entities);
|
|
||||||
auto editTags = ConvertEntitiesToTextTags(original.entities);
|
|
||||||
TextWithTags editData = { editText, editTags };
|
|
||||||
MessageCursor cursor = { editText.size(), editText.size(), QFIXED_MAX };
|
|
||||||
_history->setEditDraft(std::make_unique<Data::Draft>(editData, to->id, cursor, false));
|
|
||||||
applyDraft(false);
|
|
||||||
|
|
||||||
_previewData = nullptr;
|
|
||||||
if (auto media = to->getMedia()) {
|
|
||||||
if (media->type() == MediaTypeWebPage) {
|
|
||||||
_previewData = static_cast<HistoryWebPage*>(media)->webpage();
|
|
||||||
updatePreview();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!_previewData) {
|
|
||||||
onPreviewParse();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateBotKeyboard();
|
|
||||||
|
|
||||||
if (!_field->isHidden()) _fieldBarCancel->show();
|
|
||||||
updateFieldPlaceholder();
|
|
||||||
updateMouseTracking();
|
|
||||||
updateReplyToName();
|
|
||||||
updateControlsGeometry();
|
|
||||||
updateField();
|
|
||||||
|
|
||||||
_saveDraftText = true;
|
|
||||||
_saveDraftStart = getms();
|
|
||||||
onDraftSave();
|
|
||||||
|
|
||||||
_field->setFocus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_recording) {
|
||||||
|
// Just fix some strange inconsistency.
|
||||||
|
_send->clearState();
|
||||||
|
}
|
||||||
|
if (!_editMsgId) {
|
||||||
|
if (_replyToId || !_field->isEmpty()) {
|
||||||
|
_history->setLocalDraft(std::make_unique<Data::Draft>(_field, _replyToId, _previewCancelled));
|
||||||
|
} else {
|
||||||
|
_history->clearLocalDraft();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto original = to->originalText();
|
||||||
|
auto editText = textApplyEntities(original.text, original.entities);
|
||||||
|
auto editTags = ConvertEntitiesToTextTags(original.entities);
|
||||||
|
TextWithTags editData = { editText, editTags };
|
||||||
|
MessageCursor cursor = { editText.size(), editText.size(), QFIXED_MAX };
|
||||||
|
_history->setEditDraft(std::make_unique<Data::Draft>(editData, to->id, cursor, false));
|
||||||
|
applyDraft(false);
|
||||||
|
|
||||||
|
_previewData = nullptr;
|
||||||
|
if (auto media = to->getMedia()) {
|
||||||
|
if (media->type() == MediaTypeWebPage) {
|
||||||
|
_previewData = static_cast<HistoryWebPage*>(media)->webpage();
|
||||||
|
updatePreview();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!_previewData) {
|
||||||
|
onPreviewParse();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateBotKeyboard();
|
||||||
|
|
||||||
|
if (!_field->isHidden()) _fieldBarCancel->show();
|
||||||
|
updateFieldPlaceholder();
|
||||||
|
updateMouseTracking();
|
||||||
|
updateReplyToName();
|
||||||
|
updateControlsGeometry();
|
||||||
|
updateField();
|
||||||
|
|
||||||
|
_saveDraftText = true;
|
||||||
|
_saveDraftStart = getms();
|
||||||
|
onDraftSave();
|
||||||
|
|
||||||
|
_field->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::onPinMessage() {
|
void HistoryWidget::onPinMessage() {
|
||||||
|
|
|
@ -764,7 +764,7 @@ void MediaPreviewWidget::resizeEvent(QResizeEvent *e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaPreviewWidget::showPreview(DocumentData *document) {
|
void MediaPreviewWidget::showPreview(DocumentData *document) {
|
||||||
if (!document || (!document->isAnimation() && !document->sticker())) {
|
if (!document || (!document->isAnimation() && !document->sticker()) || document->isRoundVideo()) {
|
||||||
hidePreview();
|
hidePreview();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -487,7 +487,9 @@ bool MainWindow::ui_isLayerShown() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::ui_showMediaPreview(DocumentData *document) {
|
void MainWindow::ui_showMediaPreview(DocumentData *document) {
|
||||||
if (!document || ((!document->isAnimation() || !document->loaded()) && !document->sticker())) return;
|
if (!document || ((!document->isAnimation() || !document->loaded()) && !document->sticker())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!_mediaPreview) {
|
if (!_mediaPreview) {
|
||||||
_mediaPreview.create(bodyWidget(), controller());
|
_mediaPreview.create(bodyWidget(), controller());
|
||||||
updateControlsGeometry();
|
updateControlsGeometry();
|
||||||
|
|
|
@ -528,7 +528,7 @@ void MediaView::step_radial(TimeMs ms, bool timer) {
|
||||||
if (!_doc->data().isEmpty() && (_doc->isAnimation() || _doc->isVideo())) {
|
if (!_doc->data().isEmpty() && (_doc->isAnimation() || _doc->isVideo())) {
|
||||||
displayDocument(_doc, App::histItemById(_msgmigrated ? 0 : _channel, _msgid));
|
displayDocument(_doc, App::histItemById(_msgmigrated ? 0 : _channel, _msgid));
|
||||||
} else {
|
} else {
|
||||||
const FileLocation &location(_doc->location(true));
|
auto &location = _doc->location(true);
|
||||||
if (location.accessEnable()) {
|
if (location.accessEnable()) {
|
||||||
if (_doc->isAnimation() || _doc->isVideo() || _doc->isTheme() || QImageReader(location.name()).canRead()) {
|
if (_doc->isAnimation() || _doc->isVideo() || _doc->isTheme() || QImageReader(location.name()).canRead()) {
|
||||||
displayDocument(_doc, App::histItemById(_msgmigrated ? 0 : _channel, _msgid));
|
displayDocument(_doc, App::histItemById(_msgmigrated ? 0 : _channel, _msgid));
|
||||||
|
@ -1384,8 +1384,8 @@ void MediaView::displayFinished() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::initAnimation() {
|
void MediaView::initAnimation() {
|
||||||
t_assert(_doc != nullptr);
|
Expects(_doc != nullptr);
|
||||||
t_assert(_doc->isAnimation() || _doc->isVideo());
|
Expects(_doc->isAnimation() || _doc->isVideo());
|
||||||
|
|
||||||
auto &location = _doc->location(true);
|
auto &location = _doc->location(true);
|
||||||
if (!_doc->data().isEmpty()) {
|
if (!_doc->data().isEmpty()) {
|
||||||
|
@ -1406,8 +1406,8 @@ void MediaView::initAnimation() {
|
||||||
void MediaView::createClipReader() {
|
void MediaView::createClipReader() {
|
||||||
if (_gif) return;
|
if (_gif) return;
|
||||||
|
|
||||||
t_assert(_doc != nullptr);
|
Expects(_doc != nullptr);
|
||||||
t_assert(_doc->isAnimation() || _doc->isVideo());
|
Expects(_doc->isAnimation() || _doc->isVideo());
|
||||||
|
|
||||||
if (_doc->dimensions.width() && _doc->dimensions.height()) {
|
if (_doc->dimensions.width() && _doc->dimensions.height()) {
|
||||||
int w = _doc->dimensions.width();
|
int w = _doc->dimensions.width();
|
||||||
|
|
|
@ -3662,8 +3662,8 @@ void readSavedGifs() {
|
||||||
saved.reserve(cnt);
|
saved.reserve(cnt);
|
||||||
OrderedSet<DocumentId> read;
|
OrderedSet<DocumentId> read;
|
||||||
for (uint32 i = 0; i < cnt; ++i) {
|
for (uint32 i = 0; i < cnt; ++i) {
|
||||||
DocumentData *document = Serialize::Document::readFromStream(gifs.version, gifs.stream);
|
auto document = Serialize::Document::readFromStream(gifs.version, gifs.stream);
|
||||||
if (!document || !document->isAnimation()) continue;
|
if (!document || !document->isGifv()) continue;
|
||||||
|
|
||||||
if (read.contains(document->id)) continue;
|
if (read.contains(document->id)) continue;
|
||||||
read.insert(document->id);
|
read.insert(document->id);
|
||||||
|
|
|
@ -119,6 +119,9 @@ DocumentData *Document::readFromStreamHelper(int streamAppVersion, QDataStream &
|
||||||
if (width > 0 && height > 0) {
|
if (width > 0 && height > 0) {
|
||||||
if (duration >= 0) {
|
if (duration >= 0) {
|
||||||
auto flags = MTPDdocumentAttributeVideo::Flags(0);
|
auto flags = MTPDdocumentAttributeVideo::Flags(0);
|
||||||
|
if (type == RoundVideoDocument) {
|
||||||
|
flags |= MTPDdocumentAttributeVideo::Flag::f_round_message;
|
||||||
|
}
|
||||||
attributes.push_back(MTP_documentAttributeVideo(MTP_flags(flags), MTP_int(duration), MTP_int(width), MTP_int(height)));
|
attributes.push_back(MTP_documentAttributeVideo(MTP_flags(flags), MTP_int(duration), MTP_int(width), MTP_int(height)));
|
||||||
} else {
|
} else {
|
||||||
attributes.push_back(MTP_documentAttributeImageSize(MTP_int(width), MTP_int(height)));
|
attributes.push_back(MTP_documentAttributeImageSize(MTP_int(width), MTP_int(height)));
|
||||||
|
|
|
@ -1299,9 +1299,6 @@ VoiceData::~VoiceData() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DocumentAdditionalData::~DocumentAdditionalData() {
|
|
||||||
}
|
|
||||||
|
|
||||||
DocumentData::DocumentData(DocumentId id, int32 dc, uint64 accessHash, int32 version, const QString &url, const QVector<MTPDocumentAttribute> &attributes)
|
DocumentData::DocumentData(DocumentId id, int32 dc, uint64 accessHash, int32 version, const QString &url, const QVector<MTPDocumentAttribute> &attributes)
|
||||||
: id(id)
|
: id(id)
|
||||||
, _dc(dc)
|
, _dc(dc)
|
||||||
|
@ -1353,7 +1350,7 @@ void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes
|
||||||
case mtpc_documentAttributeVideo: {
|
case mtpc_documentAttributeVideo: {
|
||||||
auto &d = attributes[i].c_documentAttributeVideo();
|
auto &d = attributes[i].c_documentAttributeVideo();
|
||||||
if (type == FileDocument) {
|
if (type == FileDocument) {
|
||||||
type = VideoDocument;
|
type = d.is_round_message() ? RoundVideoDocument : VideoDocument;
|
||||||
}
|
}
|
||||||
_duration = d.vduration.v;
|
_duration = d.vduration.v;
|
||||||
dimensions = QSize(d.vw.v, d.vh.v);
|
dimensions = QSize(d.vw.v, d.vh.v);
|
||||||
|
@ -1440,8 +1437,10 @@ void DocumentData::automaticLoad(const HistoryItem *item) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DocumentData::automaticLoadSettingsChanged() {
|
void DocumentData::automaticLoadSettingsChanged() {
|
||||||
if (loaded() || status != FileReady || (!isAnimation() && !voice()) || !saveToCache() || _loader != CancelledMtpFileLoader) return;
|
if (loaded() || status != FileReady || (!isAnimation() && !voice()) || !saveToCache() || _loader != CancelledMtpFileLoader) {
|
||||||
_loader = 0;
|
return;
|
||||||
|
}
|
||||||
|
_loader = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DocumentData::performActionOnLoad() {
|
void DocumentData::performActionOnLoad() {
|
||||||
|
@ -1450,10 +1449,10 @@ void DocumentData::performActionOnLoad() {
|
||||||
auto loc = location(true);
|
auto loc = location(true);
|
||||||
auto already = loc.name();
|
auto already = loc.name();
|
||||||
auto item = _actionOnLoadMsgId.msg ? App::histItemById(_actionOnLoadMsgId) : nullptr;
|
auto item = _actionOnLoadMsgId.msg ? App::histItemById(_actionOnLoadMsgId) : nullptr;
|
||||||
bool showImage = !isVideo() && (size < App::kImageSizeLimit);
|
auto showImage = !isVideo() && (size < App::kImageSizeLimit);
|
||||||
bool playVoice = voice() && (_actionOnLoad == ActionOnLoadPlayInline || _actionOnLoad == ActionOnLoadOpen);
|
auto playVoice = voice() && (_actionOnLoad == ActionOnLoadPlayInline || _actionOnLoad == ActionOnLoadOpen);
|
||||||
bool playMusic = song() && (_actionOnLoad == ActionOnLoadPlayInline || _actionOnLoad == ActionOnLoadOpen);
|
auto playMusic = song() && (_actionOnLoad == ActionOnLoadPlayInline || _actionOnLoad == ActionOnLoadOpen);
|
||||||
bool playAnimation = isAnimation() && (_actionOnLoad == ActionOnLoadPlayInline || _actionOnLoad == ActionOnLoadOpen) && showImage && item && item->getMedia();
|
auto playAnimation = isAnimation() && (_actionOnLoad == ActionOnLoadPlayInline || _actionOnLoad == ActionOnLoadOpen) && showImage && item && item->getMedia();
|
||||||
if (auto applyTheme = isTheme()) {
|
if (auto applyTheme = isTheme()) {
|
||||||
if (!loc.isEmpty() && loc.accessEnable()) {
|
if (!loc.isEmpty() && loc.accessEnable()) {
|
||||||
App::wnd()->showDocument(this, item);
|
App::wnd()->showDocument(this, item);
|
||||||
|
@ -1784,7 +1783,9 @@ bool fileIsImage(const QString &name, const QString &mime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DocumentData::recountIsImage() {
|
void DocumentData::recountIsImage() {
|
||||||
if (isAnimation() || isVideo()) return;
|
if (isAnimation() || isVideo()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
_duration = fileIsImage(name, mime) ? 1 : -1; // hack
|
_duration = fileIsImage(name, mime) ? 1 : -1; // hack
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1074,17 +1074,20 @@ enum FileStatus {
|
||||||
FileReady = 1,
|
FileReady = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Don't change the values. This type is used for serialization.
|
||||||
enum DocumentType {
|
enum DocumentType {
|
||||||
FileDocument = 0,
|
FileDocument = 0,
|
||||||
VideoDocument = 1,
|
VideoDocument = 1,
|
||||||
SongDocument = 2,
|
SongDocument = 2,
|
||||||
StickerDocument = 3,
|
StickerDocument = 3,
|
||||||
AnimatedDocument = 4,
|
AnimatedDocument = 4,
|
||||||
VoiceDocument = 5,
|
VoiceDocument = 5,
|
||||||
|
RoundVideoDocument = 6,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DocumentAdditionalData {
|
struct DocumentAdditionalData {
|
||||||
virtual ~DocumentAdditionalData();
|
virtual ~DocumentAdditionalData() = default;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StickerData : public DocumentAdditionalData {
|
struct StickerData : public DocumentAdditionalData {
|
||||||
|
@ -1099,9 +1102,7 @@ struct StickerData : public DocumentAdditionalData {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SongData : public DocumentAdditionalData {
|
struct SongData : public DocumentAdditionalData {
|
||||||
SongData() : duration(0) {
|
int32 duration = 0;
|
||||||
}
|
|
||||||
int32 duration;
|
|
||||||
QString title, performer;
|
QString title, performer;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1193,8 +1194,11 @@ public:
|
||||||
const VoiceData *voice() const {
|
const VoiceData *voice() const {
|
||||||
return const_cast<DocumentData*>(this)->voice();
|
return const_cast<DocumentData*>(this)->voice();
|
||||||
}
|
}
|
||||||
|
bool isRoundVideo() const {
|
||||||
|
return (type == RoundVideoDocument);
|
||||||
|
}
|
||||||
bool isAnimation() const {
|
bool isAnimation() const {
|
||||||
return (type == AnimatedDocument) || !mime.compare(qstr("image/gif"), Qt::CaseInsensitive);
|
return (type == AnimatedDocument) || isRoundVideo() || !mime.compare(qstr("image/gif"), Qt::CaseInsensitive);
|
||||||
}
|
}
|
||||||
bool isGifv() const {
|
bool isGifv() const {
|
||||||
return (type == AnimatedDocument) && !mime.compare(qstr("video/mp4"), Qt::CaseInsensitive);
|
return (type == AnimatedDocument) && !mime.compare(qstr("video/mp4"), Qt::CaseInsensitive);
|
||||||
|
@ -1246,11 +1250,12 @@ public:
|
||||||
|
|
||||||
~DocumentData();
|
~DocumentData();
|
||||||
|
|
||||||
DocumentId id;
|
DocumentId id = 0;
|
||||||
DocumentType type = FileDocument;
|
DocumentType type = FileDocument;
|
||||||
QSize dimensions;
|
QSize dimensions;
|
||||||
int32 date = 0;
|
int32 date = 0;
|
||||||
QString name, mime;
|
QString name;
|
||||||
|
QString mime;
|
||||||
ImagePtr thumb, replyPreview;
|
ImagePtr thumb, replyPreview;
|
||||||
int32 size = 0;
|
int32 size = 0;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue