voice messages moved to documents with waveforms

This commit is contained in:
John Preston 2016-02-12 19:35:06 +03:00
parent ffa588bf5d
commit 189d0e8de3
36 changed files with 1615 additions and 2495 deletions

View File

@ -1286,6 +1286,15 @@ msgFileRadialLine: 3px;
msgVideoSize: size(320px, 240px);
msgWaveformBar: 2px;
msgWaveformSkip: 1px;
msgWaveformMin: 2px;
msgWaveformMax: 20px;
msgWaveformInActive: #59b6eb;
msgWaveformInInactive: #deeaf1;
msgWaveformOutActive: #78c67f;
msgWaveformOutInactive: #c4e8c5;
sendPadding: 9px;
btnSend: flatButton(btnDefFlat) {
color: btnYesColor;
@ -1386,7 +1395,7 @@ btnRecordAudio: sprite(379px, 390px, 16px, 24px);
btnRecordAudioActive: sprite(379px, 366px, 16px, 24px);
recordSignalColor: #f17077;
recordSignalMin: 5px;
recordSignalMax: 10px;
recordSignalMax: 12px;
recordCancel: #aaa;
recordCancelActive: #ec6466;
recordFont: font(13px);

View File

@ -48,7 +48,6 @@ namespace {
PhotosData photosData;
VideosData videosData;
AudiosData audiosData;
DocumentsData documentsData;
typedef QHash<QString, ImageLinkData*> ImageLinksData;
@ -65,7 +64,6 @@ namespace {
PhotoItems photoItems;
VideoItems videoItems;
AudioItems audioItems;
DocumentItems documentItems;
WebPageItems webPageItems;
SharedContactItems sharedContactItems;
@ -1293,22 +1291,6 @@ namespace App {
return App::videoSet(video.vid.v, convert, video.vaccess_hash.v, video.vdate.v, video.vduration.v, video.vw.v, video.vh.v, App::image(video.vthumb), video.vdc_id.v, video.vsize.v);
}
AudioData *feedAudio(const MTPaudio &audio, AudioData *convert) {
switch (audio.type()) {
case mtpc_audio: {
return feedAudio(audio.c_audio(), convert);
} break;
case mtpc_audioEmpty: {
return App::audioSet(audio.c_audioEmpty().vid.v, convert, 0, 0, QString(), 0, 0, 0);
} break;
}
return App::audio(0);
}
AudioData *feedAudio(const MTPDaudio &audio, AudioData *convert) {
return App::audioSet(audio.vid.v, convert, audio.vaccess_hash.v, audio.vdate.v, qs(audio.vmime_type), audio.vduration.v, audio.vdc_id.v, audio.vsize.v);
}
DocumentData *feedDocument(const MTPdocument &document, const QPixmap &thumb) {
switch (document.type()) {
case mtpc_document: {
@ -1568,56 +1550,6 @@ namespace App {
return result;
}
AudioData *audio(const AudioId &audio) {
AudiosData::const_iterator i = ::audiosData.constFind(audio);
if (i == ::audiosData.cend()) {
i = ::audiosData.insert(audio, new AudioData(audio));
}
return i.value();
}
AudioData *audioSet(const AudioId &audio, AudioData *convert, const uint64 &access, int32 date, const QString &mime, int32 duration, int32 dc, int32 size) {
if (convert) {
if (convert->id != audio) {
AudiosData::iterator i = ::audiosData.find(convert->id);
if (i != ::audiosData.cend() && i.value() == convert) {
::audiosData.erase(i);
}
convert->id = audio;
convert->status = FileReady;
}
if (date) {
convert->access = access;
convert->date = date;
convert->mime = mime;
convert->duration = duration;
convert->dc = dc;
convert->size = size;
}
}
AudiosData::const_iterator i = ::audiosData.constFind(audio);
AudioData *result;
if (i == ::audiosData.cend()) {
if (convert) {
result = convert;
} else {
result = new AudioData(audio, access, date, mime, duration, dc, size);
}
::audiosData.insert(audio, result);
} else {
result = i.value();
if (result != convert && date) {
result->access = access;
result->date = date;
result->mime = mime;
result->duration = duration;
result->dc = dc;
result->size = size;
}
}
return result;
}
DocumentData *document(const DocumentId &document) {
DocumentsData::const_iterator i = ::documentsData.constFind(document);
if (i == ::documentsData.cend()) {
@ -1795,9 +1727,6 @@ namespace App {
for (VideosData::const_iterator i = ::videosData.cbegin(), e = ::videosData.cend(); i != e; ++i) {
i.value()->forget();
}
for (AudiosData::const_iterator i = ::audiosData.cbegin(), e = ::audiosData.cend(); i != e; ++i) {
i.value()->forget();
}
for (DocumentsData::const_iterator i = ::documentsData.cbegin(), e = ::documentsData.cend(); i != e; ++i) {
i.value()->forget();
}
@ -1955,10 +1884,6 @@ namespace App {
delete *i;
}
::videosData.clear();
for (AudiosData::const_iterator i = ::audiosData.cbegin(), e = ::audiosData.cend(); i != e; ++i) {
delete *i;
}
::audiosData.clear();
for (DocumentsData::const_iterator i = ::documentsData.cbegin(), e = ::documentsData.cend(); i != e; ++i) {
delete *i;
}
@ -1977,7 +1902,6 @@ namespace App {
cSetReportSpamStatuses(ReportSpamStatuses());
::photoItems.clear();
::videoItems.clear();
::audioItems.clear();
::documentItems.clear();
::webPageItems.clear();
::sharedContactItems.clear();
@ -2392,22 +2316,6 @@ namespace App {
return ::videosData;
}
void regAudioItem(AudioData *data, HistoryItem *item) {
::audioItems[data].insert(item, NullType());
}
void unregAudioItem(AudioData*data, HistoryItem *item) {
::audioItems[data].remove(item);
}
const AudioItems &audioItems() {
return ::audioItems;
}
const AudiosData &audiosData() {
return ::audiosData;
}
void regDocumentItem(DocumentData *data, HistoryItem *item) {
::documentItems[data].insert(item, NullType());
}

View File

@ -37,7 +37,6 @@ class FileUploader;
typedef QMap<HistoryItem*, NullType> HistoryItemsMap;
typedef QHash<PhotoData*, HistoryItemsMap> PhotoItems;
typedef QHash<VideoData*, HistoryItemsMap> VideoItems;
typedef QHash<AudioData*, HistoryItemsMap> AudioItems;
typedef QHash<DocumentData*, HistoryItemsMap> DocumentItems;
typedef QHash<WebPageData*, HistoryItemsMap> WebPageItems;
typedef QHash<int32, HistoryItemsMap> SharedContactItems;
@ -45,7 +44,6 @@ typedef QHash<ClipReader*, HistoryItem*> GifItems;
typedef QHash<PhotoId, PhotoData*> PhotosData;
typedef QHash<VideoId, VideoData*> VideosData;
typedef QHash<AudioId, AudioData*> AudiosData;
typedef QHash<DocumentId, DocumentData*> DocumentsData;
struct ReplyMarkup {
@ -107,8 +105,6 @@ namespace App {
PhotoData *feedPhoto(const MTPPhoto &photo, PhotoData *convert = 0);
PhotoData *feedPhoto(const MTPDphoto &photo, PhotoData *convert = 0);
VideoData *feedVideo(const MTPDvideo &video, VideoData *convert = 0);
AudioData *feedAudio(const MTPaudio &audio, AudioData *convert = 0);
AudioData *feedAudio(const MTPDaudio &audio, AudioData *convert = 0);
DocumentData *feedDocument(const MTPdocument &document, const QPixmap &thumb);
DocumentData *feedDocument(const MTPdocument &document, DocumentData *convert = 0);
DocumentData *feedDocument(const MTPDdocument &document, DocumentData *convert = 0);
@ -138,8 +134,6 @@ namespace App {
PhotoData *photoSet(const PhotoId &photo, PhotoData *convert, const uint64 &access, int32 date, const ImagePtr &thumb, const ImagePtr &medium, const ImagePtr &full);
VideoData *video(const VideoId &video);
VideoData *videoSet(const VideoId &video, VideoData *convert, const uint64 &access, int32 date, int32 duration, int32 w, int32 h, const ImagePtr &thumb, int32 dc, int32 size);
AudioData *audio(const AudioId &audio);
AudioData *audioSet(const AudioId &audio, AudioData *convert, const uint64 &access, int32 date, const QString &mime, int32 duration, int32 dc, int32 size);
DocumentData *document(const DocumentId &document);
DocumentData *documentSet(const DocumentId &document, DocumentData *convert, const uint64 &access, int32 date, const QVector<MTPDocumentAttribute> &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size, const StorageImageLocation &thumbLocation);
WebPageData *webPage(const WebPageId &webPage);
@ -219,11 +213,6 @@ namespace App {
const VideoItems &videoItems();
const VideosData &videosData();
void regAudioItem(AudioData *data, HistoryItem *item);
void unregAudioItem(AudioData*data, HistoryItem *item);
const AudioItems &audioItems();
const AudiosData &audiosData();
void regDocumentItem(DocumentData *data, HistoryItem *item);
void unregDocumentItem(DocumentData *data, HistoryItem *item);
const DocumentItems &documentItems();

View File

@ -1039,7 +1039,7 @@ void AppClass::uploadProfilePhoto(const QImage &tosend, const PeerId &peerId) {
int32 filesize = 0;
QByteArray data;
ReadyLocalMedia ready(PreparePhoto, file, filename, filesize, data, id, id, qsl("jpg"), peerId, photo, MTP_audioEmpty(MTP_long(0)), photoThumbs, MTP_documentEmpty(MTP_long(0)), jpeg, false, false, 0);
ReadyLocalMedia ready(PreparePhoto, file, filename, filesize, data, id, id, qsl("jpg"), peerId, photo, photoThumbs, MTP_documentEmpty(MTP_long(0)), jpeg, false, false, 0);
connect(App::uploader(), SIGNAL(photoReady(const FullMsgId&, const MTPInputFile&)), App::app(), SLOT(photoUpdated(const FullMsgId&, const MTPInputFile&)), Qt::UniqueConnection);

File diff suppressed because it is too large Load Diff

View File

@ -56,7 +56,7 @@ public:
void play(const AudioMsgId &audio, int64 position = 0);
void play(const SongMsgId &song, int64 position = 0);
void pauseresume(MediaOverviewType type, bool fast = false);
void seek(int64 position); // type == OverviewDocuments
void seek(int64 position); // type == OverviewFiles
void stop(MediaOverviewType type);
void stopAndClear();
@ -201,8 +201,8 @@ signals:
void captureOnStart();
void captureOnStop(bool needResult);
void onDone(QByteArray data, qint32 samples);
void onUpdate(qint16 level, qint32 samples);
void onDone(QByteArray data, VoiceWaveform waveform, qint32 samples);
void onUpdate(quint16 level, qint32 samples);
void onError();
private:
@ -338,8 +338,8 @@ public:
signals:
void error();
void update(qint16 level, qint32 samples);
void done(QByteArray data, qint32 samples);
void update(quint16 level, qint32 samples);
void done(QByteArray data, VoiceWaveform waveform, qint32 samples);
public slots:
@ -360,3 +360,4 @@ private:
};
MTPDocumentAttribute audioReadSongAttributes(const QString &fname, const QByteArray &data, QImage &cover, QByteArray &coverBytes, QByteArray &coverFormat);
VoiceWaveform audioCountWaveform(const FileLocation &file, const QByteArray &data);

View File

@ -313,9 +313,11 @@ void AutoDownloadBox::onSave() {
bool enabledGroups = ((cAutoDownloadAudio() & dbiadNoGroups) && !(autoDownloadAudio & dbiadNoGroups));
cSetAutoDownloadAudio(autoDownloadAudio);
if (enabledPrivate || enabledGroups) {
const AudiosData &data(App::audiosData());
for (AudiosData::const_iterator i = data.cbegin(), e = data.cend(); i != e; ++i) {
i.value()->automaticLoadSettingsChanged();
const DocumentsData &data(App::documentsData());
for (DocumentsData::const_iterator i = data.cbegin(), e = data.cend(); i != e; ++i) {
if (i.value()->voice()) {
i.value()->automaticLoadSettingsChanged();
}
}
}
changed = true;
@ -328,7 +330,9 @@ void AutoDownloadBox::onSave() {
if (enabledPrivate || enabledGroups) {
const DocumentsData &data(App::documentsData());
for (DocumentsData::const_iterator i = data.cbegin(), e = data.cend(); i != e; ++i) {
i.value()->automaticLoadSettingsChanged();
if (i.value()->isAnimation()) {
i.value()->automaticLoadSettingsChanged();
}
}
Notify::automaticLoadSettingsChangedGif();
}

View File

@ -118,6 +118,8 @@ enum {
AudioVoiceMsgInMemory = 2 * 1024 * 1024, // 2 Mb audio is hold in memory and auto loaded
AudioPauseDeviceTimeout = 3000, // pause in 3 secs after playing is over
WaveformSamplesCount = 100,
StickerInMemory = 2 * 1024 * 1024, // 2 Mb stickers hold in memory, auto loaded and displayed inline
StickerMaxSize = 2048, // 2048x2048 is a max image size for sticker

View File

@ -32,7 +32,7 @@ FileUploader::FileUploader() : sentSize(0) {
void FileUploader::uploadMedia(const FullMsgId &msgId, const ReadyLocalMedia &media) {
if (media.type == PreparePhoto) {
App::feedPhoto(media.photo, media.photoThumbs);
} else if (media.type == PrepareDocument) {
} else if (media.type == PrepareDocument || media.type == PrepareAudio) {
DocumentData *document;
if (media.photoThumbs.isEmpty()) {
document = App::feedDocument(media.document);
@ -40,13 +40,12 @@ void FileUploader::uploadMedia(const FullMsgId &msgId, const ReadyLocalMedia &me
document = App::feedDocument(media.document, media.photoThumbs.begin().value());
}
document->status = FileUploading;
if (!media.data.isEmpty()) {
document->setData(media.data);
}
if (!media.file.isEmpty()) {
document->setLocation(FileLocation(StorageFilePartial, media.file));
}
} else if (media.type == PrepareAudio) {
AudioData *audio = App::feedAudio(media.audio);
audio->status = FileUploading;
audio->setData(media.data);
}
queue.insert(msgId, File(media));
sendNext();
@ -56,7 +55,7 @@ void FileUploader::upload(const FullMsgId &msgId, const FileLoadResultPtr &file)
if (file->type == PreparePhoto) {
PhotoData *photo = App::feedPhoto(file->photo, file->photoThumbs);
photo->uploadingData = new PhotoData::UploadingData(file->partssize);
} else if (file->type == PrepareDocument) {
} else if (file->type == PrepareDocument || file->type == PrepareAudio) {
DocumentData *document;
if (file->thumb.isNull()) {
document = App::feedDocument(file->document);
@ -64,13 +63,12 @@ void FileUploader::upload(const FullMsgId &msgId, const FileLoadResultPtr &file)
document = App::feedDocument(file->document, file->thumb);
}
document->status = FileUploading;
if (!file->content.isEmpty()) {
document->setData(file->content);
}
if (!file->filepath.isEmpty()) {
document->setLocation(FileLocation(StorageFilePartial, file->filepath));
}
} else if (file->type == PrepareAudio) {
AudioData *audio = App::feedAudio(file->audio);
audio->status = FileUploading;
audio->setData(file->content);
}
queue.insert(msgId, File(file));
sendNext();
@ -87,12 +85,6 @@ void FileUploader::currentFailed() {
doc->status = FileUploadFailed;
}
emit documentFailed(j.key());
} else if (j->type() == PrepareAudio) {
AudioData *audio = App::audio(j->id());
if (audio->status == FileUploading) {
audio->status = FileUploadFailed;
}
emit audioFailed(j.key());
}
queue.erase(j);
}
@ -133,7 +125,7 @@ void FileUploader::sendNext() {
if (!uploading.msg) {
uploading = i.key();
} else if (i == queue.end()) {
i = queue.begin();
i = queue.begin();
uploading = i.key();
}
int todc = 0;
@ -150,7 +142,7 @@ void FileUploader::sendNext() {
if (requestsSent.isEmpty() && docRequestsSent.isEmpty()) {
if (i->type() == PreparePhoto) {
emit photoReady(uploading, MTP_inputFile(MTP_long(i->id()), MTP_int(i->partsCount), MTP_string(i->filename()), MTP_string(i->file ? i->file->filemd5 : i->media.jpeg_md5)));
} else if (i->type() == PrepareDocument) {
} else if (i->type() == PrepareDocument || i->type() == PrepareAudio) {
QByteArray docMd5(32, Qt::Uninitialized);
hashMd5Hex(i->md5Hash.result(), docMd5.data());
@ -160,12 +152,6 @@ void FileUploader::sendNext() {
} else {
emit documentReady(uploading, doc);
}
} else if (i->type() == PrepareAudio) {
QByteArray audioMd5(32, Qt::Uninitialized);
hashMd5Hex(i->md5Hash.result(), audioMd5.data());
MTPInputFile audio = (i->docSize > UseBigFilesFrom) ? MTP_inputFileBig(MTP_long(i->id()), MTP_int(i->docPartsCount), MTP_string(i->filename())) : MTP_inputFile(MTP_long(i->id()), MTP_int(i->docPartsCount), MTP_string(i->filename()), MTP_string(audioMd5));
emit audioReady(uploading, audio);
}
queue.remove(uploading);
uploading = FullMsgId();
@ -212,7 +198,7 @@ void FileUploader::sendNext() {
i->docSentParts++;
} else {
UploadFileParts::iterator part = parts.begin();
mtpRequestId requestId = MTP::send(MTPupload_SaveFilePart(MTP_long(partsOfId), MTP_int(part.key()), MTP_string(part.value())), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::upl[todc]);
requestsSent.insert(requestId, part.value());
dcMap.insert(requestId, todc);
@ -303,7 +289,7 @@ void FileUploader::partLoaded(const MTPBool &result, mtpRequestId requestId) {
photo->uploadingData->offset = k->fileSentSize;
}
emit photoProgress(k.key());
} else if (k->type() == PrepareDocument) {
} else if (k->type() == PrepareDocument || k->type() == PrepareAudio) {
DocumentData *doc = App::document(k->id());
if (doc->uploading()) {
doc->uploadOffset = (k->docSentParts - docRequestsSent.size()) * k->docPartSize;
@ -312,15 +298,6 @@ void FileUploader::partLoaded(const MTPBool &result, mtpRequestId requestId) {
}
}
emit documentProgress(k.key());
} else if (k->type() == PrepareAudio) {
AudioData *audio = App::audio(k->id());
if (audio->uploading()) {
audio->uploadOffset = (k->docSentParts - docRequestsSent.size()) * k->docPartSize;
if (audio->uploadOffset > audio->size) {
audio->uploadOffset = audio->size;
}
}
emit audioProgress(k.key());
}
}
}

View File

@ -51,15 +51,12 @@ signals:
void photoReady(const FullMsgId &msgId, const MTPInputFile &file);
void documentReady(const FullMsgId &msgId, const MTPInputFile &file);
void thumbDocumentReady(const FullMsgId &msgId, const MTPInputFile &file, const MTPInputFile &thumb);
void audioReady(const FullMsgId &msgId, const MTPInputFile &file);
void photoProgress(const FullMsgId &msgId);
void documentProgress(const FullMsgId &msgId);
void audioProgress(const FullMsgId &msgId);
void photoFailed(const FullMsgId &msgId);
void documentFailed(const FullMsgId &msgId);
void audioFailed(const FullMsgId &msgId);
private:
@ -138,7 +135,7 @@ private:
QMap<mtpRequestId, int32> dcMap;
uint32 sentSize;
uint32 sentSizes[MTPUploadSessionsCount];
FullMsgId uploading, _paused;
Queue queue;
Queue uploaded;

View File

@ -352,8 +352,8 @@ bool History::updateTyping(uint64 ms, bool force) {
switch (sendActions.begin().value().type) {
case SendActionRecordVideo: newTypingStr = peer->isUser() ? lang(lng_send_action_record_video) : lng_user_action_record_video(lt_user, sendActions.begin().key()->firstName); break;
case SendActionUploadVideo: newTypingStr = peer->isUser() ? lang(lng_send_action_upload_video) : lng_user_action_upload_video(lt_user, sendActions.begin().key()->firstName); break;
case SendActionRecordAudio: newTypingStr = peer->isUser() ? lang(lng_send_action_record_audio) : lng_user_action_record_audio(lt_user, sendActions.begin().key()->firstName); break;
case SendActionUploadAudio: newTypingStr = peer->isUser() ? lang(lng_send_action_upload_audio) : lng_user_action_upload_audio(lt_user, sendActions.begin().key()->firstName); break;
case SendActionRecordVoice: newTypingStr = peer->isUser() ? lang(lng_send_action_record_audio) : lng_user_action_record_audio(lt_user, sendActions.begin().key()->firstName); break;
case SendActionUploadVoice: newTypingStr = peer->isUser() ? lang(lng_send_action_upload_audio) : lng_user_action_upload_audio(lt_user, sendActions.begin().key()->firstName); break;
case SendActionUploadPhoto: newTypingStr = peer->isUser() ? lang(lng_send_action_upload_photo) : lng_user_action_upload_photo(lt_user, sendActions.begin().key()->firstName); break;
case SendActionUploadFile: newTypingStr = peer->isUser() ? lang(lng_send_action_upload_file) : lng_user_action_upload_file(lt_user, sendActions.begin().key()->firstName); break;
case SendActionChooseLocation: newTypingStr = peer->isUser() ? lang(lng_send_action_geo_location) : lng_user_action_geo_location(lt_user, sendActions.begin().key()->firstName); break;
@ -1249,8 +1249,8 @@ void Histories::regSendAction(History *history, UserData *user, const MTPSendMes
case mtpc_sendMessageTypingAction: history->typing[user] = ms + 6000; break;
case mtpc_sendMessageRecordVideoAction: history->sendActions.insert(user, SendAction(SendActionRecordVideo, ms + 6000)); break;
case mtpc_sendMessageUploadVideoAction: history->sendActions.insert(user, SendAction(SendActionUploadVideo, ms + 6000, action.c_sendMessageUploadVideoAction().vprogress.v)); break;
case mtpc_sendMessageRecordAudioAction: history->sendActions.insert(user, SendAction(SendActionRecordAudio, ms + 6000)); break;
case mtpc_sendMessageUploadAudioAction: history->sendActions.insert(user, SendAction(SendActionUploadAudio, ms + 6000, action.c_sendMessageUploadAudioAction().vprogress.v)); break;
case mtpc_sendMessageRecordAudioAction: history->sendActions.insert(user, SendAction(SendActionRecordVoice, ms + 6000)); break;
case mtpc_sendMessageUploadAudioAction: history->sendActions.insert(user, SendAction(SendActionUploadVoice, ms + 6000, action.c_sendMessageUploadAudioAction().vprogress.v)); break;
case mtpc_sendMessageUploadPhotoAction: history->sendActions.insert(user, SendAction(SendActionUploadPhoto, ms + 6000, action.c_sendMessageUploadPhotoAction().vprogress.v)); break;
case mtpc_sendMessageUploadDocumentAction: history->sendActions.insert(user, SendAction(SendActionUploadFile, ms + 6000, action.c_sendMessageUploadDocumentAction().vprogress.v)); break;
case mtpc_sendMessageGeoLocationAction: history->sendActions.insert(user, SendAction(SendActionChooseLocation, ms + 6000)); break;
@ -1369,13 +1369,6 @@ HistoryItem *History::createItem(HistoryBlock *block, const MTPMessage &msg, boo
default: badMedia = 1; break;
}
break;
case mtpc_messageMediaAudio:
switch (m.vmedia.c_messageMediaAudio().vaudio.type()) {
case mtpc_audio: break;
case mtpc_audioEmpty: badMedia = 2; break;
default: badMedia = 1; break;
}
break;
case mtpc_messageMediaDocument:
switch (m.vmedia.c_messageMediaDocument().vdocument.type()) {
case mtpc_document: break;
@ -3060,18 +3053,14 @@ namespace {
return result;
}
int32 audioMaxStatusWidth(AudioData *audio) {
int32 result = st::normalFont->width(formatDownloadText(audio->size, audio->size));
result = qMax(result, st::normalFont->width(formatPlayedText(audio->duration, audio->duration)));
result = qMax(result, st::normalFont->width(formatDurationAndSizeText(audio->duration, audio->size)));
return result;
}
int32 documentMaxStatusWidth(DocumentData *document) {
int32 result = st::normalFont->width(formatDownloadText(document->size, document->size));
if (SongData *song = document->song()) {
result = qMax(result, st::normalFont->width(formatPlayedText(song->duration, song->duration)));
result = qMax(result, st::normalFont->width(formatDurationAndSizeText(song->duration, document->size)));
} else if (VoiceData *voice = document->voice()) {
result = qMax(result, st::normalFont->width(formatPlayedText(voice->duration, voice->duration)));
result = qMax(result, st::normalFont->width(formatDurationAndSizeText(voice->duration, document->size)));
} else {
result = qMax(result, st::normalFont->width(formatSizeText(document->size)));
}
@ -3785,291 +3774,151 @@ ImagePtr HistoryVideo::replyPreview() {
return _data->replyPreview;
}
HistoryAudio::HistoryAudio(const MTPDaudio &audio) : HistoryFileMedia()
, _data(App::feedAudio(audio)) {
setLinks(new AudioOpenLink(_data), new AudioOpenLink(_data), new AudioCancelLink(_data));
setStatusSize(FileStatusSizeReady);
HistoryDocumentVoicePlayback::HistoryDocumentVoicePlayback(const HistoryDocument *that)
: _position(0)
, a_progress(0., 0.)
, _a_progress(animation(const_cast<HistoryDocument*>(that), &HistoryDocument::step_voiceProgress)) {
}
HistoryAudio::HistoryAudio(const HistoryAudio &other) : HistoryFileMedia()
, _data(other._data) {
setLinks(new AudioOpenLink(_data), new AudioOpenLink(_data), new AudioCancelLink(_data));
setStatusSize(other._statusSize);
}
void HistoryAudio::initDimensions(const HistoryItem *parent) {
_maxw = st::msgFileMinWidth;
int32 tleft = 0, tright = 0;
tleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right();
tright = st::msgFileThumbPadding.left();
_maxw = qMax(_maxw, tleft + audioMaxStatusWidth(_data) + int(st::mediaUnreadSkip + st::mediaUnreadSize) + parent->skipBlockWidth() + st::msgPadding.right());
_maxw = qMax(tleft + st::semiboldFont->width(lang(lng_media_audio)) + tright, _maxw);
_maxw = qMin(_maxw, int(st::msgMaxWidth));
_height = _minh = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom();
}
void HistoryAudio::draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const {
if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return;
_data->automaticLoad(parent);
bool loaded = _data->loaded(), displayLoading = _data->displayLoading();
bool out = parent->out(), fromChannel = parent->fromChannel(), outbg = out && !fromChannel;
if (displayLoading) {
ensureAnimation(parent);
if (!_animation->radial.animating()) {
_animation->radial.start(_data->progress());
}
}
bool showPause = updateStatusText(parent);
bool radial = isRadialAnimation(ms);
int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0;
nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right();
nametop = st::msgFileNameTop;
nameright = st::msgFilePadding.left();
statustop = st::msgFileStatusTop;
QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width));
p.setPen(Qt::NoPen);
if (selected) {
p.setBrush(outbg ? st::msgFileOutBgSelected : st::msgFileInBgSelected);
} else if (isThumbAnimation(ms)) {
float64 over = _animation->a_thumbOver.current();
p.setBrush(style::interpolate(outbg ? st::msgFileOutBg : st::msgFileInBg, outbg ? st::msgFileOutBgOver : st::msgFileInBgOver, over));
} else {
bool over = textlnkDrawOver(_data->loading() ? _cancell : _savel);
p.setBrush(outbg ? (over ? st::msgFileOutBgOver : st::msgFileOutBg) : (over ? st::msgFileInBgOver : st::msgFileInBg));
}
p.setRenderHint(QPainter::HighQualityAntialiasing);
p.drawEllipse(inner);
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
if (radial) {
QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine)));
style::color bg(outbg ? (selected ? st::msgOutBgSelected : st::msgOutBg) : (selected ? st::msgInBgSelected : st::msgInBg));
_animation->radial.draw(p, rinner, st::msgFileRadialLine, bg);
}
style::sprite icon;
if (showPause) {
icon = outbg ? (selected ? st::msgFileOutPauseSelected : st::msgFileOutPause) : (selected ? st::msgFileInPauseSelected : st::msgFileInPause);
} else if (radial || _data->loading()) {
icon = outbg ? (selected ? st::msgFileOutCancelSelected : st::msgFileOutCancel) : (selected ? st::msgFileInCancelSelected : st::msgFileInCancel);
} else if (loaded) {
icon = outbg ? (selected ? st::msgFileOutPlaySelected : st::msgFileOutPlay) : (selected ? st::msgFileInPlaySelected : st::msgFileInPlay);
} else {
icon = outbg ? (selected ? st::msgFileOutDownloadSelected : st::msgFileOutDownload) : (selected ? st::msgFileInDownloadSelected : st::msgFileInDownload);
}
p.drawSpriteCenter(inner, icon);
int32 namewidth = _width - nameleft - nameright;
p.setFont(st::semiboldFont);
p.setPen(st::black);
p.drawTextLeft(nameleft, nametop, _width, lang(lng_media_audio));
style::color status(outbg ? (selected ? st::mediaOutFgSelected : st::mediaOutFg) : (selected ? st::mediaInFgSelected : st::mediaInFg));
p.setFont(st::normalFont);
p.setPen(status);
p.drawTextLeft(nameleft, statustop, _width, _statusText);
if (parent->isMediaUnread()) {
int32 w = st::normalFont->width(_statusText);
if (w + st::mediaUnreadSkip + st::mediaUnreadSize <= namewidth) {
p.setPen(Qt::NoPen);
p.setBrush(outbg ? (selected ? st::msgFileOutBgSelected : st::msgFileOutBg) : (selected ? st::msgFileInBgSelected : st::msgFileInBg));
p.setRenderHint(QPainter::HighQualityAntialiasing, true);
p.drawEllipse(rtlrect(nameleft + w + st::mediaUnreadSkip, statustop + st::mediaUnreadTop, st::mediaUnreadSize, st::mediaUnreadSize, _width));
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
}
void HistoryDocumentVoice::ensurePlayback(const HistoryDocument *that) const {
if (!_playback) {
_playback = new HistoryDocumentVoicePlayback(that);
}
}
void HistoryAudio::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const HistoryItem *parent) const {
if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return;
bool out = parent->out(), fromChannel = parent->fromChannel(), outbg = out && !fromChannel;
bool loaded = _data->loaded();
bool showPause = updateStatusText(parent);
int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0;
QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width));
if ((_data->loading() || _data->status == FileUploading || !loaded) && inner.contains(x, y)) {
lnk = (_data->loading() || _data->status == FileUploading) ? _cancell : _savel;
return;
void HistoryDocumentVoice::checkPlaybackFinished() const {
if (_playback && !_playback->_a_progress.animating()) {
delete _playback;
_playback = 0;
}
if (x >= 0 && y >= 0 && x < _width && y < _height && _data->access && !_data->loading()) {
lnk = _openl;
return;
}
}
const QString HistoryAudio::inDialogsText() const {
return lang(lng_in_dlg_audio);
}
const QString HistoryAudio::inHistoryText() const {
return qsl("[ ") + lang(lng_in_dlg_audio) + qsl(" ]");
}
void HistoryAudio::regItem(HistoryItem *item) {
App::regAudioItem(_data, item);
}
void HistoryAudio::unregItem(HistoryItem *item) {
App::unregAudioItem(_data, item);
}
void HistoryAudio::updateFrom(const MTPMessageMedia &media, HistoryItem *parent) {
if (media.type() == mtpc_messageMediaAudio) {
App::feedAudio(media.c_messageMediaAudio().vaudio, _data);
if (!_data->data().isEmpty()) {
Local::writeAudio(mediaKey(AudioFileLocation, _data->dc, _data->id), _data->data());
}
}
}
void HistoryAudio::setStatusSize(int32 newSize, qint64 realDuration) const {
HistoryFileMedia::setStatusSize(newSize, _data->size, _data->duration, realDuration);
}
bool HistoryAudio::updateStatusText(const HistoryItem *parent) const {
bool showPause = false;
int32 statusSize = 0, realDuration = 0;
if (_data->status == FileDownloadFailed || _data->status == FileUploadFailed) {
statusSize = FileStatusSizeFailed;
} else if (_data->status == FileUploading) {
statusSize = _data->uploadOffset;
} else if (_data->loading()) {
statusSize = _data->loadOffset();
} else if (_data->loaded()) {
AudioMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped;
int64 playingPosition = 0, playingDuration = 0;
int32 playingFrequency = 0;
if (audioPlayer()) {
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency);
}
if (playing.msgId == parent->fullId() && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
statusSize = -1 - (playingPosition / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency));
realDuration = playingDuration / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency);
showPause = (playingState == AudioPlayerPlaying || playingState == AudioPlayerResuming || playingState == AudioPlayerStarting);
} else {
statusSize = FileStatusSizeLoaded;
}
} else {
statusSize = FileStatusSizeReady;
}
if (statusSize != _statusSize) {
setStatusSize(statusSize, realDuration);
}
return showPause;
}
HistoryDocument::HistoryDocument(DocumentData *document, const QString &caption, const HistoryItem *parent) : HistoryFileMedia()
, _data(document)
, _linksavel(new DocumentSaveLink(_data))
, _linkcancell(new DocumentCancelLink(_data))
, _name(documentName(_data))
, _namew(st::semiboldFont->width(_name))
, _caption(st::msgFileMinWidth - st::msgPadding.left() - st::msgPadding.right()) {
setLinks(new DocumentOpenLink(_data), new DocumentSaveLink(_data), new DocumentCancelLink(_data));
, _parent(0)
, _data(document) {
create(!caption.isEmpty());
if (HistoryDocumentNamed *named = Get<HistoryDocumentNamed>()) {
named->_name = documentName(_data);
named->_namew = st::semiboldFont->width(named->_name);
}
setLinks(new DocumentOpenLink(_data), _data->voice() ? (ITextLink*)(new VoiceSaveLink(_data)) : new DocumentSaveLink(_data), new DocumentCancelLink(_data));
setStatusSize(FileStatusSizeReady);
if (!caption.isEmpty()) {
_caption.setText(st::msgFont, caption + parent->skipBlock(), itemTextNoMonoOptions(parent));
if (HistoryDocumentCaptioned *captioned = Get<HistoryDocumentCaptioned>()) {
captioned->_caption.setText(st::msgFont, caption + parent->skipBlock(), itemTextNoMonoOptions(parent));
}
}
HistoryDocument::HistoryDocument(const HistoryDocument &other) : HistoryFileMedia()
, _data(other._data)
, _linksavel(new DocumentSaveLink(_data))
, _linkcancell(new DocumentCancelLink(_data))
, _name(other._name)
, _namew(other._namew)
, _thumbw(other._thumbw)
, _caption(other._caption) {
setLinks(new DocumentOpenLink(_data), new DocumentSaveLink(_data), new DocumentCancelLink(_data));
, _parent(0)
, _data(other._data) {
const HistoryDocumentCaptioned *captioned = other.Get<HistoryDocumentCaptioned>();
create(captioned != 0);
if (HistoryDocumentNamed *named = Get<HistoryDocumentNamed>()) {
if (const HistoryDocumentNamed *oin = other.Get<HistoryDocumentNamed>()) {
named->_name = oin->_name;
named->_namew = oin->_namew;
} else {
named->_name = documentName(_data);
named->_namew = st::semiboldFont->width(named->_name);
}
}
setLinks(new DocumentOpenLink(_data), _data->voice() ? (ITextLink*)(new VoiceSaveLink(_data)) : new DocumentSaveLink(_data), new DocumentCancelLink(_data));
setStatusSize(other._statusSize);
if (captioned) {
Get<HistoryDocumentCaptioned>()->_caption = captioned->_caption;
}
}
void HistoryDocument::create(bool caption) {
uint64 mask;
if (_data->voice()) {
mask = HistoryDocumentVoice::Bit();
} else {
mask = HistoryDocumentNamed::Bit();
if (caption) {
mask |= HistoryDocumentCaptioned::Bit();
}
if (!_data->song() && !_data->thumb->isNull() && _data->thumb->width() && _data->thumb->height()) {
mask |= HistoryDocumentThumbed::Bit();
}
}
UpdateInterfaces(mask);
if (HistoryDocumentThumbed *thumbed = Get<HistoryDocumentThumbed>()) {
thumbed->_linksavel.reset(new DocumentSaveLink(_data));
thumbed->_linkcancell.reset(new DocumentCancelLink(_data));
}
}
void HistoryDocument::initDimensions(const HistoryItem *parent) {
if (_caption.hasSkipBlock()) {
_caption.setSkipBlock(parent->skipBlockWidth(), parent->skipBlockHeight());
_parent = parent;
HistoryDocumentCaptioned *captioned = Get<HistoryDocumentCaptioned>();
if (captioned && captioned->_caption.hasSkipBlock()) {
captioned->_caption.setSkipBlock(parent->skipBlockWidth(), parent->skipBlockHeight());
}
if (withThumb()) {
HistoryDocumentThumbed *thumbed = Get<HistoryDocumentThumbed>();
if (thumbed) {
_data->thumb->load();
int32 tw = _data->thumb->width(), th = _data->thumb->height();
if (tw > th) {
_thumbw = (tw * st::msgFileThumbSize) / th;
thumbed->_thumbw = (tw * st::msgFileThumbSize) / th;
} else {
_thumbw = st::msgFileThumbSize;
thumbed->_thumbw = st::msgFileThumbSize;
}
} else {
_thumbw = 0;
}
_maxw = st::msgFileMinWidth;
int32 tleft = 0, tright = 0;
bool wthumb = withThumb();
if (wthumb) {
if (thumbed) {
tleft = st::msgFileThumbPadding.left() + st::msgFileThumbSize + st::msgFileThumbPadding.right();
tright = st::msgFileThumbPadding.left();
_maxw = qMax(_maxw, tleft + documentMaxStatusWidth(_data) + tright);
} else {
tleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right();
tright = st::msgFileThumbPadding.left();
_maxw = qMax(_maxw, tleft + documentMaxStatusWidth(_data) + parent->skipBlockWidth() + st::msgPadding.right());
int32 unread = _data->voice() ? (st::mediaUnreadSkip + st::mediaUnreadSize) : 0;
_maxw = qMax(_maxw, tleft + documentMaxStatusWidth(_data) + unread + parent->skipBlockWidth() + st::msgPadding.right());
}
_maxw = qMax(tleft + _namew + tright, _maxw);
_maxw = qMin(_maxw, int(st::msgMaxWidth));
if (HistoryDocumentNamed *named = Get<HistoryDocumentNamed>()) {
_maxw = qMax(tleft + named->_namew + tright, _maxw);
_maxw = qMin(_maxw, int(st::msgMaxWidth));
}
if (wthumb) {
if (thumbed) {
_minh = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom();
} else {
_minh = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom();
}
if (_caption.isEmpty()) {
_height = _minh;
if (captioned) {
_minh += captioned->_caption.countHeight(_maxw - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom();
} else {
_minh += _caption.countHeight(_maxw - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom();
_height = _minh;
}
}
int32 HistoryDocument::resize(int32 width, const HistoryItem *parent) {
if (_caption.isEmpty()) {
HistoryDocumentCaptioned *captioned = Get<HistoryDocumentCaptioned>();
if (!captioned) {
return HistoryFileMedia::resize(width, parent);
}
_width = qMin(width, _maxw);
bool wthumb = withThumb();
if (wthumb) {
if (Get<HistoryDocumentThumbed>()) {
_height = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom();
} else {
_height = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom();
}
_height += _caption.countHeight(_width - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom();
_height += captioned->_caption.countHeight(_width - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom();
return _height;
}
@ -4094,8 +3943,7 @@ void HistoryDocument::draw(Painter &p, const HistoryItem *parent, const QRect &r
bool radial = isRadialAnimation(ms);
int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0, bottom = 0;
bool wthumb = withThumb();
if (wthumb) {
if (const HistoryDocumentThumbed *thumbed = Get<HistoryDocumentThumbed>()) {
nameleft = st::msgFileThumbPadding.left() + st::msgFileThumbSize + st::msgFileThumbPadding.right();
nametop = st::msgFileThumbNameTop;
nameright = st::msgFileThumbPadding.left();
@ -4104,7 +3952,7 @@ void HistoryDocument::draw(Painter &p, const HistoryItem *parent, const QRect &r
bottom = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom();
QRect rthumb(rtlrect(st::msgFileThumbPadding.left(), st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, _width));
QPixmap thumb = loaded ? _data->thumb->pixSingle(_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize) : _data->thumb->pixBlurredSingle(_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize);
QPixmap thumb = loaded ? _data->thumb->pixSingle(thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize) : _data->thumb->pixBlurredSingle(thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize);
p.drawPixmap(rthumb.topLeft(), thumb);
if (selected) {
App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, SelectedOverlayCorners);
@ -4148,11 +3996,11 @@ void HistoryDocument::draw(Painter &p, const HistoryItem *parent, const QRect &r
}
if (_data->status != FileUploadFailed) {
const TextLinkPtr &lnk((_data->loading() || _data->status == FileUploading) ? _linkcancell : _linksavel);
const TextLinkPtr &lnk((_data->loading() || _data->status == FileUploading) ? thumbed->_linkcancell : thumbed->_linksavel);
bool over = textlnkDrawOver(lnk);
p.setFont(over ? st::semiboldFont->underline() : st::semiboldFont);
p.setPen(outbg ? (selected ? st::msgFileThumbLinkOutFgSelected : st::msgFileThumbLinkOutFg) : (selected ? st::msgFileThumbLinkInFgSelected : st::msgFileThumbLinkInFg));
p.drawTextLeft(nameleft, linktop, _width, _link, _linkw);
p.drawTextLeft(nameleft, linktop, _width, thumbed->_link, thumbed->_linkw);
}
} else {
nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right();
@ -4189,7 +4037,7 @@ void HistoryDocument::draw(Painter &p, const HistoryItem *parent, const QRect &r
} else if (radial || _data->loading()) {
icon = outbg ? (selected ? st::msgFileOutCancelSelected : st::msgFileOutCancel) : (selected ? st::msgFileInCancelSelected : st::msgFileInCancel);
} else if (loaded) {
if (_data->song()) {
if (_data->song() || _data->voice()) {
icon = outbg ? (selected ? st::msgFileOutPlaySelected : st::msgFileOutPlay) : (selected ? st::msgFileInPlaySelected : st::msgFileInPlay);
} else if (_data->isImage()) {
icon = outbg ? (selected ? st::msgFileOutImageSelected : st::msgFileOutImage) : (selected ? st::msgFileInImageSelected : st::msgFileInImage);
@ -4203,12 +4051,70 @@ void HistoryDocument::draw(Painter &p, const HistoryItem *parent, const QRect &r
}
int32 namewidth = _width - nameleft - nameright;
p.setFont(st::semiboldFont);
p.setPen(st::black);
if (namewidth < _namew) {
p.drawTextLeft(nameleft, nametop, _width, st::semiboldFont->elided(_name, namewidth));
} else {
p.drawTextLeft(nameleft, nametop, _width, _name, _namew);
if (const HistoryDocumentVoice *voice = Get<HistoryDocumentVoice>()) {
const VoiceWaveform *wf = 0;
uchar norm_value = 0;
if (_data->voice()) {
wf = &_data->voice()->waveform;
if (wf->isEmpty()) {
wf = 0;
if (loaded) {
Local::countVoiceWaveform(_data);
}
} else if (wf->at(0) < 0) {
wf = 0;
} else {
norm_value = _data->voice()->wavemax;
}
}
float64 prg = voice->_playback ? voice->_playback->a_progress.current() : 0;
// rescale waveform by going in waveform.size * bar_count 1D grid
style::color active(outbg ? st::msgWaveformOutActive : st::msgWaveformInActive);
style::color inactive(outbg ? st::msgWaveformOutInactive : st::msgWaveformInInactive);
int32 wf_size = wf ? wf->size() : WaveformSamplesCount, availw = int32(namewidth + st::msgWaveformSkip), activew = qRound(availw * prg);
int32 bar_count = qMin(availw / int32(st::msgWaveformBar + st::msgWaveformSkip), wf_size);
uchar max_value = 0;
int32 max_delta = st::msgWaveformMax - st::msgWaveformMin, bottom = st::msgFilePadding.top() + st::msgWaveformMax;
p.setPen(Qt::NoPen);
for (uint32 i = 0, bar_x = 0, sum_i = 0; i < wf_size; ++i) {
uchar value = wf ? wf->at(i) : 0;
if (sum_i + bar_count >= wf_size) { // draw bar
sum_i = sum_i + bar_count - wf_size;
if (sum_i < (bar_count + 1) / 2) {
if (max_value < value) max_value = value;
}
int32 bar_value = ((max_value * max_delta) + ((norm_value + 1) / 2)) / (norm_value + 1);
if (bar_x >= activew) {
p.fillRect(nameleft + bar_x, bottom - bar_value, st::msgWaveformBar, st::msgWaveformMin + bar_value, inactive);
} else if (bar_x + st::msgWaveformBar <= activew) {
p.fillRect(nameleft + bar_x, bottom - bar_value, st::msgWaveformBar, st::msgWaveformMin + bar_value, active);
} else {
p.fillRect(nameleft + bar_x, bottom - bar_value, activew - bar_x, st::msgWaveformMin + bar_value, active);
p.fillRect(nameleft + activew, bottom - bar_value, st::msgWaveformBar - (activew - bar_x), st::msgWaveformMin + bar_value, inactive);
}
bar_x += st::msgWaveformBar + st::msgWaveformSkip;
if (sum_i < (bar_count + 1) / 2) {
max_value = 0;
} else {
max_value = value;
}
} else {
if (max_value < value) max_value = value;
sum_i += bar_count;
}
}
} else if (const HistoryDocumentNamed *named = Get<HistoryDocumentNamed>()) {
p.setFont(st::semiboldFont);
p.setPen(st::black);
if (namewidth < named->_namew) {
p.drawTextLeft(nameleft, nametop, _width, st::semiboldFont->elided(named->_name, namewidth));
} else {
p.drawTextLeft(nameleft, nametop, _width, named->_name, named->_namew);
}
}
style::color status(outbg ? (selected ? st::mediaOutFgSelected : st::mediaOutFg) : (selected ? st::mediaInFgSelected : st::mediaInFg));
@ -4216,9 +4122,21 @@ void HistoryDocument::draw(Painter &p, const HistoryItem *parent, const QRect &r
p.setPen(status);
p.drawTextLeft(nameleft, statustop, _width, _statusText);
if (!_caption.isEmpty()) {
if (parent->isMediaUnread()) {
int32 w = st::normalFont->width(_statusText);
if (w + st::mediaUnreadSkip + st::mediaUnreadSize <= namewidth) {
p.setPen(Qt::NoPen);
p.setBrush(outbg ? (selected ? st::msgFileOutBgSelected : st::msgFileOutBg) : (selected ? st::msgFileInBgSelected : st::msgFileInBg));
p.setRenderHint(QPainter::HighQualityAntialiasing, true);
p.drawEllipse(rtlrect(nameleft + w + st::mediaUnreadSkip, statustop + st::mediaUnreadTop, st::mediaUnreadSize, st::mediaUnreadSize, _width));
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
}
}
if (const HistoryDocumentCaptioned *captioned = Get<HistoryDocumentCaptioned>()) {
p.setPen(st::black);
_caption.draw(p, st::msgPadding.left(), bottom, captionw);
captioned->_caption.draw(p, st::msgPadding.left(), bottom, captionw);
}
}
@ -4231,8 +4149,7 @@ void HistoryDocument::getState(TextLinkPtr &lnk, HistoryCursorState &state, int3
bool showPause = updateStatusText(parent);
int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0, bottom = 0;
bool wthumb = withThumb();
if (wthumb) {
if (const HistoryDocumentThumbed *thumbed = Get<HistoryDocumentThumbed>()) {
nameleft = st::msgFileThumbPadding.left() + st::msgFileThumbSize + st::msgFileThumbPadding.right();
linktop = st::msgFileThumbLinkTop;
bottom = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom();
@ -4245,8 +4162,8 @@ void HistoryDocument::getState(TextLinkPtr &lnk, HistoryCursorState &state, int3
}
if (_data->status != FileUploadFailed) {
if (rtlrect(nameleft, linktop, _linkw, st::semiboldFont->height, _width).contains(x, y)) {
lnk = (_data->loading() || _data->uploading()) ? _linkcancell : _linksavel;
if (rtlrect(nameleft, linktop, thumbed->_linkw, st::semiboldFont->height, _width).contains(x, y)) {
lnk = (_data->loading() || _data->uploading()) ? thumbed->_linkcancell : thumbed->_linksavel;
return;
}
}
@ -4261,14 +4178,14 @@ void HistoryDocument::getState(TextLinkPtr &lnk, HistoryCursorState &state, int3
}
int32 height = _height;
if (!_caption.isEmpty()) {
if (const HistoryDocumentCaptioned *captioned = Get<HistoryDocumentCaptioned>()) {
if (y >= bottom) {
bool inText = false;
_caption.getState(lnk, inText, x - st::msgPadding.left(), y - bottom, _width - st::msgPadding.left() - st::msgPadding.right());
captioned->_caption.getState(lnk, inText, x - st::msgPadding.left(), y - bottom, _width - st::msgPadding.left() - st::msgPadding.right());
state = inText ? HistoryInTextCursorState : HistoryDefaultCursorState;
return;
}
height -= _caption.countHeight(_width - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom();
height -= captioned->_caption.countHeight(_width - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom();
}
if (x >= 0 && y >= 0 && x < _width && y < height && !_data->loading() && !_data->uploading() && _data->access) {
lnk = _openl;
@ -4277,28 +4194,53 @@ void HistoryDocument::getState(TextLinkPtr &lnk, HistoryCursorState &state, int3
}
const QString HistoryDocument::inDialogsText() const {
return (_name.isEmpty() ? lang(lng_in_dlg_file) : _name) + (_caption.isEmpty() ? QString() : (' ' + _caption.original(0, 0xFFFF, Text::ExpandLinksNone)));
QString result;
if (Get<HistoryDocumentVoice>()) {
result = lang(lng_in_dlg_audio);
} else {
const HistoryDocumentNamed *named = Get<HistoryDocumentNamed>();
result = (!named || named->_name.isEmpty()) ? lang(lng_in_dlg_file) : named->_name;
}
if (const HistoryDocumentCaptioned *captioned = Get<HistoryDocumentCaptioned>()) {
if (!captioned->_caption.isEmpty()) {
result.append(' ').append(captioned->_caption.original(0, 0xFFFF, Text::ExpandLinksNone));
}
}
return result;
}
const QString HistoryDocument::inHistoryText() const {
return qsl("[ ") + lang(lng_in_dlg_file) + (_name.isEmpty() ? QString() : (qsl(" : ") + _name)) + (_caption.isEmpty() ? QString() : (qsl(", ") + _caption.original(0, 0xFFFF, Text::ExpandLinksAll))) + qsl(" ]");
QString result = qsl("[ ") + lang(Get<HistoryDocumentVoice>() ? lng_in_dlg_audio : lng_in_dlg_file);
if (const HistoryDocumentNamed *named = Get<HistoryDocumentNamed>()) {
if (!named->_name.isEmpty()) {
result.append(qsl(" : ")).append(named->_name);
}
}
if (const HistoryDocumentCaptioned *captioned = Get<HistoryDocumentCaptioned>()) {
if (!captioned->_caption.isEmpty()) {
result.append(qsl(", ")).append(captioned->_caption.original(0, 0xFFFF, Text::ExpandLinksAll));
}
}
return result.append(qsl(" ]"));
}
void HistoryDocument::setStatusSize(int32 newSize, qint64 realDuration) const {
HistoryFileMedia::setStatusSize(newSize, _data->size, _data->song() ? _data->song()->duration : -1, realDuration);
if (_statusSize == FileStatusSizeReady) {
_link = lang(lng_media_download).toUpper();
} else if (_statusSize == FileStatusSizeLoaded) {
_link = lang(lng_media_open_with).toUpper();
} else if (_statusSize == FileStatusSizeFailed) {
_link = lang(lng_media_download).toUpper();
} else if (_statusSize >= 0) {
_link = lang(lng_media_cancel).toUpper();
} else {
_link = lang(lng_media_open_with).toUpper();
int32 duration = _data->song() ? _data->song()->duration : (_data->voice() ? _data->voice()->duration : -1);
HistoryFileMedia::setStatusSize(newSize, _data->size, duration, realDuration);
if (const HistoryDocumentThumbed *thumbed = Get<HistoryDocumentThumbed>()) {
if (_statusSize == FileStatusSizeReady) {
thumbed->_link = lang(lng_media_download).toUpper();
} else if (_statusSize == FileStatusSizeLoaded) {
thumbed->_link = lang(lng_media_open_with).toUpper();
} else if (_statusSize == FileStatusSizeFailed) {
thumbed->_link = lang(lng_media_download).toUpper();
} else if (_statusSize >= 0) {
thumbed->_link = lang(lng_media_cancel).toUpper();
} else {
thumbed->_link = lang(lng_media_open_with).toUpper();
}
thumbed->_linkw = st::semiboldFont->width(thumbed->_link);
}
_linkw = st::semiboldFont->width(_link);
}
bool HistoryDocument::updateStatusText(const HistoryItem *parent) const {
@ -4311,7 +4253,41 @@ bool HistoryDocument::updateStatusText(const HistoryItem *parent) const {
} else if (_data->loading()) {
statusSize = _data->loadOffset();
} else if (_data->loaded()) {
if (_data->song()) {
if (_data->voice()) {
AudioMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped;
int64 playingPosition = 0, playingDuration = 0;
int32 playingFrequency = 0;
if (audioPlayer()) {
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency);
}
if (playing.msgId == parent->fullId() && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
if (const HistoryDocumentVoice *voice = Get<HistoryDocumentVoice>()) {
bool was = voice->_playback;
voice->ensurePlayback(this);
if (!was || playingPosition != voice->_playback->_position) {
float64 prg = playingDuration ? snap(float64(playingPosition) / playingDuration, 0., 1.) : 0.;
if (voice->_playback->_position < playingPosition) {
voice->_playback->a_progress.start(prg);
} else {
voice->_playback->a_progress = anim::fvalue(0., prg);
}
voice->_playback->_position = playingPosition;
voice->_playback->_a_progress.start();
}
}
statusSize = -1 - (playingPosition / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency));
realDuration = playingDuration / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency);
showPause = (playingState == AudioPlayerPlaying || playingState == AudioPlayerResuming || playingState == AudioPlayerStarting);
} else {
statusSize = FileStatusSizeLoaded;
if (const HistoryDocumentVoice *voice = Get<HistoryDocumentVoice>()) {
voice->checkPlaybackFinished();
}
}
} else if (_data->song()) {
SongMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped;
int64 playingPosition = 0, playingDuration = 0;
@ -4342,6 +4318,21 @@ bool HistoryDocument::updateStatusText(const HistoryItem *parent) const {
return showPause;
}
void HistoryDocument::step_voiceProgress(float64 ms, bool timer) {
if (HistoryDocumentVoice *voice = Get<HistoryDocumentVoice>()) {
if (voice->_playback) {
float64 dt = ms / (2 * AudioVoiceMsgUpdateView);
if (dt >= 1) {
voice->_playback->_a_progress.stop();
voice->_playback->a_progress.finish();
} else {
voice->_playback->a_progress.update(qMin(dt, 1.), anim::linear);
}
if (timer) Ui::repaintHistoryItem(_parent);
}
}
}
void HistoryDocument::regItem(HistoryItem *item) {
App::regDocumentItem(_data, item);
}
@ -4353,6 +4344,13 @@ void HistoryDocument::unregItem(HistoryItem *item) {
void HistoryDocument::updateFrom(const MTPMessageMedia &media, HistoryItem *parent) {
if (media.type() == mtpc_messageMediaDocument) {
App::feedDocument(media.c_messageMediaDocument().vdocument, _data);
if (!_data->data().isEmpty()) {
if (_data->voice()) {
Local::writeAudio(mediaKey(AudioFileLocation, _data->dc, _data->id), _data->data());
} else {
Local::writeStickerImage(mediaKey(DocumentFileLocation, _data->dc, _data->id), _data->data());
}
}
}
}
@ -4361,6 +4359,7 @@ ImagePtr HistoryDocument::replyPreview() {
}
HistoryGif::HistoryGif(DocumentData *document, const QString &caption, const HistoryItem *parent) : HistoryFileMedia()
, _parent(0)
, _data(document)
, _thumbw(1)
, _thumbh(1)
@ -5126,7 +5125,6 @@ void HistoryWebPage::initDimensions(const HistoryItem *parent) {
_maxw = _minh = _height = 0;
return;
}
if (!_lineHeight) _lineHeight = qMax(st::webPageTitleFont->height, st::webPageDescriptionFont->height);
if (!_openl && !_data->url.isEmpty()) _openl = TextLinkPtr(new TextLink(_data->url));
@ -5144,7 +5142,7 @@ void HistoryWebPage::initDimensions(const HistoryItem *parent) {
} else {
_asArticle = true;
}
if (_asArticle && (_data->description.isEmpty() || (title.isEmpty() && _data->siteName.isEmpty()))) {
if (_asArticle && _data->description.isEmpty() && title.isEmpty() && _data->siteName.isEmpty()) {
_asArticle = false;
}
} else {
@ -6121,12 +6119,6 @@ void HistoryMessage::initMedia(const MTPMessageMedia *media, QString &currentTex
_media = new HistoryVideo(video.vvideo.c_video(), qs(video.vcaption), this);
}
} break;
case mtpc_messageMediaAudio: {
const MTPAudio &audio(media->c_messageMediaAudio().vaudio);
if (audio.type() == mtpc_audio) {
_media = new HistoryAudio(audio.c_audio());
}
} break;
case mtpc_messageMediaDocument: {
const MTPDocument &document(media->c_messageMediaDocument().vdocument);
if (document.type() == mtpc_document) {
@ -6225,8 +6217,8 @@ void HistoryMessage::countPositionAndSize(int32 &left, int32 &width) const {
left += (!fromChannel() && out() && !Adaptive::Wide()) ? st::msgMargin.right() : st::msgMargin.left();
if (displayFromPhoto()) {
left += st::msgPhotoSkip;
} else if (!Adaptive::Wide() && !out() && !fromChannel() && st::msgPhotoSkip - (hmaxwidth - hwidth) > 0) {
left += st::msgPhotoSkip - (hmaxwidth - hwidth);
// } else if (!Adaptive::Wide() && !out() && !fromChannel() && st::msgPhotoSkip - (hmaxwidth - hwidth) > 0) {
// left += st::msgPhotoSkip - (hmaxwidth - hwidth);
}
width = hwidth - st::msgMargin.left() - st::msgMargin.right();

View File

@ -95,23 +95,24 @@ enum HistoryMediaType {
MediaTypeVideo,
MediaTypeGeo,
MediaTypeContact,
MediaTypeAudio,
MediaTypeDocument,
MediaTypeFile,
MediaTypeGif,
MediaTypeSticker,
MediaTypeImageLink,
MediaTypeWebPage,
MediaTypeMusicFile,
MediaTypeVoiceFile,
MediaTypeCount
};
enum MediaOverviewType {
OverviewPhotos,
OverviewVideos,
OverviewAudioDocuments,
OverviewDocuments,
OverviewAudios,
OverviewLinks,
OverviewPhotos = 0,
OverviewVideos = 1,
OverviewMusicFiles = 2,
OverviewFiles = 3,
OverviewVoiceFiles = 4,
OverviewLinks = 5,
OverviewCount
};
@ -120,9 +121,9 @@ inline MTPMessagesFilter typeToMediaFilter(MediaOverviewType &type) {
switch (type) {
case OverviewPhotos: return MTP_inputMessagesFilterPhotos();
case OverviewVideos: return MTP_inputMessagesFilterVideo();
case OverviewAudioDocuments: return MTP_inputMessagesFilterAudioDocuments();
case OverviewDocuments: return MTP_inputMessagesFilterDocument();
case OverviewAudios: return MTP_inputMessagesFilterAudio();
case OverviewMusicFiles: return MTP_inputMessagesFilterMusic();
case OverviewFiles: return MTP_inputMessagesFilterDocument();
case OverviewVoiceFiles: return MTP_inputMessagesFilterVoice();
case OverviewLinks: return MTP_inputMessagesFilterUrl();
default: type = OverviewCount; break;
}
@ -133,8 +134,8 @@ enum SendActionType {
SendActionTyping,
SendActionRecordVideo,
SendActionUploadVideo,
SendActionRecordAudio,
SendActionUploadAudio,
SendActionRecordVoice,
SendActionUploadVoice,
SendActionUploadPhoto,
SendActionUploadFile,
SendActionChooseLocation,
@ -1205,10 +1206,11 @@ inline MediaOverviewType mediaToOverviewType(HistoryMedia *media) {
switch (media->type()) {
case MediaTypePhoto: return OverviewPhotos;
case MediaTypeVideo: return OverviewVideos;
case MediaTypeDocument: return media->getDocument()->song() ? OverviewAudioDocuments : OverviewDocuments;
case MediaTypeGif: return media->getDocument()->isGifv() ? OverviewCount : OverviewDocuments;
// case MediaTypeSticker: return OverviewDocuments;
case MediaTypeAudio: return OverviewAudios;
case MediaTypeFile: return OverviewFiles;
case MediaTypeMusicFile: return media->getDocument()->isMusic() ? OverviewMusicFiles : OverviewFiles;
case MediaTypeVoiceFile: return OverviewVoiceFiles;
case MediaTypeGif: return media->getDocument()->isGifv() ? OverviewCount : OverviewFiles;
// case MediaTypeSticker: return OverviewFiles;
}
return OverviewCount;
}
@ -1418,76 +1420,52 @@ private:
};
class HistoryAudio : public HistoryFileMedia {
public:
HistoryAudio(const MTPDaudio &audio);
HistoryAudio(const HistoryAudio &other);
HistoryMediaType type() const {
return MediaTypeAudio;
struct HistoryDocumentThumbed : public BasicInterface<HistoryDocumentThumbed> {
HistoryDocumentThumbed(Interfaces *interfaces) : _thumbw(0), _linkw(0) {
}
HistoryMedia *clone() const {
return new HistoryAudio(*this);
TextLinkPtr _linksavel, _linkcancell;
int32 _thumbw;
mutable int32 _linkw;
mutable QString _link;
};
struct HistoryDocumentCaptioned : public BasicInterface<HistoryDocumentCaptioned> {
HistoryDocumentCaptioned(Interfaces *interfaces) : _caption(st::msgFileMinWidth - st::msgPadding.left() - st::msgPadding.right()) {
}
void initDimensions(const HistoryItem *parent);
void draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const;
void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const HistoryItem *parent) const;
const QString inDialogsText() const;
const QString inHistoryText() const;
bool uploading() const {
return _data->uploading();
Text _caption;
};
struct HistoryDocumentNamed : public BasicInterface<HistoryDocumentNamed> {
HistoryDocumentNamed(Interfaces *interfaces) : _namew(0) {
}
QString _name;
int32 _namew;
};
class HistoryDocument;
struct HistoryDocumentVoicePlayback {
HistoryDocumentVoicePlayback(const HistoryDocument *that);
AudioData *audio() {
return _data;
int32 _position;
anim::fvalue a_progress;
Animation _a_progress;
};
struct HistoryDocumentVoice : public BasicInterface<HistoryDocumentVoice> {
HistoryDocumentVoice(Interfaces *that) : _playback(0) {
}
void regItem(HistoryItem *item);
void unregItem(HistoryItem *item);
void updateFrom(const MTPMessageMedia &media, HistoryItem *parent);
bool needsBubble(const HistoryItem *parent) const {
return true;
~HistoryDocumentVoice() {
deleteAndMark(_playback);
}
bool customInfoLayout() const {
return false;
}
QMargins bubbleMargins() const {
return st::msgPadding;
}
protected:
float64 dataProgress() const {
return _data->progress();
}
bool dataFinished() const {
return !_data->loading() && !_data->uploading();
}
bool dataLoaded() const {
return _data->loaded();
}
private:
AudioData *_data;
void setStatusSize(int32 newSize, qint64 realDuration = 0) const;
bool updateStatusText(const HistoryItem *parent) const; // returns showPause
void ensurePlayback(const HistoryDocument *interfaces) const;
void checkPlaybackFinished() const;
mutable HistoryDocumentVoicePlayback *_playback;
};
class HistoryDocument : public HistoryFileMedia {
class HistoryDocument : public HistoryFileMedia, public Interfaces {
public:
HistoryDocument(DocumentData *document, const QString &caption, const HistoryItem *parent);
HistoryDocument(const HistoryDocument &other);
HistoryMediaType type() const {
return MediaTypeDocument;
return _data->voice() ? MediaTypeVoiceFile : (_data->song() ? MediaTypeMusicFile : MediaTypeFile);
}
HistoryMedia *clone() const {
return new HistoryDocument(*this);
@ -1506,10 +1484,6 @@ public:
return _data->uploading();
}
bool withThumb() const {
return !_data->song() && !_data->thumb->isNull() && _data->thumb->width() && _data->thumb->height();
}
DocumentData *getDocument() {
return _data;
}
@ -1525,7 +1499,10 @@ public:
ImagePtr replyPreview();
QString getCaption() const {
return _caption.original();
if (const HistoryDocumentCaptioned *captioned = Get<HistoryDocumentCaptioned>()) {
return captioned->_caption.original();
}
return QString();
}
bool needsBubble(const HistoryItem *parent) const {
return true;
@ -1534,12 +1511,14 @@ public:
return false;
}
QMargins bubbleMargins() const {
return withThumb() ? QMargins(st::msgFileThumbPadding.left(), st::msgFileThumbPadding.top(), st::msgFileThumbPadding.left(), st::msgFileThumbPadding.bottom()) : st::msgPadding;
return Get<HistoryDocumentThumbed>() ? QMargins(st::msgFileThumbPadding.left(), st::msgFileThumbPadding.top(), st::msgFileThumbPadding.left(), st::msgFileThumbPadding.bottom()) : st::msgPadding;
}
bool hideForwardedFrom() const {
return _data->song();
}
void step_voiceProgress(float64 ms, bool timer);
protected:
float64 dataProgress() const {
@ -1554,17 +1533,9 @@ protected:
private:
void create(bool caption);
const HistoryItem *_parent;
DocumentData *_data;
TextLinkPtr _linksavel, _linkcancell;
QString _name;
int32 _namew;
int32 _thumbw;
mutable int32 _linkw;
mutable QString _link;
Text _caption;
void setStatusSize(int32 newSize, qint64 realDuration = 0) const;
bool updateStatusText(const HistoryItem *parent) const; // returns showPause
@ -2237,7 +2208,20 @@ inline int32 newMessageFlags(PeerData *p) {
return p->isSelf() ? 0 : (((p->isChat() || (p->isUser() && !p->asUser()->botInfo)) ? MTPDmessage::flag_unread : 0) | MTPDmessage::flag_out);
}
inline int32 newForwardedFlags(PeerData *p, int32 from, HistoryMessage *msg) {
return newMessageFlags(p) | (from ? MTPDmessage::flag_from_id : 0) | (msg->via() ? MTPDmessage::flag_via_bot_id : 0) | (!p->isChannel() && msg->getMedia() && (msg->getMedia()->type() == MediaTypeAudio/* || msg->getMedia()->type() == MediaTypeVideo*/) ? MTPDmessage::flag_media_unread : 0);
int32 result = newMessageFlags(p) | (from ? MTPDmessage::flag_from_id : 0);
if (msg->via()) {
result |= MTPDmessage::flag_via_bot_id;
}
if (!p->isChannel()) {
if (HistoryMedia *media = msg->getMedia()) {
if (media->type() == MediaTypeVoiceFile) {
result |= MTPDmessage::flag_media_unread;
// } else if (media->type() == MediaTypeVideo) {
// result |= MTPDmessage::flag_media_unread;
}
}
}
return result;
}
class HistoryServiceMsg : public HistoryItem {

View File

@ -865,9 +865,9 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
HistoryItem *item = App::hoveredItem() ? App::hoveredItem() : App::hoveredLinkItem();
PhotoLink *lnkPhoto = dynamic_cast<PhotoLink*>(_contextMenuLnk.data());
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data());
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data());
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
if (lnkPhoto || lnkVideo || lnkAudio || lnkDocument) {
bool lnkIsAudio = lnkDocument ? lnkDocument->document()->voice() : false;
if (lnkPhoto || lnkVideo || lnkDocument) {
if (isUponSelected > 0) {
_menu->addAction(lang(lng_context_copy_selected), this, SLOT(copySelectedText()))->setEnabled(true);
}
@ -879,17 +879,17 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
_menu->addAction(lang(lng_context_save_image), this, SLOT(saveContextImage()))->setEnabled(true);
_menu->addAction(lang(lng_context_copy_image), this, SLOT(copyContextImage()))->setEnabled(true);
} else {
if ((lnkVideo && lnkVideo->video()->loading()) || (lnkAudio && lnkAudio->audio()->loading()) || (lnkDocument && lnkDocument->document()->loading())) {
if ((lnkVideo && lnkVideo->video()->loading()) || (lnkDocument && lnkDocument->document()->loading())) {
_menu->addAction(lang(lng_context_cancel_download), this, SLOT(cancelContextDownload()))->setEnabled(true);
} else {
if (lnkDocument && lnkDocument->document()->loaded() && lnkDocument->document()->isGifv()) {
_menu->addAction(lang(lng_context_save_gif), this, SLOT(saveContextGif()))->setEnabled(true);
}
if ((lnkVideo && !lnkVideo->video()->already(true).isEmpty()) || (lnkAudio && !lnkAudio->audio()->already(true).isEmpty()) || (lnkDocument && !lnkDocument->document()->already(true).isEmpty())) {
if ((lnkVideo && !lnkVideo->video()->already(true).isEmpty()) || (lnkDocument && !lnkDocument->document()->already(true).isEmpty())) {
_menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), this, SLOT(showContextInFolder()))->setEnabled(true);
}
_menu->addAction(lang(lnkVideo ? lng_context_open_video : (lnkAudio ? lng_context_open_audio : lng_context_open_file)), this, SLOT(openContextFile()))->setEnabled(true);
_menu->addAction(lang(lnkVideo ? lng_context_save_video : (lnkAudio ? lng_context_save_audio : lng_context_save_file)), this, SLOT(saveContextFile()))->setEnabled(true);
_menu->addAction(lang(lnkVideo ? lng_context_open_video : (lnkIsAudio ? lng_context_open_audio : lng_context_open_file)), this, SLOT(openContextFile()))->setEnabled(true);
_menu->addAction(lang(lnkVideo ? lng_context_save_video : (lnkIsAudio ? lng_context_save_audio : lng_context_save_file)), this, SLOT(saveContextFile()))->setEnabled(true);
}
}
if (isUponSelected > 1) {
@ -1071,8 +1071,6 @@ void HistoryInner::copyContextImage() {
void HistoryInner::cancelContextDownload() {
if (VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data())) {
lnkVideo->video()->cancel();
} else if (AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data())) {
lnkAudio->audio()->cancel();
} else if (DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data())) {
lnkDocument->document()->cancel();
} else if (HistoryItem *item = App::contextItem()) {
@ -1088,8 +1086,6 @@ void HistoryInner::showContextInFolder() {
QString already;
if (VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data())) {
already = lnkVideo->video()->already(true);
} else if (AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data())) {
already = lnkAudio->audio()->already(true);
} else if (DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data())) {
already = lnkDocument->document()->already(true);
} else if (HistoryItem *item = App::contextItem()) {
@ -1106,10 +1102,8 @@ void HistoryInner::openContextFile() {
HistoryItem *was = App::hoveredLinkItem();
App::hoveredLinkItem(App::contextItem());
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data());
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data());
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
if (lnkVideo) VideoOpenLink(lnkVideo->video()).onClick(Qt::LeftButton);
if (lnkAudio) AudioOpenLink(lnkAudio->audio()).onClick(Qt::LeftButton);
if (lnkDocument) DocumentOpenLink(lnkDocument->document()).onClick(Qt::LeftButton);
App::hoveredLinkItem(was);
}
@ -1117,8 +1111,6 @@ void HistoryInner::openContextFile() {
void HistoryInner::saveContextFile() {
if (VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data())) {
VideoSaveLink::doSave(lnkVideo->video(), true);
} else if (AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data())) {
AudioSaveLink::doSave(lnkAudio->audio(), true);
} else if (DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data())) {
DocumentSaveLink::doSave(lnkDocument->document(), true);
} else if (HistoryItem *item = App::contextItem()) {
@ -2720,8 +2712,8 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreviewTimeout()));
if (audioCapture()) {
connect(audioCapture(), SIGNAL(onError()), this, SLOT(onRecordError()));
connect(audioCapture(), SIGNAL(onUpdate(qint16,qint32)), this, SLOT(onRecordUpdate(qint16,qint32)));
connect(audioCapture(), SIGNAL(onDone(QByteArray,qint32)), this, SLOT(onRecordDone(QByteArray,qint32)));
connect(audioCapture(), SIGNAL(onUpdate(quint16,qint32)), this, SLOT(onRecordUpdate(quint16,qint32)));
connect(audioCapture(), SIGNAL(onDone(QByteArray,VoiceWaveform,qint32)), this, SLOT(onRecordDone(QByteArray,VoiceWaveform,qint32)));
}
_updateHistoryItems.setSingleShot(true);
@ -3005,8 +2997,8 @@ void HistoryWidget::updateSendAction(History *history, SendActionType type, int3
case SendActionTyping: action = MTP_sendMessageTypingAction(); break;
case SendActionRecordVideo: action = MTP_sendMessageRecordVideoAction(); break;
case SendActionUploadVideo: action = MTP_sendMessageUploadVideoAction(MTP_int(progress)); break;
case SendActionRecordAudio: action = MTP_sendMessageRecordAudioAction(); break;
case SendActionUploadAudio: action = MTP_sendMessageUploadAudioAction(MTP_int(progress)); break;
case SendActionRecordVoice: action = MTP_sendMessageRecordAudioAction(); break;
case SendActionUploadVoice: action = MTP_sendMessageUploadAudioAction(MTP_int(progress)); break;
case SendActionUploadPhoto: action = MTP_sendMessageUploadPhotoAction(MTP_int(progress)); break;
case SendActionUploadFile: action = MTP_sendMessageUploadDocumentAction(MTP_int(progress)); break;
case SendActionChooseLocation: action = MTP_sendMessageGeoLocationAction(); break;
@ -3055,16 +3047,16 @@ void HistoryWidget::onRecordError() {
stopRecording(false);
}
void HistoryWidget::onRecordDone(QByteArray result, qint32 samples) {
void HistoryWidget::onRecordDone(QByteArray result, VoiceWaveform waveform, qint32 samples) {
if (!_peer) return;
App::wnd()->activateWindow();
int32 duration = samples / AudioVoiceMsgFrequency;
_fileLoader.addTask(new FileLoadTask(result, duration, FileLoadTo(_peer->id, _broadcast.checked(), replyToId())));
_fileLoader.addTask(new FileLoadTask(result, duration, waveform, FileLoadTo(_peer->id, _broadcast.checked(), replyToId())));
cancelReply(lastForceReplyReplied());
}
void HistoryWidget::onRecordUpdate(qint16 level, qint32 samples) {
void HistoryWidget::onRecordUpdate(quint16 level, qint32 samples) {
if (!_recording) {
return;
}
@ -3077,7 +3069,7 @@ void HistoryWidget::onRecordUpdate(qint16 level, qint32 samples) {
}
updateField();
if (_peer && (!_peer->isChannel() || _peer->isMegagroup() || !_peer->asChannel()->canPublish() || (!_peer->asChannel()->isBroadcast() && !_broadcast.checked()))) {
updateSendAction(_history, SendActionRecordAudio);
updateSendAction(_history, SendActionRecordVoice);
}
}
@ -4241,9 +4233,9 @@ void HistoryWidget::firstLoadMessages() {
}
if (loadImportant) {
_firstLoadRequest = MTP::send(MTPchannels_GetImportantHistory(from->asChannel()->inputChannel, MTP_int(offset_id), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from), rpcFail(&HistoryWidget::messagesFailed));
_firstLoadRequest = MTP::send(MTPchannels_GetImportantHistory(from->asChannel()->inputChannel, MTP_int(offset_id), MTP_int(0), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from), rpcFail(&HistoryWidget::messagesFailed));
} else {
_firstLoadRequest = MTP::send(MTPmessages_GetHistory(from->input, MTP_int(offset_id), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from), rpcFail(&HistoryWidget::messagesFailed));
_firstLoadRequest = MTP::send(MTPmessages_GetHistory(from->input, MTP_int(offset_id), MTP_int(offset), MTP_int(0), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from), rpcFail(&HistoryWidget::messagesFailed));
}
}
@ -4265,9 +4257,9 @@ void HistoryWidget::loadMessages() {
int32 offset = 0, loadCount = offset_id ? MessagesPerPage : MessagesFirstLoad;
if (loadImportant) {
_preloadRequest = MTP::send(MTPchannels_GetImportantHistory(from->peer->asChannel()->inputChannel, MTP_int(offset_id), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from->peer), rpcFail(&HistoryWidget::messagesFailed));
_preloadRequest = MTP::send(MTPchannels_GetImportantHistory(from->peer->asChannel()->inputChannel, MTP_int(offset_id), MTP_int(0), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from->peer), rpcFail(&HistoryWidget::messagesFailed));
} else {
_preloadRequest = MTP::send(MTPmessages_GetHistory(from->peer->input, MTP_int(offset_id), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from->peer), rpcFail(&HistoryWidget::messagesFailed));
_preloadRequest = MTP::send(MTPmessages_GetHistory(from->peer->input, MTP_int(offset_id), MTP_int(0), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from->peer), rpcFail(&HistoryWidget::messagesFailed));
}
}
@ -4295,9 +4287,9 @@ void HistoryWidget::loadMessagesDown() {
}
if (loadImportant) {
_preloadDownRequest = MTP::send(MTPchannels_GetImportantHistory(from->peer->asChannel()->inputChannel, MTP_int(offset_id + 1), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from->peer), rpcFail(&HistoryWidget::messagesFailed));
_preloadDownRequest = MTP::send(MTPchannels_GetImportantHistory(from->peer->asChannel()->inputChannel, MTP_int(offset_id + 1), MTP_int(0), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from->peer), rpcFail(&HistoryWidget::messagesFailed));
} else {
_preloadDownRequest = MTP::send(MTPmessages_GetHistory(from->peer->input, MTP_int(offset_id + 1), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from->peer), rpcFail(&HistoryWidget::messagesFailed));
_preloadDownRequest = MTP::send(MTPmessages_GetHistory(from->peer->input, MTP_int(offset_id + 1), MTP_int(0), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from->peer), rpcFail(&HistoryWidget::messagesFailed));
}
}
@ -4355,9 +4347,9 @@ void HistoryWidget::delayedShowAt(MsgId showAtMsgId) {
}
if (loadImportant) {
_delayedShowAtRequest = MTP::send(MTPchannels_GetImportantHistory(from->asChannel()->inputChannel, MTP_int(offset_id), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from), rpcFail(&HistoryWidget::messagesFailed));
_delayedShowAtRequest = MTP::send(MTPchannels_GetImportantHistory(from->asChannel()->inputChannel, MTP_int(offset_id), MTP_int(0), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from), rpcFail(&HistoryWidget::messagesFailed));
} else {
_delayedShowAtRequest = MTP::send(MTPmessages_GetHistory(from->input, MTP_int(offset_id), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from), rpcFail(&HistoryWidget::messagesFailed));
_delayedShowAtRequest = MTP::send(MTPmessages_GetHistory(from->input, MTP_int(offset_id), MTP_int(0), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from), rpcFail(&HistoryWidget::messagesFailed));
}
}
@ -4807,7 +4799,7 @@ void HistoryWidget::onDocumentSelect() {
void HistoryWidget::dragEnterEvent(QDragEnterEvent *e) {
if (!_history) return;
if (_peer && (_peer->isChannel() && !_peer->asChannel()->canPublish())) return;
if (_peer && !_canSendMessages) return;
_attachDrag = getDragState(e->mimeData());
updateDragAreas();
@ -4887,7 +4879,7 @@ void HistoryWidget::stopRecording(bool send) {
_recording = false;
_recordingSamples = 0;
if (_peer && (!_peer->isChannel() || _peer->isMegagroup() || !_peer->asChannel()->canPublish() || (!_peer->asChannel()->isBroadcast() && !_broadcast.checked()))) {
updateSendAction(_history, SendActionRecordAudio, -1);
updateSendAction(_history, SendActionRecordVoice, -1);
}
updateControlsVisibility();
@ -5151,7 +5143,7 @@ void HistoryWidget::onPhotoDrop(const QMimeData *data) {
void HistoryWidget::onDocumentDrop(const QMimeData *data) {
if (!_history) return;
if (_peer && (_peer->isChannel() && !_peer->asChannel()->canPublish())) return;
if (_peer && !_canSendMessages) return;
QStringList files = getMediasFromMime(data);
if (files.isEmpty()) return;
@ -5161,7 +5153,7 @@ void HistoryWidget::onDocumentDrop(const QMimeData *data) {
void HistoryWidget::onFilesDrop(const QMimeData *data) {
if (_peer && (_peer->isChannel() && !_peer->asChannel()->canPublish())) return;
if (_peer && !_canSendMessages) return;
QStringList files = getMediasFromMime(data);
if (files.isEmpty()) {
@ -5522,13 +5514,10 @@ void HistoryWidget::confirmSendFile(const FileLoadResultPtr &file, bool ctrlShif
connect(App::uploader(), SIGNAL(photoReady(const FullMsgId&, const MTPInputFile&)), this, SLOT(onPhotoUploaded(const FullMsgId&, const MTPInputFile&)), Qt::UniqueConnection);
connect(App::uploader(), SIGNAL(documentReady(const FullMsgId&, const MTPInputFile&)), this, SLOT(onDocumentUploaded(const FullMsgId&, const MTPInputFile&)), Qt::UniqueConnection);
connect(App::uploader(), SIGNAL(thumbDocumentReady(const FullMsgId&, const MTPInputFile&, const MTPInputFile&)), this, SLOT(onThumbDocumentUploaded(const FullMsgId&, const MTPInputFile&, const MTPInputFile&)), Qt::UniqueConnection);
connect(App::uploader(), SIGNAL(audioReady(const FullMsgId&, const MTPInputFile&)), this, SLOT(onAudioUploaded(const FullMsgId&, const MTPInputFile&)), Qt::UniqueConnection);
connect(App::uploader(), SIGNAL(photoProgress(const FullMsgId&)), this, SLOT(onPhotoProgress(const FullMsgId&)), Qt::UniqueConnection);
connect(App::uploader(), SIGNAL(documentProgress(const FullMsgId&)), this, SLOT(onDocumentProgress(const FullMsgId&)), Qt::UniqueConnection);
connect(App::uploader(), SIGNAL(audioProgress(const FullMsgId&)), this, SLOT(onAudioProgress(const FullMsgId&)), Qt::UniqueConnection);
connect(App::uploader(), SIGNAL(photoFailed(const FullMsgId&)), this, SLOT(onPhotoFailed(const FullMsgId&)), Qt::UniqueConnection);
connect(App::uploader(), SIGNAL(documentFailed(const FullMsgId&)), this, SLOT(onDocumentFailed(const FullMsgId&)), Qt::UniqueConnection);
connect(App::uploader(), SIGNAL(audioFailed(const FullMsgId&)), this, SLOT(onAudioFailed(const FullMsgId&)), Qt::UniqueConnection);
App::uploader()->upload(newId, file);
@ -5552,7 +5541,7 @@ void HistoryWidget::confirmSendFile(const FileLoadResultPtr &file, bool ctrlShif
if (!h->peer->isChannel()) {
flags |= MTPDmessage::flag_media_unread;
}
h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(file->to.peer), MTPPeer(), MTPint(), MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaAudio(file->audio), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread);
h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(file->to.peer), MTPPeer(), MTPint(), MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(file->document, MTP_string(file->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread);
}
if (_peer && file->to.peer == _peer->id) {
@ -5628,7 +5617,9 @@ namespace {
} else if (document->type == StickerDocument && document->sticker()) {
attributes.push_back(MTP_documentAttributeSticker(MTP_string(document->sticker()->alt), document->sticker()->set));
} else if (document->type == SongDocument && document->song()) {
attributes.push_back(MTP_documentAttributeAudio(MTP_int(document->song()->duration), MTP_string(document->song()->title), MTP_string(document->song()->performer)));
attributes.push_back(MTP_documentAttributeAudio(MTP_int(MTPDdocumentAttributeAudio::flag_title | MTPDdocumentAttributeAudio::flag_performer), MTP_int(document->song()->duration), MTP_string(document->song()->title), MTP_string(document->song()->performer), MTPstring()));
} else if (document->type == VoiceDocument && document->voice()) {
attributes.push_back(MTP_documentAttributeAudio(MTP_int(MTPDdocumentAttributeAudio::flag_voice | MTPDdocumentAttributeAudio::flag_waveform), MTP_int(document->voice()->duration), MTPstring(), MTPstring(), MTP_string(documentWaveformEncode5bit(document->voice()->waveform))));
}
return MTP_vector<MTPDocumentAttribute>(attributes);
}
@ -5684,33 +5675,6 @@ void HistoryWidget::onThumbDocumentUploaded(const FullMsgId &newId, const MTPInp
}
}
void HistoryWidget::onAudioUploaded(const FullMsgId &newId, const MTPInputFile &file) {
if (!MTP::authedId()) return;
HistoryMessage *item = dynamic_cast<HistoryMessage*>(App::histItemById(newId));
if (item) {
AudioData *audio = 0;
if (HistoryAudio *media = dynamic_cast<HistoryAudio*>(item->getMedia())) {
audio = media->audio();
}
if (audio) {
uint64 randomId = MTP::nonce<uint64>();
App::historyRegRandom(randomId, newId);
History *hist = item->history();
MsgId replyTo = item->toHistoryReply() ? item->toHistoryReply()->replyToId() : 0;
int32 sendFlags = 0;
if (replyTo) {
sendFlags |= MTPmessages_SendMedia::flag_reply_to_msg_id;
}
bool fromChannelName = hist->peer->isChannel() && !hist->peer->isMegagroup() && hist->peer->asChannel()->canPublish() && item->fromChannel();
if (fromChannelName) {
sendFlags |= MTPmessages_SendMedia::flag_broadcast;
}
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_int(sendFlags), item->history()->peer->input, MTP_int(replyTo), MTP_inputMediaUploadedAudio(file, MTP_int(audio->duration), MTP_string(audio->mime)), MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), 0, 0, hist->sendRequestId);
}
}
}
void HistoryWidget::onPhotoProgress(const FullMsgId &newId) {
if (!MTP::authedId()) return;
if (HistoryItem *item = App::histItemById(newId)) {
@ -5728,18 +5692,7 @@ void HistoryWidget::onDocumentProgress(const FullMsgId &newId) {
HistoryMedia *media = item->getMedia();
DocumentData *doc = media ? media->getDocument() : 0;
if (!item->fromChannel()) {
updateSendAction(item->history(), SendActionUploadFile, doc ? doc->uploadOffset : 0);
}
Ui::repaintHistoryItem(item);
}
}
void HistoryWidget::onAudioProgress(const FullMsgId &newId) {
if (!MTP::authedId()) return;
if (HistoryItem *item = App::histItemById(newId)) {
AudioData *audio = (item->getMedia() && item->getMedia()->type() == MediaTypeAudio) ? static_cast<HistoryAudio*>(item->getMedia())->audio() : 0;
if (!item->fromChannel()) {
updateSendAction(item->history(), SendActionUploadAudio, audio ? audio->uploadOffset : 0);
updateSendAction(item->history(), (doc && doc->voice()) ? SendActionUploadVoice : SendActionUploadFile, doc ? doc->uploadOffset : 0);
}
Ui::repaintHistoryItem(item);
}
@ -5760,19 +5713,10 @@ void HistoryWidget::onDocumentFailed(const FullMsgId &newId) {
if (!MTP::authedId()) return;
HistoryItem *item = App::histItemById(newId);
if (item) {
HistoryMedia *media = item->getMedia();
DocumentData *doc = media ? media->getDocument() : 0;
if (!item->fromChannel()) {
updateSendAction(item->history(), SendActionUploadFile, -1);
}
Ui::repaintHistoryItem(item);
}
}
void HistoryWidget::onAudioFailed(const FullMsgId &newId) {
if (!MTP::authedId()) return;
HistoryItem *item = App::histItemById(newId);
if (item) {
if (!item->fromChannel()) {
updateSendAction(item->history(), SendActionUploadAudio, -1);
updateSendAction(item->history(), (doc && doc->voice()) ? SendActionUploadVoice : SendActionUploadFile, -1);
}
Ui::repaintHistoryItem(item);
}
@ -7194,7 +7138,7 @@ void HistoryWidget::drawRecording(Painter &p) {
p.setPen(Qt::NoPen);
p.setBrush(st::recordSignalColor->b);
p.setRenderHint(QPainter::HighQualityAntialiasing);
float64 delta = qMin(float64(a_recordingLevel.current()) * 3 * M_PI / 0x7fff, 1.);
float64 delta = qMin(float64(a_recordingLevel.current()) / 0x4000, 1.);
int32 d = 2 * qRound(st::recordSignalMin + (delta * (st::recordSignalMax - st::recordSignalMin)));
p.drawEllipse(_attachPhoto.x() + (_attachEmoji.width() - d) / 2, _attachPhoto.y() + (_attachPhoto.height() - d) / 2, d, d);
p.setRenderHint(QPainter::HighQualityAntialiasing, false);

View File

@ -610,15 +610,12 @@ public slots:
void onPhotoUploaded(const FullMsgId &msgId, const MTPInputFile &file);
void onDocumentUploaded(const FullMsgId &msgId, const MTPInputFile &file);
void onThumbDocumentUploaded(const FullMsgId &msgId, const MTPInputFile &file, const MTPInputFile &thumb);
void onAudioUploaded(const FullMsgId &msgId, const MTPInputFile &file);
void onPhotoProgress(const FullMsgId &msgId);
void onDocumentProgress(const FullMsgId &msgId);
void onAudioProgress(const FullMsgId &msgId);
void onPhotoFailed(const FullMsgId &msgId);
void onDocumentFailed(const FullMsgId &msgId);
void onAudioFailed(const FullMsgId &msgId);
void onReportSpamClicked();
void onReportSpamSure();
@ -683,8 +680,8 @@ public slots:
void updateField();
void onRecordError();
void onRecordDone(QByteArray result, qint32 samples);
void onRecordUpdate(qint16 level, qint32 samples);
void onRecordDone(QByteArray result, VoiceWaveform waveform, qint32 samples);
void onRecordUpdate(quint16 level, qint32 samples);
void onUpdateHistoryItems();

View File

@ -550,23 +550,25 @@ void LayoutOverviewVideo::updateStatusText() const {
}
}
LayoutOverviewAudio::LayoutOverviewAudio(AudioData *audio, HistoryItem *parent) : LayoutAbstractFileItem(OverviewItemInfo::Bit(), parent)
, _data(audio)
, _namel(new AudioOpenLink(_data)) {
setLinks(new AudioOpenLink(_data), new AudioOpenLink(_data), new AudioCancelLink(_data));
LayoutOverviewVoice::LayoutOverviewVoice(DocumentData *voice, HistoryItem *parent) : LayoutAbstractFileItem(OverviewItemInfo::Bit(), parent)
, _data(voice)
, _namel(new DocumentOpenLink(_data)) {
t_assert(_data->voice() != 0);
setLinks(new DocumentOpenLink(_data), new DocumentOpenLink(_data), new DocumentCancelLink(_data));
updateName();
QString d = textcmdLink(1, textRichPrepare(langDateTime(date(_data->date))));
TextParseOptions opts = { TextParseRichText, 0, 0, Qt::LayoutDirectionAuto };
_details.setText(st::normalFont, lng_date_and_duration(lt_date, d, lt_duration, formatDurationText(_data->duration)), opts);
_details.setText(st::normalFont, lng_date_and_duration(lt_date, d, lt_duration, formatDurationText(_data->voice()->duration)), opts);
_details.setLink(1, TextLinkPtr(new MessageLink(parent)));
}
void LayoutOverviewAudio::initDimensions() {
void LayoutOverviewVoice::initDimensions() {
_maxw = st::profileMaxWidth;
_minh = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom() + st::lineWidth;
}
void LayoutOverviewAudio::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const {
void LayoutOverviewVoice::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const {
bool selected = (selection == FullSelection);
_data->automaticLoad(_parent);
@ -666,7 +668,7 @@ void LayoutOverviewAudio::paint(Painter &p, const QRect &clip, uint32 selection,
}
}
void LayoutOverviewAudio::getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const {
void LayoutOverviewVoice::getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const {
bool loaded = _data->loaded();
bool showPause = updateStatusText();
@ -696,7 +698,7 @@ void LayoutOverviewAudio::getState(TextLinkPtr &link, HistoryCursorState &cursor
}
}
void LayoutOverviewAudio::updateName() const {
void LayoutOverviewVoice::updateName() const {
int32 version = 0;
if (HistoryForwarded *fwd = _parent->toHistoryForwarded()) {
_name.setText(st::semiboldFont, lang(lng_forwarded_from) + ' ' + App::peerName(fwd->fromForwarded()), _textNameOptions);
@ -708,7 +710,7 @@ void LayoutOverviewAudio::updateName() const {
_nameVersion = version;
}
bool LayoutOverviewAudio::updateStatusText() const {
bool LayoutOverviewVoice::updateStatusText() const {
bool showPause = false;
int32 statusSize = 0, realDuration = 0;
if (_data->status == FileDownloadFailed || _data->status == FileUploadFailed) {
@ -733,7 +735,7 @@ bool LayoutOverviewAudio::updateStatusText() const {
statusSize = FileStatusSizeReady;
}
if (statusSize != _statusSize) {
setStatusSize(statusSize, _data->size, _data->duration, realDuration);
setStatusSize(statusSize, _data->size, _data->voice()->duration, realDuration);
}
return showPause;
}

View File

@ -349,9 +349,9 @@ private:
};
class LayoutOverviewAudio : public LayoutAbstractFileItem {
class LayoutOverviewVoice : public LayoutAbstractFileItem {
public:
LayoutOverviewAudio(AudioData *audio, HistoryItem *parent);
LayoutOverviewVoice(DocumentData *voice, HistoryItem *parent);
virtual void initDimensions();
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const;
@ -372,7 +372,7 @@ protected:
}
private:
AudioData *_data;
DocumentData *_data;
TextLinkPtr _namel;
mutable Text _name, _details;

View File

@ -198,10 +198,11 @@ FileLoadTask::FileLoadTask(const QImage &image, PrepareMediaType type, const Fil
, _result(0) {
}
FileLoadTask::FileLoadTask(const QByteArray &audio, int32 duration, const FileLoadTo &to) : _id(MTP::nonce<uint64>())
FileLoadTask::FileLoadTask(const QByteArray &voice, int32 duration, const VoiceWaveform &waveform, const FileLoadTo &to) : _id(MTP::nonce<uint64>())
, _to(to)
, _content(audio)
, _content(voice)
, _duration(duration)
, _waveform(waveform)
, _type(PrepareAudio)
, _confirm(FileLoadNoForceConfirm)
, _result(0) {
@ -220,7 +221,7 @@ void FileLoadTask::process() {
QString thumbname = "thumb.jpg";
QByteArray thumbdata;
bool animated = false;
bool animated = false, song = false, gif = false, voice = (_type == PrepareAudio);
QImage fullimage = _image;
if (!_filepath.isEmpty()) {
@ -232,30 +233,32 @@ void FileLoadTask::process() {
filesize = info.size();
filemime = mimeTypeForFile(info).name();
filename = info.fileName();
if (filesize <= MaxUploadPhotoSize && _type != PrepareAudio) {
if (filesize <= MaxUploadPhotoSize && !voice) {
bool opaque = (filemime != stickerMime);
fullimage = App::readImage(_filepath, 0, opaque, &animated);
}
} else if (!_content.isEmpty()) {
filesize = _content.size();
MimeType mimeType = mimeTypeForData(_content);
filemime = mimeType.name();
if (filesize <= MaxUploadPhotoSize && _type != PrepareAudio) {
bool opaque = (filemime != stickerMime);
fullimage = App::readImage(_content, 0, opaque, &animated);
}
if (filemime == "image/jpeg") {
filename = filedialogDefaultName(qsl("image"), qsl(".jpg"), QString(), true);
} else if (_type == PrepareAudio) {
if (voice) {
filename = filedialogDefaultName(qsl("audio"), qsl(".ogg"), QString(), true);
filemime = "audio/ogg";
} else {
QString ext;
QStringList patterns = mimeType.globPatterns();
if (!patterns.isEmpty()) {
ext = patterns.front().replace('*', QString());
MimeType mimeType = mimeTypeForData(_content);
filemime = mimeType.name();
if (filesize <= MaxUploadPhotoSize && !voice) {
bool opaque = (filemime != stickerMime);
fullimage = App::readImage(_content, 0, opaque, &animated);
}
if (filemime == "image/jpeg") {
filename = filedialogDefaultName(qsl("image"), qsl(".jpg"), QString(), true);
} else {
QString ext;
QStringList patterns = mimeType.globPatterns();
if (!patterns.isEmpty()) {
ext = patterns.front().replace('*', QString());
}
filename = filedialogDefaultName(qsl("file"), ext, QString(), true);
}
filename = filedialogDefaultName(qsl("file"), ext, QString(), true);
}
} else if (!_image.isNull()) {
_image = QImage();
@ -292,10 +295,8 @@ void FileLoadTask::process() {
MTPPhotoSize thumbSize(MTP_photoSizeEmpty(MTP_string("")));
MTPPhoto photo(MTP_photoEmpty(MTP_long(0)));
MTPDocument document(MTP_documentEmpty(MTP_long(0)));
MTPAudio audio(MTP_audioEmpty(MTP_long(0)));
bool song = false, gif = false;
if (_type != PrepareAudio) {
if (!voice) {
if (filemime == qstr("audio/mp3") || filemime == qstr("audio/m4a") || filemime == qstr("audio/aac") || filemime == qstr("audio/ogg") || filemime == qstr("audio/flac") ||
filename.endsWith(qstr(".mp3"), Qt::CaseInsensitive) || filename.endsWith(qstr(".m4a"), Qt::CaseInsensitive) ||
filename.endsWith(qstr(".aac"), Qt::CaseInsensitive) || filename.endsWith(qstr(".ogg"), Qt::CaseInsensitive) ||
@ -358,7 +359,7 @@ void FileLoadTask::process() {
}
}
if (!fullimage.isNull() && fullimage.width() > 0 && !song && !gif) {
if (!fullimage.isNull() && fullimage.width() > 0 && !song && !gif && !voice) {
int32 w = fullimage.width(), h = fullimage.height();
attributes.push_back(MTP_documentAttributeImageSize(MTP_int(w), MTP_int(h)));
@ -408,8 +409,10 @@ void FileLoadTask::process() {
}
}
if (_type == PrepareAudio) {
audio = MTP_audio(MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_int(_duration), MTP_string(filemime), MTP_int(filesize), MTP_int(MTP::maindc()));
if (voice) {
attributes[0] = MTP_documentAttributeAudio(MTP_int(MTPDdocumentAttributeAudio::flag_voice | MTPDdocumentAttributeAudio::flag_waveform), MTP_int(_duration), MTPstring(), MTPstring(), MTP_string(documentWaveformEncode5bit(_waveform)));
attributes.resize(1);
document = MTP_document(MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_string(filemime), MTP_int(filesize), thumbSize, MTP_int(MTP::maindc()), MTP_vector<MTPDocumentAttribute>(attributes));
} else {
document = MTP_document(MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_string(filemime), MTP_int(filesize), thumbSize, MTP_int(MTP::maindc()), MTP_vector<MTPDocumentAttribute>(attributes));
if (photo.type() == mtpc_photoEmpty) {
@ -431,7 +434,6 @@ void FileLoadTask::process() {
_result->thumb = thumb;
_result->photo = photo;
_result->audio = audio;
_result->document = document;
_result->photoThumbs = photoThumbs;
}

View File

@ -52,8 +52,8 @@ typedef QList<ToPrepareMedia> ToPrepareMedias;
typedef QMap<int32, QByteArray> UploadFileParts;
struct ReadyLocalMedia {
ReadyLocalMedia(PrepareMediaType type, const QString &file, const QString &filename, int32 filesize, const QByteArray &data, const uint64 &id, const uint64 &thumbId, const QString &thumbExt, const PeerId &peer, const MTPPhoto &photo, const MTPAudio &audio, const PreparedPhotoThumbs &photoThumbs, const MTPDocument &document, const QByteArray &jpeg, bool broadcast, bool ctrlShiftEnter, MsgId replyTo) :
replyTo(replyTo), type(type), file(file), filename(filename), filesize(filesize), data(data), thumbExt(thumbExt), id(id), thumbId(thumbId), peer(peer), photo(photo), document(document), audio(audio), photoThumbs(photoThumbs), broadcast(broadcast), ctrlShiftEnter(ctrlShiftEnter) {
ReadyLocalMedia(PrepareMediaType type, const QString &file, const QString &filename, int32 filesize, const QByteArray &data, const uint64 &id, const uint64 &thumbId, const QString &thumbExt, const PeerId &peer, const MTPPhoto &photo, const PreparedPhotoThumbs &photoThumbs, const MTPDocument &document, const QByteArray &jpeg, bool broadcast, bool ctrlShiftEnter, MsgId replyTo) :
replyTo(replyTo), type(type), file(file), filename(filename), filesize(filesize), data(data), thumbExt(thumbExt), id(id), thumbId(thumbId), peer(peer), photo(photo), document(document), photoThumbs(photoThumbs), broadcast(broadcast), ctrlShiftEnter(ctrlShiftEnter) {
if (!jpeg.isEmpty()) {
int32 size = jpeg.size();
for (int32 i = 0, part = 0; i < size; i += UploadPartSize, ++part) {
@ -74,7 +74,6 @@ struct ReadyLocalMedia {
MTPPhoto photo;
MTPDocument document;
MTPAudio audio;
PreparedPhotoThumbs photoThumbs;
UploadFileParts parts;
QByteArray jpeg_md5;
@ -114,7 +113,7 @@ public:
TaskId addTask(TaskPtr task);
void addTasks(const TasksList &tasks);
void cancelTask(TaskId id); // this task finish() won't be called
TaskId addTask(Task *task) {
return addTask(TaskPtr(task));
}
@ -203,7 +202,6 @@ struct FileLoadResult {
QPixmap thumb;
MTPPhoto photo;
MTPAudio audio;
MTPDocument document;
PreparedPhotoThumbs photoThumbs;
@ -248,7 +246,7 @@ public:
FileLoadTask(const QString &filepath, PrepareMediaType type, const FileLoadTo &to, FileLoadForceConfirmType confirm = FileLoadNoForceConfirm);
FileLoadTask(const QByteArray &content, PrepareMediaType type, const FileLoadTo &to);
FileLoadTask(const QImage &image, PrepareMediaType type, const FileLoadTo &to, FileLoadForceConfirmType confirm = FileLoadNoForceConfirm, const QString &originalText = QString());
FileLoadTask(const QByteArray &audio, int32 duration, const FileLoadTo &to);
FileLoadTask(const QByteArray &voice, int32 duration, const VoiceWaveform &waveform, const FileLoadTo &to);
uint64 fileid() const {
return _id;
@ -265,6 +263,7 @@ protected:
QImage _image;
QByteArray _content;
int32 _duration;
VoiceWaveform _waveform;
PrepareMediaType _type;
FileLoadForceConfirmType _confirm;
QString _originalText;

View File

@ -2785,6 +2785,77 @@ namespace Local {
return _storageWebFilesSize;
}
class CountWaveformTask : public Task {
public:
CountWaveformTask(DocumentData *doc)
: _doc(doc)
, _loc(doc->location(true))
, _data(doc->data())
, _wavemax(0) {
if (_data.isEmpty() && !_loc.accessEnable()) {
_doc = 0;
}
}
void process() {
if (!_doc) return;
_waveform = audioCountWaveform(_loc, _data);
uchar wavemax = 0;
for (int32 i = 0, l = _waveform.size(); i < l; ++i) {
uchar waveat = _waveform.at(i);
if (wavemax < waveat) wavemax = waveat;
}
_wavemax = wavemax;
}
void finish() {
if (VoiceData *voice = _doc ? _doc->voice() : 0) {
if (!_waveform.isEmpty()) {
voice->waveform = _waveform;
voice->wavemax = _wavemax;
}
if (voice->waveform.isEmpty()) {
voice->waveform.resize(1);
voice->waveform[0] = -2;
voice->wavemax = 0;
} else if (voice->waveform[0] < 0) {
voice->waveform[0] = -2;
voice->wavemax = 0;
}
const DocumentItems &items(App::documentItems());
DocumentItems::const_iterator i = items.constFind(_doc);
if (i != items.cend()) {
for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) {
Ui::repaintHistoryItem(j.key());
}
}
}
}
virtual ~CountWaveformTask() {
if (_data.isEmpty() && _doc) {
_loc.accessDisable();
}
}
protected:
DocumentData *_doc;
FileLocation _loc;
QByteArray _data;
VoiceWaveform _waveform;
char _wavemax;
};
void countVoiceWaveform(DocumentData *document) {
if (VoiceData *voice = document->voice()) {
if (_localLoader) {
voice->waveform.resize(1 + sizeof(TaskId));
voice->waveform[0] = -1; // counting
TaskId taskId = _localLoader->addTask(new CountWaveformTask(document));
memcpy(voice->waveform.data() + 1, &taskId, sizeof(taskId));
}
}
}
void cancelTask(TaskId id) {
if (_localLoader) {
_localLoader->cancelTask(id);

View File

@ -144,6 +144,8 @@ namespace Local {
int32 hasWebFiles();
qint64 storageWebFilesSize();
void countVoiceWaveform(DocumentData *document);
void cancelTask(TaskId id);
void writeStickers();

View File

@ -1124,9 +1124,9 @@ bool MainWidget::kickParticipantFail(ChatData *chat, const RPCError &error) {
void MainWidget::checkPeerHistory(PeerData *peer) {
if (peer->isChannel() && !peer->isMegagroup()) {
MTP::send(MTPchannels_GetImportantHistory(peer->asChannel()->inputChannel, MTP_int(0), MTP_int(0), MTP_int(1), MTP_int(0), MTP_int(0)), rpcDone(&MainWidget::checkedHistory, peer));
MTP::send(MTPchannels_GetImportantHistory(peer->asChannel()->inputChannel, MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(1), MTP_int(0), MTP_int(0)), rpcDone(&MainWidget::checkedHistory, peer));
} else {
MTP::send(MTPmessages_GetHistory(peer->input, MTP_int(0), MTP_int(0), MTP_int(1), MTP_int(0), MTP_int(0)), rpcDone(&MainWidget::checkedHistory, peer));
MTP::send(MTPmessages_GetHistory(peer->input, MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(1), MTP_int(0), MTP_int(0)), rpcDone(&MainWidget::checkedHistory, peer));
}
}
@ -1479,9 +1479,9 @@ void MainWidget::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
switch (i) {
case OverviewPhotos: connect(_mediaType.addButton(new IconedButton(this, st::dropdownMediaPhotos, lang(lng_media_type_photos))), SIGNAL(clicked()), this, SLOT(onPhotosSelect())); break;
case OverviewVideos: connect(_mediaType.addButton(new IconedButton(this, st::dropdownMediaVideos, lang(lng_media_type_videos))), SIGNAL(clicked()), this, SLOT(onVideosSelect())); break;
case OverviewAudioDocuments: connect(_mediaType.addButton(new IconedButton(this, st::dropdownMediaSongs, lang(lng_media_type_songs))), SIGNAL(clicked()), this, SLOT(onSongsSelect())); break;
case OverviewDocuments: connect(_mediaType.addButton(new IconedButton(this, st::dropdownMediaDocuments, lang(lng_media_type_files))), SIGNAL(clicked()), this, SLOT(onDocumentsSelect())); break;
case OverviewAudios: connect(_mediaType.addButton(new IconedButton(this, st::dropdownMediaAudios, lang(lng_media_type_audios))), SIGNAL(clicked()), this, SLOT(onAudiosSelect())); break;
case OverviewMusicFiles: connect(_mediaType.addButton(new IconedButton(this, st::dropdownMediaSongs, lang(lng_media_type_songs))), SIGNAL(clicked()), this, SLOT(onSongsSelect())); break;
case OverviewFiles: connect(_mediaType.addButton(new IconedButton(this, st::dropdownMediaDocuments, lang(lng_media_type_files))), SIGNAL(clicked()), this, SLOT(onDocumentsSelect())); break;
case OverviewVoiceFiles: connect(_mediaType.addButton(new IconedButton(this, st::dropdownMediaAudios, lang(lng_media_type_audios))), SIGNAL(clicked()), this, SLOT(onAudiosSelect())); break;
case OverviewLinks: connect(_mediaType.addButton(new IconedButton(this, st::dropdownMediaLinks, lang(lng_media_type_links))), SIGNAL(clicked()), this, SLOT(onLinksSelect())); break;
}
}
@ -1709,24 +1709,6 @@ void MainWidget::videoLoadRetry() {
if (video) video->save(failedFileName);
}
void MainWidget::audioLoadProgress(FileLoader *loader) {
mtpFileLoader *l = loader ? loader->mtpLoader() : 0;
if (!l) return;
AudioData *audio = App::audio(l->objId());
if (audio->loaded()) {
audio->performActionOnLoad();
}
const AudioItems &items(App::audioItems());
AudioItems::const_iterator i = items.constFind(audio);
if (i != items.cend()) {
for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) {
Ui::repaintHistoryItem(j.key());
}
}
}
void MainWidget::audioPlayProgress(const AudioMsgId &audioId) {
AudioMsgId playing;
AudioPlayerState state = AudioPlayerStopped;
@ -1734,7 +1716,7 @@ void MainWidget::audioPlayProgress(const AudioMsgId &audioId) {
if (playing == audioId && state == AudioPlayerStoppedAtStart) {
audioPlayer()->clearStoppedAtStart(audioId);
AudioData *audio = audioId.audio;
DocumentData *audio = audioId.audio;
QString already = audio->already(true);
if (already.isEmpty() && !audio->data().isEmpty()) {
bool mp3 = (audio->mime == qstr("audio/mp3"));
@ -1746,7 +1728,7 @@ void MainWidget::audioPlayProgress(const AudioMsgId &audioId) {
f.close();
already = filename;
audio->setLocation(FileLocation(StorageFilePartial, filename));
Local::writeFileLocation(mediaKey(mtpToLocationType(mtpc_inputAudioFileLocation), audio->dc, audio->id), FileLocation(mtpToStorageType(mtpc_storage_filePartial), filename));
Local::writeFileLocation(mediaKey(AudioFileLocation, audio->dc, audio->id), FileLocation(mtpToStorageType(mtpc_storage_filePartial), filename));
}
}
}
@ -1794,7 +1776,7 @@ void MainWidget::documentPlayProgress(const SongMsgId &songId) {
f.close();
already = filename;
document->setLocation(FileLocation(StorageFilePartial, filename));
Local::writeFileLocation(mediaKey(mtpToLocationType(mtpc_inputDocumentFileLocation), document->dc, document->id), FileLocation(mtpToStorageType(mtpc_storage_filePartial), filename));
Local::writeFileLocation(mediaKey(DocumentFileLocation, document->dc, document->id), FileLocation(mtpToStorageType(mtpc_storage_filePartial), filename));
}
}
}
@ -1831,24 +1813,6 @@ void MainWidget::hidePlayer() {
}
}
void MainWidget::audioLoadFailed(FileLoader *loader, bool started) {
mtpFileLoader *l = loader ? loader->mtpLoader() : 0;
if (!l) return;
loadFailed(l, started, SLOT(audioLoadRetry()));
AudioData *audio = App::audio(l->objId());
if (audio) {
if (audio->loading()) audio->cancel();
audio->status = FileDownloadFailed;
}
}
void MainWidget::audioLoadRetry() {
Ui::hideLayer();
AudioData *audio = App::audio(failedObjId);
if (audio) audio->save(failedFileName);
}
void MainWidget::documentLoadProgress(FileLoader *loader) {
mtpFileLoader *l = loader ? loader->mtpLoader() : 0;
if (!l) return;
@ -1915,9 +1879,9 @@ void MainWidget::inlineResultLoadFailed(FileLoader *loader, bool started) {
//Ui::repaintInlineItem();
}
void MainWidget::audioMarkRead(AudioData *data) {
const AudioItems &items(App::audioItems());
AudioItems::const_iterator i = items.constFind(data);
void MainWidget::audioMarkRead(DocumentData *data) {
const DocumentItems &items(App::documentItems());
DocumentItems::const_iterator i = items.constFind(data);
if (i != items.cend()) {
mediaMarkRead(i.value());
}
@ -2428,7 +2392,7 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool
if (overview && overview->peer() == peer) {
if (overview->type() != type) {
overview->switchType(type);
} else if (type == OverviewAudioDocuments) { // hack for player
} else if (type == OverviewMusicFiles) { // hack for player
showBackFromStack();
}
return;
@ -2872,17 +2836,17 @@ void MainWidget::onVideosSelect() {
}
void MainWidget::onSongsSelect() {
if (overview) overview->switchType(OverviewAudioDocuments);
if (overview) overview->switchType(OverviewMusicFiles);
_mediaType.hideStart();
}
void MainWidget::onDocumentsSelect() {
if (overview) overview->switchType(OverviewDocuments);
if (overview) overview->switchType(OverviewFiles);
_mediaType.hideStart();
}
void MainWidget::onAudiosSelect() {
if (overview) overview->switchType(OverviewAudios);
if (overview) overview->switchType(OverviewVoiceFiles);
_mediaType.hideStart();
}

View File

@ -375,7 +375,7 @@ public:
void cancelForwarding();
void finishForwarding(History *hist, bool broadcast); // send them
void audioMarkRead(AudioData *data);
void audioMarkRead(DocumentData *data);
void videoMarkRead(VideoData *data);
void mediaMarkRead(const HistoryItemsMap &items);
@ -448,9 +448,6 @@ public slots:
void videoLoadProgress(FileLoader *loader);
void videoLoadFailed(FileLoader *loader, bool started);
void videoLoadRetry();
void audioLoadProgress(FileLoader *loader);
void audioLoadFailed(FileLoader *loader, bool started);
void audioLoadRetry();
void audioPlayProgress(const AudioMsgId &audioId);
void documentLoadProgress(FileLoader *loader);
void documentLoadFailed(FileLoader *loader, bool started);

View File

@ -363,7 +363,7 @@ void MediaView::updateControls() {
_dateNav = myrtlrect(st::mvTextLeft, height() - st::mvTextTop, st::mvFont->width(_dateText), st::mvFont->height);
}
updateHeader();
if (_photo || (_history && (_overview == OverviewPhotos || _overview == OverviewDocuments))) {
if (_photo || (_history && (_overview == OverviewPhotos || _overview == OverviewFiles))) {
_leftNavVisible = (_index > 0) || (_index == 0 && (
(!_msgmigrated && _history && _history->overview[_overview].size() < _history->overviewCount(_overview)) ||
(_msgmigrated && _migrated && _migrated->overview[_overview].size() < _migrated->overviewCount(_overview)) ||
@ -865,7 +865,7 @@ void MediaView::showDocument(DocumentData *doc, HistoryItem *context) {
_canForward = _msgid > 0;
_canDelete = context ? context->canDelete() : false;
if (_history) {
_overview = OverviewDocuments;
_overview = OverviewFiles;
findCurrent();
}
displayDocument(doc, context);
@ -1486,7 +1486,7 @@ void MediaView::keyPressEvent(QKeyEvent *e) {
}
void MediaView::moveToNext(int32 delta) {
if (_index < 0 || (_history && _overview != OverviewPhotos && _overview != OverviewDocuments) || (_overview == OverviewCount && !_user)) {
if (_index < 0 || (_history && _overview != OverviewPhotos && _overview != OverviewFiles) || (_overview == OverviewCount && !_user)) {
return;
}
if (_msgmigrated && !_history->overviewLoaded(_overview)) {
@ -1515,7 +1515,7 @@ void MediaView::moveToNext(int32 delta) {
if (HistoryMedia *media = item->getMedia()) {
switch (media->type()) {
case MediaTypePhoto: displayPhoto(static_cast<HistoryPhoto*>(item->getMedia())->photo(), item); preloadData(delta); break;
case MediaTypeDocument:
case MediaTypeFile:
case MediaTypeGif:
case MediaTypeSticker: displayDocument(media->getDocument(), item); preloadData(delta); break;
}
@ -1562,7 +1562,7 @@ void MediaView::preloadData(int32 delta) {
if (HistoryMedia *media = item->getMedia()) {
switch (media->type()) {
case MediaTypePhoto: static_cast<HistoryPhoto*>(media)->photo()->forget(); break;
case MediaTypeDocument:
case MediaTypeFile:
case MediaTypeGif:
case MediaTypeSticker: media->getDocument()->forget(); break;
}
@ -1587,7 +1587,7 @@ void MediaView::preloadData(int32 delta) {
if (HistoryMedia *media = item->getMedia()) {
switch (media->type()) {
case MediaTypePhoto: static_cast<HistoryPhoto*>(media)->photo()->download(); break;
case MediaTypeDocument:
case MediaTypeFile:
case MediaTypeGif: {
DocumentData *doc = media->getDocument();
doc->thumb->load();

View File

@ -368,7 +368,7 @@ static const mtpTypeId mtpLayers[] = {
mtpTypeId(mtpc_invokeWithLayer18),
};
static const uint32 mtpLayerMaxSingle = sizeof(mtpLayers) / sizeof(mtpLayers[0]);
static const mtpPrime mtpCurrentLayer = 45;
static const mtpPrime mtpCurrentLayer = 46;
template <typename bareT>
class MTPBoxed : public bareT {

View File

@ -388,7 +388,7 @@ bool mtpFileLoader::loadPart() {
} else {
switch (_locationType) {
case VideoFileLocation: loc = MTP_inputVideoFileLocation(MTP_long(_id), MTP_long(_access)); break;
case AudioFileLocation: loc = MTP_inputAudioFileLocation(MTP_long(_id), MTP_long(_access)); break;
case AudioFileLocation: loc = MTP_inputDocumentFileLocation(MTP_long(_id), MTP_long(_access)); break;
case DocumentFileLocation: loc = MTP_inputDocumentFileLocation(MTP_long(_id), MTP_long(_access)); break;
default: cancel(true); return false; break;
}

View File

@ -30,23 +30,6 @@ enum LocationType {
AudioFileLocation = 0x74dc404d, // mtpc_inputAudioFileLocation
VideoFileLocation = 0x3d0364ec, // mtpc_inputVideoFileLocation
};
inline LocationType mtpToLocationType(mtpTypeId type) {
switch (type) {
case mtpc_inputDocumentFileLocation: return DocumentFileLocation;
case mtpc_inputAudioFileLocation: return AudioFileLocation;
case mtpc_inputVideoFileLocation: return VideoFileLocation;
default: return UnknownFileLocation;
}
}
inline mtpTypeId mtpFromLocationType(LocationType type) {
switch (type) {
case DocumentFileLocation: return mtpc_inputDocumentFileLocation;
case AudioFileLocation: return mtpc_inputAudioFileLocation;
case VideoFileLocation: return mtpc_inputVideoFileLocation;
case UnknownFileLocation:
default: return 0;
}
}
enum StorageFileType {
StorageFileUnknown = 0xaa963b05, // mtpc_storage_fileUnknown

View File

@ -693,34 +693,6 @@ void _serialize_inputMediaVideo(MTPStringLogger &to, int32 stage, int32 lev, Typ
}
}
void _serialize_inputMediaUploadedAudio(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ inputMediaUploadedAudio");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" file: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" duration: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" mime_type: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
}
void _serialize_inputMediaAudio(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ inputMediaAudio");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
}
void _serialize_inputMediaUploadedDocument(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
@ -928,20 +900,6 @@ void _serialize_inputEncryptedFileLocation(MTPStringLogger &to, int32 stage, int
}
}
void _serialize_inputAudioFileLocation(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ inputAudioFileLocation");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" id: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" access_hash: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
}
void _serialize_inputDocumentFileLocation(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
@ -1279,14 +1237,15 @@ void _serialize_channel(MTPStringLogger &to, int32 stage, int32 lev, Types &type
case 7: to.add(" verified: "); ++stages.back(); if (flag & MTPDchannel::flag_verified) { to.add("YES [ BY BIT 7 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 7 IN FIELD flags ]"); } break;
case 8: to.add(" megagroup: "); ++stages.back(); if (flag & MTPDchannel::flag_megagroup) { to.add("YES [ BY BIT 8 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 8 IN FIELD flags ]"); } break;
case 9: to.add(" restricted: "); ++stages.back(); if (flag & MTPDchannel::flag_restricted) { to.add("YES [ BY BIT 9 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 9 IN FIELD flags ]"); } break;
case 10: to.add(" id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 11: to.add(" access_hash: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 12: to.add(" title: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 13: to.add(" username: "); ++stages.back(); if (flag & MTPDchannel::flag_username) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 6 IN FIELD flags ]"); } break;
case 14: to.add(" photo: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 15: to.add(" date: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 16: to.add(" version: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 17: to.add(" restriction_reason: "); ++stages.back(); if (flag & MTPDchannel::flag_restriction_reason) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 9 IN FIELD flags ]"); } break;
case 10: to.add(" invites_enabled: "); ++stages.back(); if (flag & MTPDchannel::flag_invites_enabled) { to.add("YES [ BY BIT 10 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 10 IN FIELD flags ]"); } break;
case 11: to.add(" id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 12: to.add(" access_hash: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 13: to.add(" title: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 14: to.add(" username: "); ++stages.back(); if (flag & MTPDchannel::flag_username) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 6 IN FIELD flags ]"); } break;
case 15: to.add(" photo: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 16: to.add(" date: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 17: to.add(" version: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 18: to.add(" restriction_reason: "); ++stages.back(); if (flag & MTPDchannel::flag_restriction_reason) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 9 IN FIELD flags ]"); } break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
}
@ -1587,19 +1546,6 @@ void _serialize_messageMediaDocument(MTPStringLogger &to, int32 stage, int32 lev
}
}
void _serialize_messageMediaAudio(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ messageMediaAudio");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" audio: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
}
void _serialize_messageMediaWebPage(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
@ -2189,20 +2135,6 @@ void _serialize_contactBlocked(MTPStringLogger &to, int32 stage, int32 lev, Type
}
}
void _serialize_contactSuggested(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ contactSuggested");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" user_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" mutual_contacts: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
}
void _serialize_contactStatus(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
@ -2294,20 +2226,6 @@ void _serialize_contacts_blockedSlice(MTPStringLogger &to, int32 stage, int32 le
}
}
void _serialize_contacts_suggested(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ contacts_suggested");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" results: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" users: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
}
void _serialize_messages_dialogs(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
@ -2458,14 +2376,6 @@ void _serialize_inputMessagesFilterDocument(MTPStringLogger &to, int32 stage, in
to.add("{ inputMessagesFilterDocument }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
}
void _serialize_inputMessagesFilterAudio(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
to.add("{ inputMessagesFilterAudio }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
}
void _serialize_inputMessagesFilterAudioDocuments(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
to.add("{ inputMessagesFilterAudioDocuments }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
}
void _serialize_inputMessagesFilterUrl(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
to.add("{ inputMessagesFilterUrl }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
}
@ -2474,6 +2384,14 @@ void _serialize_inputMessagesFilterGif(MTPStringLogger &to, int32 stage, int32 l
to.add("{ inputMessagesFilterGif }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
}
void _serialize_inputMessagesFilterVoice(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
to.add("{ inputMessagesFilterVoice }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
}
void _serialize_inputMessagesFilterMusic(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
to.add("{ inputMessagesFilterMusic }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
}
void _serialize_updateNewMessage(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
@ -3067,6 +2985,21 @@ void _serialize_updateBotInlineQuery(MTPStringLogger &to, int32 stage, int32 lev
}
}
void _serialize_updateBotInlineSend(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ updateBotInlineSend");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" user_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" query: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" id: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
}
void _serialize_updates_state(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
@ -3673,24 +3606,6 @@ void _serialize_messages_sentEncryptedFile(MTPStringLogger &to, int32 stage, int
}
}
void _serialize_inputAudioEmpty(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
to.add("{ inputAudioEmpty }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
}
void _serialize_inputAudio(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ inputAudio");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" id: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" access_hash: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
}
void _serialize_inputDocumentEmpty(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
to.add("{ inputDocumentEmpty }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
}
@ -3709,38 +3624,6 @@ void _serialize_inputDocument(MTPStringLogger &to, int32 stage, int32 lev, Types
}
}
void _serialize_audioEmpty(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ audioEmpty");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" id: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
}
void _serialize_audio(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ audio");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" id: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" access_hash: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" date: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 3: to.add(" duration: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 4: to.add(" mime_type: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 5: to.add(" size: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 6: to.add(" dc_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
}
void _serialize_documentEmpty(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
@ -3908,10 +3791,18 @@ void _serialize_inputPrivacyKeyStatusTimestamp(MTPStringLogger &to, int32 stage,
to.add("{ inputPrivacyKeyStatusTimestamp }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
}
void _serialize_inputPrivacyKeyChatInvite(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
to.add("{ inputPrivacyKeyChatInvite }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
}
void _serialize_privacyKeyStatusTimestamp(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
to.add("{ privacyKeyStatusTimestamp }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
}
void _serialize_privacyKeyChatInvite(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
to.add("{ privacyKeyChatInvite }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
}
void _serialize_inputPrivacyValueAllowContacts(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
to.add("{ inputPrivacyValueAllowContacts }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
}
@ -4092,9 +3983,12 @@ void _serialize_documentAttributeAudio(MTPStringLogger &to, int32 stage, int32 l
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" duration: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" title: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" performer: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" voice: "); ++stages.back(); if (flag & MTPDdocumentAttributeAudio::flag_voice) { to.add("YES [ BY BIT 10 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 10 IN FIELD flags ]"); } break;
case 2: to.add(" duration: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 3: to.add(" title: "); ++stages.back(); if (flag & MTPDdocumentAttributeAudio::flag_title) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
case 4: to.add(" performer: "); ++stages.back(); if (flag & MTPDdocumentAttributeAudio::flag_performer) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break;
case 5: to.add(" waveform: "); ++stages.back(); if (flag & MTPDdocumentAttributeAudio::flag_waveform) { types.push_back(mtpc_bytes); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
}
@ -6373,19 +6267,6 @@ void _serialize_contacts_importContacts(MTPStringLogger &to, int32 stage, int32
}
}
void _serialize_contacts_getSuggested(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ contacts_getSuggested");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" limit: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
}
void _serialize_contacts_deleteContact(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
@ -6482,10 +6363,11 @@ void _serialize_messages_getHistory(MTPStringLogger &to, int32 stage, int32 lev,
switch (stage) {
case 0: to.add(" peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" offset_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" add_offset: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 3: to.add(" limit: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 4: to.add(" max_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 5: to.add(" min_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" offset_date: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 3: to.add(" add_offset: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 4: to.add(" limit: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 5: to.add(" max_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 6: to.add(" min_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
}
@ -6539,10 +6421,11 @@ void _serialize_channels_getImportantHistory(MTPStringLogger &to, int32 stage, i
switch (stage) {
case 0: to.add(" channel: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" offset_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" add_offset: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 3: to.add(" limit: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 4: to.add(" max_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 5: to.add(" min_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 2: to.add(" offset_date: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 3: to.add(" add_offset: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 4: to.add(" limit: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 5: to.add(" max_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 6: to.add(" min_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
}
@ -7063,6 +6946,20 @@ void _serialize_channels_deleteChannel(MTPStringLogger &to, int32 stage, int32 l
}
}
void _serialize_channels_toggleInvites(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
} else {
to.add("{ channels_toggleInvites");
to.add("\n").addSpaces(lev);
}
switch (stage) {
case 0: to.add(" channel: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
case 1: to.add(" enabled: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
}
}
void _serialize_messages_getChats(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
if (stage) {
to.add(",\n").addSpaces(lev);
@ -7678,8 +7575,6 @@ namespace {
_serializers.insert(mtpc_inputMediaUploadedVideo, _serialize_inputMediaUploadedVideo);
_serializers.insert(mtpc_inputMediaUploadedThumbVideo, _serialize_inputMediaUploadedThumbVideo);
_serializers.insert(mtpc_inputMediaVideo, _serialize_inputMediaVideo);
_serializers.insert(mtpc_inputMediaUploadedAudio, _serialize_inputMediaUploadedAudio);
_serializers.insert(mtpc_inputMediaAudio, _serialize_inputMediaAudio);
_serializers.insert(mtpc_inputMediaUploadedDocument, _serialize_inputMediaUploadedDocument);
_serializers.insert(mtpc_inputMediaUploadedThumbDocument, _serialize_inputMediaUploadedThumbDocument);
_serializers.insert(mtpc_inputMediaDocument, _serialize_inputMediaDocument);
@ -7697,7 +7592,6 @@ namespace {
_serializers.insert(mtpc_inputFileLocation, _serialize_inputFileLocation);
_serializers.insert(mtpc_inputVideoFileLocation, _serialize_inputVideoFileLocation);
_serializers.insert(mtpc_inputEncryptedFileLocation, _serialize_inputEncryptedFileLocation);
_serializers.insert(mtpc_inputAudioFileLocation, _serialize_inputAudioFileLocation);
_serializers.insert(mtpc_inputDocumentFileLocation, _serialize_inputDocumentFileLocation);
_serializers.insert(mtpc_inputPhotoCropAuto, _serialize_inputPhotoCropAuto);
_serializers.insert(mtpc_inputPhotoCrop, _serialize_inputPhotoCrop);
@ -7751,7 +7645,6 @@ namespace {
_serializers.insert(mtpc_messageMediaContact, _serialize_messageMediaContact);
_serializers.insert(mtpc_messageMediaUnsupported, _serialize_messageMediaUnsupported);
_serializers.insert(mtpc_messageMediaDocument, _serialize_messageMediaDocument);
_serializers.insert(mtpc_messageMediaAudio, _serialize_messageMediaAudio);
_serializers.insert(mtpc_messageMediaWebPage, _serialize_messageMediaWebPage);
_serializers.insert(mtpc_messageMediaVenue, _serialize_messageMediaVenue);
_serializers.insert(mtpc_messageActionEmpty, _serialize_messageActionEmpty);
@ -7802,7 +7695,6 @@ namespace {
_serializers.insert(mtpc_contact, _serialize_contact);
_serializers.insert(mtpc_importedContact, _serialize_importedContact);
_serializers.insert(mtpc_contactBlocked, _serialize_contactBlocked);
_serializers.insert(mtpc_contactSuggested, _serialize_contactSuggested);
_serializers.insert(mtpc_contactStatus, _serialize_contactStatus);
_serializers.insert(mtpc_contacts_link, _serialize_contacts_link);
_serializers.insert(mtpc_contacts_contactsNotModified, _serialize_contacts_contactsNotModified);
@ -7810,7 +7702,6 @@ namespace {
_serializers.insert(mtpc_contacts_importedContacts, _serialize_contacts_importedContacts);
_serializers.insert(mtpc_contacts_blocked, _serialize_contacts_blocked);
_serializers.insert(mtpc_contacts_blockedSlice, _serialize_contacts_blockedSlice);
_serializers.insert(mtpc_contacts_suggested, _serialize_contacts_suggested);
_serializers.insert(mtpc_messages_dialogs, _serialize_messages_dialogs);
_serializers.insert(mtpc_messages_dialogsSlice, _serialize_messages_dialogsSlice);
_serializers.insert(mtpc_messages_messages, _serialize_messages_messages);
@ -7825,10 +7716,10 @@ namespace {
_serializers.insert(mtpc_inputMessagesFilterPhotoVideo, _serialize_inputMessagesFilterPhotoVideo);
_serializers.insert(mtpc_inputMessagesFilterPhotoVideoDocuments, _serialize_inputMessagesFilterPhotoVideoDocuments);
_serializers.insert(mtpc_inputMessagesFilterDocument, _serialize_inputMessagesFilterDocument);
_serializers.insert(mtpc_inputMessagesFilterAudio, _serialize_inputMessagesFilterAudio);
_serializers.insert(mtpc_inputMessagesFilterAudioDocuments, _serialize_inputMessagesFilterAudioDocuments);
_serializers.insert(mtpc_inputMessagesFilterUrl, _serialize_inputMessagesFilterUrl);
_serializers.insert(mtpc_inputMessagesFilterGif, _serialize_inputMessagesFilterGif);
_serializers.insert(mtpc_inputMessagesFilterVoice, _serialize_inputMessagesFilterVoice);
_serializers.insert(mtpc_inputMessagesFilterMusic, _serialize_inputMessagesFilterMusic);
_serializers.insert(mtpc_updateNewMessage, _serialize_updateNewMessage);
_serializers.insert(mtpc_updateMessageID, _serialize_updateMessageID);
_serializers.insert(mtpc_updateDeleteMessages, _serialize_updateDeleteMessages);
@ -7871,6 +7762,7 @@ namespace {
_serializers.insert(mtpc_updateStickerSets, _serialize_updateStickerSets);
_serializers.insert(mtpc_updateSavedGifs, _serialize_updateSavedGifs);
_serializers.insert(mtpc_updateBotInlineQuery, _serialize_updateBotInlineQuery);
_serializers.insert(mtpc_updateBotInlineSend, _serialize_updateBotInlineSend);
_serializers.insert(mtpc_updates_state, _serialize_updates_state);
_serializers.insert(mtpc_updates_differenceEmpty, _serialize_updates_differenceEmpty);
_serializers.insert(mtpc_updates_difference, _serialize_updates_difference);
@ -7910,12 +7802,8 @@ namespace {
_serializers.insert(mtpc_messages_dhConfig, _serialize_messages_dhConfig);
_serializers.insert(mtpc_messages_sentEncryptedMessage, _serialize_messages_sentEncryptedMessage);
_serializers.insert(mtpc_messages_sentEncryptedFile, _serialize_messages_sentEncryptedFile);
_serializers.insert(mtpc_inputAudioEmpty, _serialize_inputAudioEmpty);
_serializers.insert(mtpc_inputAudio, _serialize_inputAudio);
_serializers.insert(mtpc_inputDocumentEmpty, _serialize_inputDocumentEmpty);
_serializers.insert(mtpc_inputDocument, _serialize_inputDocument);
_serializers.insert(mtpc_audioEmpty, _serialize_audioEmpty);
_serializers.insert(mtpc_audio, _serialize_audio);
_serializers.insert(mtpc_documentEmpty, _serialize_documentEmpty);
_serializers.insert(mtpc_document, _serialize_document);
_serializers.insert(mtpc_help_support, _serialize_help_support);
@ -7935,7 +7823,9 @@ namespace {
_serializers.insert(mtpc_sendMessageChooseContactAction, _serialize_sendMessageChooseContactAction);
_serializers.insert(mtpc_contacts_found, _serialize_contacts_found);
_serializers.insert(mtpc_inputPrivacyKeyStatusTimestamp, _serialize_inputPrivacyKeyStatusTimestamp);
_serializers.insert(mtpc_inputPrivacyKeyChatInvite, _serialize_inputPrivacyKeyChatInvite);
_serializers.insert(mtpc_privacyKeyStatusTimestamp, _serialize_privacyKeyStatusTimestamp);
_serializers.insert(mtpc_privacyKeyChatInvite, _serialize_privacyKeyChatInvite);
_serializers.insert(mtpc_inputPrivacyValueAllowContacts, _serialize_inputPrivacyValueAllowContacts);
_serializers.insert(mtpc_inputPrivacyValueAllowAll, _serialize_inputPrivacyValueAllowAll);
_serializers.insert(mtpc_inputPrivacyValueAllowUsers, _serialize_inputPrivacyValueAllowUsers);
@ -8133,7 +8023,6 @@ namespace {
_serializers.insert(mtpc_contacts_getStatuses, _serialize_contacts_getStatuses);
_serializers.insert(mtpc_contacts_getContacts, _serialize_contacts_getContacts);
_serializers.insert(mtpc_contacts_importContacts, _serialize_contacts_importContacts);
_serializers.insert(mtpc_contacts_getSuggested, _serialize_contacts_getSuggested);
_serializers.insert(mtpc_contacts_deleteContact, _serialize_contacts_deleteContact);
_serializers.insert(mtpc_contacts_getBlocked, _serialize_contacts_getBlocked);
_serializers.insert(mtpc_contacts_exportCard, _serialize_contacts_exportCard);
@ -8180,6 +8069,7 @@ namespace {
_serializers.insert(mtpc_channels_inviteToChannel, _serialize_channels_inviteToChannel);
_serializers.insert(mtpc_channels_kickFromChannel, _serialize_channels_kickFromChannel);
_serializers.insert(mtpc_channels_deleteChannel, _serialize_channels_deleteChannel);
_serializers.insert(mtpc_channels_toggleInvites, _serialize_channels_toggleInvites);
_serializers.insert(mtpc_messages_getChats, _serialize_messages_getChats);
_serializers.insert(mtpc_channels_getChannels, _serialize_channels_getChannels);
_serializers.insert(mtpc_messages_getFullChat, _serialize_messages_getFullChat);

File diff suppressed because it is too large Load Diff

View File

@ -153,8 +153,6 @@ inputMediaContact#a6e45987 phone_number:string first_name:string last_name:strin
inputMediaUploadedVideo#82713fdf file:InputFile duration:int w:int h:int mime_type:string caption:string = InputMedia;
inputMediaUploadedThumbVideo#7780ddf9 file:InputFile thumb:InputFile duration:int w:int h:int mime_type:string caption:string = InputMedia;
inputMediaVideo#936a4ebd id:InputVideo caption:string = InputMedia;
inputMediaUploadedAudio#4e498cab file:InputFile duration:int mime_type:string = InputMedia;
inputMediaAudio#89938781 id:InputAudio = InputMedia;
inputMediaUploadedDocument#1d89306d file:InputFile mime_type:string attributes:Vector<DocumentAttribute> caption:string = InputMedia;
inputMediaUploadedThumbDocument#ad613491 file:InputFile thumb:InputFile mime_type:string attributes:Vector<DocumentAttribute> caption:string = InputMedia;
inputMediaDocument#1a77f29c id:InputDocument caption:string = InputMedia;
@ -177,7 +175,6 @@ inputVideo#ee579652 id:long access_hash:long = InputVideo;
inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation;
inputVideoFileLocation#3d0364ec id:long access_hash:long = InputFileLocation;
inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation;
inputAudioFileLocation#74dc404d id:long access_hash:long = InputFileLocation;
inputDocumentFileLocation#4e45abe9 id:long access_hash:long = InputFileLocation;
inputPhotoCropAuto#ade6b004 = InputPhotoCrop;
@ -219,7 +216,7 @@ userStatusLastMonth#77ebc742 = UserStatus;
chatEmpty#9ba2d800 id:int = Chat;
chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat;
chatForbidden#7328bdb id:int title:string = Chat;
channel#4b1b7506 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true editor:flags.3?true moderator:flags.4?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true id:int access_hash:long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string = Chat;
channel#4b1b7506 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true editor:flags.3?true moderator:flags.4?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true invites_enabled:flags.10?true id:int access_hash:long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string = Chat;
channelForbidden#2d85832c id:int access_hash:long title:string = Chat;
chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> = ChatFull;
@ -246,7 +243,6 @@ messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia;
messageMediaContact#5e7d2f39 phone_number:string first_name:string last_name:string user_id:int = MessageMedia;
messageMediaUnsupported#9f84f49e = MessageMedia;
messageMediaDocument#f3e02ea8 document:Document caption:string = MessageMedia;
messageMediaAudio#c6b68300 audio:Audio = MessageMedia;
messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia;
messageMediaVenue#7912b71f geo:GeoPoint title:string address:string provider:string venue_id:string = MessageMedia;
@ -319,8 +315,6 @@ importedContact#d0028438 user_id:int client_id:long = ImportedContact;
contactBlocked#561bc879 user_id:int date:int = ContactBlocked;
contactSuggested#3de191a1 user_id:int mutual_contacts:int = ContactSuggested;
contactStatus#d3680c61 user_id:int status:UserStatus = ContactStatus;
contacts.link#3ace484c my_link:ContactLink foreign_link:ContactLink user:User = contacts.Link;
@ -333,8 +327,6 @@ contacts.importedContacts#ad524315 imported:Vector<ImportedContact> retry_contac
contacts.blocked#1c138d15 blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked;
contacts.blockedSlice#900802a1 count:int blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked;
contacts.suggested#5649dcc5 results:Vector<ContactSuggested> users:Vector<User> = contacts.Suggested;
messages.dialogs#15ba6c40 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
@ -354,10 +346,10 @@ inputMessagesFilterVideo#9fc00e65 = MessagesFilter;
inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter;
inputMessagesFilterPhotoVideoDocuments#d95e73bb = MessagesFilter;
inputMessagesFilterDocument#9eddf188 = MessagesFilter;
inputMessagesFilterAudio#cfc87522 = MessagesFilter;
inputMessagesFilterAudioDocuments#5afbf764 = MessagesFilter;
inputMessagesFilterUrl#7ef0dd87 = MessagesFilter;
inputMessagesFilterGif#ffc86587 = MessagesFilter;
inputMessagesFilterVoice#50f5c392 = MessagesFilter;
inputMessagesFilterMusic#3751b49e = MessagesFilter;
updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update;
updateMessageID#4e90bfd6 id:int random_id:long = Update;
@ -401,6 +393,7 @@ updateStickerSetsOrder#f0dfb451 order:Vector<long> = Update;
updateStickerSets#43ae3dec = Update;
updateSavedGifs#9375341e = Update;
updateBotInlineQuery#c01eea08 query_id:long user_id:int query:string offset:string = Update;
updateBotInlineSend#f69e113 user_id:int query:string id:string = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@ -459,15 +452,9 @@ messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhC
messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage;
messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage;
inputAudioEmpty#d95adc84 = InputAudio;
inputAudio#77d440ff id:long access_hash:long = InputAudio;
inputDocumentEmpty#72f0eaae = InputDocument;
inputDocument#18798952 id:long access_hash:long = InputDocument;
audioEmpty#586988d8 id:long = Audio;
audio#f9e35055 id:long access_hash:long date:int duration:int mime_type:string size:int dc_id:int = Audio;
documentEmpty#36f8c871 id:long = Document;
document#f9a39f4f id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int attributes:Vector<DocumentAttribute> = Document;
@ -492,8 +479,10 @@ sendMessageChooseContactAction#628cbc6f = SendMessageAction;
contacts.found#1aa1f784 results:Vector<Peer> chats:Vector<Chat> users:Vector<User> = contacts.Found;
inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey;
inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey;
privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey;
privacyKeyChatInvite#500e6dfa = PrivacyKey;
inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule;
inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule;
@ -519,7 +508,7 @@ documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute;
documentAttributeAnimated#11b58939 = DocumentAttribute;
documentAttributeSticker#3a556302 alt:string stickerset:InputStickerSet = DocumentAttribute;
documentAttributeVideo#5910cccb duration:int w:int h:int = DocumentAttribute;
documentAttributeAudio#ded218e0 duration:int title:string performer:string = DocumentAttribute;
documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute;
documentAttributeFilename#15590068 file_name:string = DocumentAttribute;
messages.stickersNotModified#f1749a22 = messages.Stickers;
@ -552,7 +541,7 @@ account.password#7c18141c current_salt:bytes new_salt:bytes hint:string has_reco
account.passwordSettings#b7b72ab3 email:string = account.PasswordSettings;
account.passwordInputSettings#bcfc532c flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string = account.PasswordInputSettings;
account.passwordInputSettings#86916deb flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string = account.PasswordInputSettings;
auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery;
@ -717,7 +706,6 @@ users.getFullUser#ca30a5b1 id:InputUser = UserFull;
contacts.getStatuses#c4a353ee = Vector<ContactStatus>;
contacts.getContacts#22c6aa08 hash:string = contacts.Contacts;
contacts.importContacts#da30b32d contacts:Vector<InputContact> replace:Bool = contacts.ImportedContacts;
contacts.getSuggested#cd773428 limit:int = contacts.Suggested;
contacts.deleteContact#8e953744 id:InputUser = contacts.Link;
contacts.deleteContacts#59ab389e id:Vector<InputUser> = Bool;
contacts.block#332b49fc id:InputUser = Bool;
@ -730,7 +718,7 @@ contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer;
messages.getMessages#4222fa74 id:Vector<int> = messages.Messages;
messages.getDialogs#6b47f94d offset_date:int offset_id:int offset_peer:InputPeer limit:int = messages.Dialogs;
messages.getHistory#8a8ec2da peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
messages.getHistory#afa92846 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
messages.search#d4569248 flags:# important_only:flags.0?true peer:InputPeer q:string filter:MessagesFilter min_date:int max_date:int offset:int max_id:int limit:int = messages.Messages;
messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages;
messages.deleteHistory#b7c13bd9 peer:InputPeer max_id:int = messages.AffectedHistory;
@ -808,7 +796,7 @@ help.getAppChangelog#5bab7fb2 device_model:string system_version:string app_vers
help.getTermsOfService#37d78f83 lang_code:string = help.TermsOfService;
channels.getDialogs#a9d3d249 offset:int limit:int = messages.Dialogs;
channels.getImportantHistory#ddb929cb channel:InputChannel offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
channels.getImportantHistory#8f494bb2 channel:InputChannel offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool;
channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages;
channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory;
@ -832,3 +820,4 @@ channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector<InputUser> =
channels.kickFromChannel#a672de14 channel:InputChannel user_id:InputUser kicked:Bool = Updates;
channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite;
channels.deleteChannel#c0111fe3 channel:InputChannel = Updates;
channels.toggleInvites#49609307 channel:InputChannel enabled:Bool = Updates;

View File

@ -39,7 +39,7 @@ OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, PeerD
, _resizeSkip(0)
, _peer(peer->migrateTo() ? peer->migrateTo() : peer)
, _type(type)
, _reversed(_type != OverviewDocuments && _type != OverviewLinks)
, _reversed(_type != OverviewFiles && _type != OverviewLinks)
, _migrated(_peer->migrateFrom() ? App::history(_peer->migrateFrom()->id) : 0)
, _history(App::history(_peer->id))
, _channel(peerToChannel(_peer->id))
@ -108,7 +108,7 @@ OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, PeerD
connect(&_searchTimer, SIGNAL(timeout()), this, SLOT(onSearchMessages()));
_cancelSearch.hide();
if (_type == OverviewLinks || _type == OverviewDocuments) {
if (_type == OverviewLinks || _type == OverviewFiles) {
_search.show();
} else {
_search.hide();
@ -735,7 +735,7 @@ QPoint OverviewInner::mapMouseToItem(QPoint p, MsgId itemId, int32 itemIndex) {
}
void OverviewInner::activate() {
if (_type == OverviewLinks || _type == OverviewDocuments) {
if (_type == OverviewLinks || _type == OverviewFiles) {
_search.setFocus();
} else {
setFocus();
@ -759,7 +759,7 @@ void OverviewInner::clear() {
}
int32 OverviewInner::itemTop(const FullMsgId &msgId) const {
if (_type == OverviewAudioDocuments) {
if (_type == OverviewMusicFiles) {
int32 itemIndex = -1;
fixItemIndex(itemIndex, (msgId.channel == _channel) ? msgId.msg : ((_migrated && msgId.channel == _migrated->channelId()) ? -msgId.msg : 0));
if (itemIndex >= 0) {
@ -1261,9 +1261,9 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
_contextMenuLnk = textlnkOver();
PhotoLink *lnkPhoto = dynamic_cast<PhotoLink*>(_contextMenuLnk.data());
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data());
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data());
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
if (lnkPhoto || lnkVideo || lnkAudio || lnkDocument) {
bool lnkIsAudio = lnkDocument ? lnkDocument->document()->voice() : false;
if (lnkPhoto || lnkVideo || lnkDocument) {
_menu = new PopupMenu();
if (App::hoveredLinkItem()) {
_menu->addAction(lang(lng_context_to_msg), this, SLOT(goToMessage()))->setEnabled(true);
@ -1271,14 +1271,14 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
if (lnkPhoto) {
_menu->addAction(lang(lng_context_open_image), this, SLOT(openContextUrl()))->setEnabled(true);
} else {
if ((lnkVideo && lnkVideo->video()->loading()) || (lnkAudio && lnkAudio->audio()->loading()) || (lnkDocument && lnkDocument->document()->loading())) {
if ((lnkVideo && lnkVideo->video()->loading()) || (lnkDocument && lnkDocument->document()->loading())) {
_menu->addAction(lang(lng_context_cancel_download), this, SLOT(cancelContextDownload()))->setEnabled(true);
} else {
if ((lnkVideo && !lnkVideo->video()->already(true).isEmpty()) || (lnkAudio && !lnkAudio->audio()->already(true).isEmpty()) || (lnkDocument && !lnkDocument->document()->already(true).isEmpty())) {
if ((lnkVideo && !lnkVideo->video()->already(true).isEmpty()) || (lnkDocument && !lnkDocument->document()->already(true).isEmpty())) {
_menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), this, SLOT(showContextInFolder()))->setEnabled(true);
}
_menu->addAction(lang(lnkVideo ? lng_context_open_video : (lnkAudio ? lng_context_open_audio : lng_context_open_file)), this, SLOT(openContextFile()))->setEnabled(true);
_menu->addAction(lang(lnkVideo ? lng_context_save_video : (lnkAudio ? lng_context_save_audio : lng_context_save_file)), this, SLOT(saveContextFile()))->setEnabled(true);
_menu->addAction(lang(lnkVideo ? lng_context_open_video : (lnkIsAudio ? lng_context_open_audio : lng_context_open_file)), this, SLOT(openContextFile()))->setEnabled(true);
_menu->addAction(lang(lnkVideo ? lng_context_save_video : (lnkIsAudio ? lng_context_save_audio : lng_context_save_file)), this, SLOT(saveContextFile()))->setEnabled(true);
}
}
if (isUponSelected > 1) {
@ -1420,8 +1420,8 @@ void OverviewInner::switchType(MediaOverviewType type) {
if (_type != type) {
clear();
_type = type;
_reversed = (_type != OverviewLinks && _type != OverviewDocuments);
if (_type == OverviewLinks || _type == OverviewDocuments) {
_reversed = (_type != OverviewLinks && _type != OverviewFiles);
if (_type == OverviewLinks || _type == OverviewFiles) {
_search.show();
} else {
_search.hide();
@ -1502,12 +1502,9 @@ void OverviewInner::selectMessage() {
void OverviewInner::cancelContextDownload() {
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data());
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data());
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
if (lnkVideo) {
lnkVideo->video()->cancel();
} else if (lnkAudio) {
lnkAudio->audio()->cancel();
} else if (lnkDocument) {
lnkDocument->document()->cancel();
}
@ -1515,18 +1512,15 @@ void OverviewInner::cancelContextDownload() {
void OverviewInner::showContextInFolder() {
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data());
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data());
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
QString already = lnkVideo ? lnkVideo->video()->already(true) : (lnkAudio ? lnkAudio->audio()->already(true) : (lnkDocument ? lnkDocument->document()->already(true) : QString()));
QString already = lnkVideo ? lnkVideo->video()->already(true) : (lnkDocument ? lnkDocument->document()->already(true) : QString());
if (!already.isEmpty()) psShowInFolder(already);
}
void OverviewInner::saveContextFile() {
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data());
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data());
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
if (lnkVideo) VideoSaveLink::doSave(lnkVideo->video(), true);
if (lnkAudio) AudioSaveLink::doSave(lnkAudio->audio(), true);
if (lnkDocument) DocumentSaveLink::doSave(lnkDocument->document(), true);
}
@ -1534,10 +1528,8 @@ void OverviewInner::openContextFile() {
HistoryItem *was = App::hoveredLinkItem();
App::hoveredLinkItem(App::contextItem());
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data());
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data());
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
if (lnkVideo) VideoOpenLink(lnkVideo->video()).onClick(Qt::LeftButton);
if (lnkAudio) AudioOpenLink(lnkAudio->audio()).onClick(Qt::LeftButton);
if (lnkDocument) DocumentOpenLink(lnkDocument->document()).onClick(Qt::LeftButton);
App::hoveredLinkItem(was);
}
@ -1581,7 +1573,7 @@ void OverviewInner::onNeedSearchMessages() {
}
void OverviewInner::onSearchUpdate() {
QString filterText = (_type == OverviewLinks || _type == OverviewDocuments) ? _search.text().trimmed() : QString();
QString filterText = (_type == OverviewLinks || _type == OverviewFiles) ? _search.text().trimmed() : QString();
bool inSearch = !filterText.isEmpty(), changed = (inSearch != _inSearch);
_inSearch = inSearch;
@ -1729,7 +1721,7 @@ void OverviewInner::mediaOverviewUpdated() {
_height = countHeight();
} else {
bool dateEveryMonth = (_type == OverviewDocuments), dateEveryDay = (_type == OverviewLinks);
bool dateEveryMonth = (_type == OverviewFiles), dateEveryDay = (_type == OverviewLinks);
bool withDates = (dateEveryMonth || dateEveryDay);
History::MediaOverview &o(_history->overview[_type]), *migratedOverview = _migrated ? &_migrated->overview[_type] : 0;
@ -1793,7 +1785,7 @@ void OverviewInner::mediaOverviewUpdated() {
int32 newHeight = _marginTop + _height + _marginBottom, deltaHeight = newHeight - height();
if (deltaHeight) {
resize(_width, newHeight);
if (_type != OverviewLinks && _type != OverviewDocuments) {
if (_type != OverviewLinks && _type != OverviewFiles) {
_overview->scrollBy(deltaHeight);
}
} else {
@ -1909,10 +1901,10 @@ void OverviewInner::recountMargins() {
if (_type == OverviewPhotos || _type == OverviewVideos) {
_marginBottom = 0;
_marginTop = qMax(_minHeight - _height - _marginBottom, 0);
} else if (_type == OverviewAudioDocuments) {
} else if (_type == OverviewMusicFiles) {
_marginTop = st::playlistPadding;
_marginBottom = qMax(_minHeight - _height - _marginTop, int32(st::playlistPadding));
} else if (_type == OverviewLinks || _type == OverviewDocuments) {
} else if (_type == OverviewLinks || _type == OverviewFiles) {
_marginTop = st::linksSearchMargin.top() + _search.height() + st::linksSearchMargin.bottom();
_marginBottom = qMax(_minHeight - _height - _marginTop, int32(st::playlistPadding));
} else {
@ -1940,15 +1932,15 @@ LayoutMediaItem *OverviewInner::layoutPrepare(HistoryItem *item) {
i.value()->initDimensions();
}
}
} else if (_type == OverviewAudios) {
if (media && media->type() == MediaTypeAudio) {
} else if (_type == OverviewVoiceFiles) {
if (media && (media->type() == MediaTypeVoiceFile)) {
if ((i = _layoutItems.constFind(item)) == _layoutItems.cend()) {
i = _layoutItems.insert(item, new LayoutOverviewAudio(static_cast<HistoryAudio*>(media)->audio(), item));
i = _layoutItems.insert(item, new LayoutOverviewVoice(media->getDocument(), item));
i.value()->initDimensions();
}
}
} else if (_type == OverviewDocuments || _type == OverviewAudioDocuments) {
if (media && (media->type() == MediaTypeDocument || media->type() == MediaTypeGif)) {
} else if (_type == OverviewFiles || _type == OverviewMusicFiles) {
if (media && (media->type() == MediaTypeFile || media->type() == MediaTypeMusicFile || media->type() == MediaTypeGif)) {
if ((i = _layoutItems.constFind(item)) == _layoutItems.cend()) {
i = _layoutItems.insert(item, new LayoutOverviewDocument(media->getDocument(), item));
i.value()->initDimensions();
@ -2032,7 +2024,7 @@ void OverviewWidget::onScroll() {
int32 preloadThreshold = _scroll.height() * 5;
bool needToPreload = false;
do {
needToPreload = (type() == OverviewLinks || type() == OverviewDocuments) ? (_scroll.scrollTop() + preloadThreshold > _scroll.scrollTopMax()) : (_scroll.scrollTop() < preloadThreshold);
needToPreload = (type() == OverviewLinks || type() == OverviewFiles) ? (_scroll.scrollTop() + preloadThreshold > _scroll.scrollTopMax()) : (_scroll.scrollTop() < preloadThreshold);
if (!needToPreload || !_inner.preloadLocal()) {
break;
}
@ -2097,7 +2089,7 @@ void OverviewWidget::scrollBy(int32 add) {
}
void OverviewWidget::scrollReset() {
_scroll.scrollToY((type() == OverviewLinks || type() == OverviewDocuments) ? 0 : _scroll.scrollTopMax());
_scroll.scrollToY((type() == OverviewLinks || type() == OverviewFiles) ? 0 : _scroll.scrollTopMax());
}
void OverviewWidget::paintTopBar(QPainter &p, float64 over, int32 decreaseWidth) {
@ -2142,9 +2134,9 @@ void OverviewWidget::switchType(MediaOverviewType type) {
switch (type) {
case OverviewPhotos: _header = lang(lng_profile_photos_header); break;
case OverviewVideos: _header = lang(lng_profile_videos_header); break;
case OverviewAudioDocuments: _header = lang(lng_profile_songs_header); break;
case OverviewDocuments: _header = lang(lng_profile_files_header); break;
case OverviewAudios: _header = lang(lng_profile_audios_header); break;
case OverviewMusicFiles: _header = lang(lng_profile_songs_header); break;
case OverviewFiles: _header = lang(lng_profile_files_header); break;
case OverviewVoiceFiles: _header = lang(lng_profile_audios_header); break;
case OverviewLinks: _header = lang(lng_profile_shared_links_header); break;
}
noSelectingScroll();
@ -2183,7 +2175,7 @@ int32 OverviewWidget::lastScrollTop() const {
}
int32 OverviewWidget::countBestScroll() const {
if (type() == OverviewAudioDocuments && audioPlayer()) {
if (type() == OverviewMusicFiles && audioPlayer()) {
SongMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &playingState);
@ -2193,7 +2185,7 @@ int32 OverviewWidget::countBestScroll() const {
return snap(top - int(_scroll.height() - (st::msgPadding.top() + st::mediaThumbSize + st::msgPadding.bottom())) / 2, 0, _scroll.scrollTopMax());
}
}
} else if (type() == OverviewLinks || type() == OverviewDocuments) {
} else if (type() == OverviewLinks || type() == OverviewFiles) {
return 0;
}
return _scroll.scrollTopMax();
@ -2350,7 +2342,7 @@ void OverviewWidget::onScrollTimer() {
}
void OverviewWidget::onPlayerSongChanged(const FullMsgId &msgId) {
if (type() == OverviewAudioDocuments) {
if (type() == OverviewMusicFiles) {
// int32 top = _inner.itemTop(msgId);
// if (top > 0) {
// _scroll.scrollToY(snap(top - int(_scroll.height() - (st::msgPadding.top() + st::mediaThumbSize + st::msgPadding.bottom())) / 2, 0, _scroll.scrollTopMax()));

View File

@ -198,7 +198,7 @@ void PlayerWidget::mousePressEvent(QMouseEvent *e) {
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency);
if (playing == _song && playingDuration) {
if (playingState == AudioPlayerPlaying || playingState == AudioPlayerStarting || playingState == AudioPlayerResuming) {
audioPlayer()->pauseresume(OverviewDocuments);
audioPlayer()->pauseresume(OverviewFiles);
}
_down = OverPlayback;
_downProgress = snap((pos.x() - _playbackRect.x()) / float64(_playbackRect.width()), 0., 1.);
@ -210,7 +210,7 @@ void PlayerWidget::mousePressEvent(QMouseEvent *e) {
}
} else if (_over == OverFull && _song) {
if (HistoryItem *item = App::histItemById(_song.msgId)) {
App::main()->showMediaOverview(item->history()->peer, OverviewAudioDocuments);
App::main()->showMediaOverview(item->history()->peer, OverviewMusicFiles);
}
} else if (_over == OverRepeat) {
_repeat = !_repeat;
@ -269,23 +269,23 @@ void PlayerWidget::updateControls() {
_fullAvailable = (_index >= 0);
History *history = _msgmigrated ? _migrated : _history;
_prevAvailable = _fullAvailable && ((_index > 0) || (_index == 0 && _migrated && !_msgmigrated && !_migrated->overview[OverviewAudioDocuments].isEmpty()));
_nextAvailable = _fullAvailable && ((_index < history->overview[OverviewAudioDocuments].size() - 1) || (_msgmigrated && _index == _migrated->overview[OverviewAudioDocuments].size() - 1 && _history->overviewLoaded(OverviewAudioDocuments) && _history->overviewCount(OverviewAudioDocuments) > 0));
_prevAvailable = _fullAvailable && ((_index > 0) || (_index == 0 && _migrated && !_msgmigrated && !_migrated->overview[OverviewMusicFiles].isEmpty()));
_nextAvailable = _fullAvailable && ((_index < history->overview[OverviewMusicFiles].size() - 1) || (_msgmigrated && _index == _migrated->overview[OverviewMusicFiles].size() - 1 && _history->overviewLoaded(OverviewMusicFiles) && _history->overviewCount(OverviewMusicFiles) > 0));
resizeEvent(0);
update();
if (_index >= 0 && _index < MediaOverviewStartPerPage) {
if (!_history->overviewLoaded(OverviewAudioDocuments) || (_migrated && !_migrated->overviewLoaded(OverviewAudioDocuments))) {
if (!_history->overviewLoaded(OverviewMusicFiles) || (_migrated && !_migrated->overviewLoaded(OverviewMusicFiles))) {
if (App::main()) {
if (_msgmigrated || (_migrated && _index == 0 && _history->overviewLoaded(OverviewAudioDocuments))) {
App::main()->loadMediaBack(_migrated->peer, OverviewAudioDocuments);
if (_msgmigrated || (_migrated && _index == 0 && _history->overviewLoaded(OverviewMusicFiles))) {
App::main()->loadMediaBack(_migrated->peer, OverviewMusicFiles);
} else {
App::main()->loadMediaBack(_history->peer, OverviewAudioDocuments);
if (_migrated && _index == 0 && _migrated->overview[OverviewAudioDocuments].isEmpty() && !_migrated->overviewLoaded(OverviewAudioDocuments)) {
App::main()->loadMediaBack(_migrated->peer, OverviewAudioDocuments);
App::main()->loadMediaBack(_history->peer, OverviewMusicFiles);
if (_migrated && _index == 0 && _migrated->overview[OverviewMusicFiles].isEmpty() && !_migrated->overviewLoaded(OverviewMusicFiles)) {
App::main()->loadMediaBack(_migrated->peer, OverviewMusicFiles);
}
}
if (_msgmigrated && !_history->overviewCountLoaded(OverviewAudioDocuments)) {
App::main()->preloadOverview(_history->peer, OverviewAudioDocuments);
if (_msgmigrated && !_history->overviewCountLoaded(OverviewMusicFiles)) {
App::main()->preloadOverview(_history->peer, OverviewMusicFiles);
}
}
}
@ -296,7 +296,7 @@ void PlayerWidget::findCurrent() {
_index = -1;
if (!_history) return;
const History::MediaOverview *o = &(_msgmigrated ? _migrated : _history)->overview[OverviewAudioDocuments];
const History::MediaOverview *o = &(_msgmigrated ? _migrated : _history)->overview[OverviewMusicFiles];
if ((_msgmigrated ? _migrated : _history)->channelId() == _song.msgId.channel) {
for (int i = 0, l = o->size(); i < l; ++i) {
if (o->at(i) == _song.msgId.msg) {
@ -312,14 +312,14 @@ void PlayerWidget::preloadNext() {
if (_index < 0) return;
History *history = _msgmigrated ? _migrated : _history;
const History::MediaOverview *o = &history->overview[OverviewAudioDocuments];
const History::MediaOverview *o = &history->overview[OverviewMusicFiles];
HistoryItem *next = 0;
if (_index < o->size() - 1) {
next = App::histItemById(history->channelId(), o->at(_index + 1));
} else if (_msgmigrated && _index == o->size() - 1 && _history->overviewLoaded(OverviewAudioDocuments) && _history->overviewCount(OverviewAudioDocuments) > 0) {
next = App::histItemById(_history->channelId(), _history->overview[OverviewAudioDocuments].at(0));
} else if (_msgmigrated && _index == o->size() - 1 && !_history->overviewCountLoaded(OverviewAudioDocuments)) {
if (App::main()) App::main()->preloadOverview(_history->peer, OverviewAudioDocuments);
} else if (_msgmigrated && _index == o->size() - 1 && _history->overviewLoaded(OverviewMusicFiles) && _history->overviewCount(OverviewMusicFiles) > 0) {
next = App::histItemById(_history->channelId(), _history->overview[OverviewMusicFiles].at(0));
} else if (_msgmigrated && _index == o->size() - 1 && !_history->overviewCountLoaded(OverviewMusicFiles)) {
if (App::main()) App::main()->preloadOverview(_history->peer, OverviewMusicFiles);
}
if (next) {
if (HistoryDocument *document = static_cast<HistoryDocument*>(next->getMedia())) {
@ -348,12 +348,12 @@ void PlayerWidget::clearSelection() {
}
void PlayerWidget::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
if (_history && (_history->peer == peer || (_migrated && _migrated->peer == peer)) && type == OverviewAudioDocuments) {
if (_history && (_history->peer == peer || (_migrated && _migrated->peer == peer)) && type == OverviewMusicFiles) {
_index = -1;
History *history = _msgmigrated ? _migrated : _history;
if (history->channelId() == _song.msgId.channel) {
for (int i = 0, l = history->overview[OverviewAudioDocuments].size(); i < l; ++i) {
if (history->overview[OverviewAudioDocuments].at(i) == _song.msgId.msg) {
for (int i = 0, l = history->overview[OverviewMusicFiles].size(); i < l; ++i) {
if (history->overview[OverviewMusicFiles].at(i) == _song.msgId.msg) {
_index = i;
preloadNext();
break;
@ -476,7 +476,7 @@ void PlayerWidget::playPressed() {
audioPlayer()->currentState(&playing, &playingState);
if (playing == _song && !(playingState & AudioPlayerStoppedMask)) {
if (playingState == AudioPlayerPausing || playingState == AudioPlayerPaused || playingState == AudioPlayerPausedAtEnd) {
audioPlayer()->pauseresume(OverviewDocuments);
audioPlayer()->pauseresume(OverviewFiles);
}
} else {
audioPlayer()->play(_song);
@ -492,7 +492,7 @@ void PlayerWidget::pausePressed() {
audioPlayer()->currentState(&playing, &playingState);
if (playing == _song && !(playingState & AudioPlayerStoppedMask)) {
if (playingState == AudioPlayerStarting || playingState == AudioPlayerResuming || playingState == AudioPlayerPlaying || playingState == AudioPlayerFinishing) {
audioPlayer()->pauseresume(OverviewDocuments);
audioPlayer()->pauseresume(OverviewFiles);
}
}
}
@ -504,7 +504,7 @@ void PlayerWidget::playPausePressed() {
AudioPlayerState playingState = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &playingState);
if (playing == _song && !(playingState & AudioPlayerStoppedMask)) {
audioPlayer()->pauseresume(OverviewDocuments);
audioPlayer()->pauseresume(OverviewFiles);
} else {
audioPlayer()->play(_song);
if (App::main()) App::main()->documentPlayProgress(_song);
@ -515,11 +515,11 @@ void PlayerWidget::prevPressed() {
if (isHidden()) return;
History *history = _msgmigrated ? _migrated : _history;
const History::MediaOverview *o = history ? &history->overview[OverviewAudioDocuments] : 0;
const History::MediaOverview *o = history ? &history->overview[OverviewMusicFiles] : 0;
if (audioPlayer() && o && _index > 0 && _index <= o->size() && !o->isEmpty()) {
startPlay(FullMsgId(history->channelId(), o->at(_index - 1)));
} else if (!_index && _history && _migrated && !_msgmigrated) {
o = &_migrated->overview[OverviewAudioDocuments];
o = &_migrated->overview[OverviewMusicFiles];
if (!o->isEmpty()) {
startPlay(FullMsgId(_migrated->channelId(), o->at(o->size() - 1)));
}
@ -530,11 +530,11 @@ void PlayerWidget::nextPressed() {
if (isHidden()) return;
History *history = _msgmigrated ? _migrated : _history;
const History::MediaOverview *o = history ? &history->overview[OverviewAudioDocuments] : 0;
const History::MediaOverview *o = history ? &history->overview[OverviewMusicFiles] : 0;
if (audioPlayer() && o && _index >= 0 && _index < o->size() - 1) {
startPlay(FullMsgId(history->channelId(), o->at(_index + 1)));
} else if (o && (_index == o->size() - 1) && _msgmigrated && _history->overviewLoaded(OverviewAudioDocuments)) {
o = &_history->overview[OverviewAudioDocuments];
} else if (o && (_index == o->size() - 1) && _msgmigrated && _history->overviewLoaded(OverviewMusicFiles)) {
o = &_history->overview[OverviewMusicFiles];
if (!o->isEmpty()) {
startPlay(FullMsgId(_history->channelId(), o->at(0)));
}
@ -544,7 +544,7 @@ void PlayerWidget::nextPressed() {
void PlayerWidget::stopPressed() {
if (!_song || isHidden()) return;
audioPlayer()->stop(OverviewDocuments);
audioPlayer()->stop(OverviewFiles);
if (App::main()) App::main()->hidePlayer();
}
@ -636,7 +636,7 @@ void PlayerWidget::updateState(SongMsgId playing, AudioPlayerState playingState,
display = _song.song->song()->duration;
}
bool showPause = false, stopped = ((playingState & AudioPlayerStoppedMask) || playingState == AudioPlayerFinishing);
bool wasPlaying = !!_duration;
bool wasPlaying = (_duration != 0);
if (!stopped) {
showPause = (playingState == AudioPlayerPlaying || playingState == AudioPlayerResuming || playingState == AudioPlayerStarting);
}

View File

@ -101,7 +101,7 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, PeerData
, _kickOver(0)
, _kickDown(0)
, _kickConfirm(0)
, _menu(0) {
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update()));
@ -209,9 +209,9 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, PeerData
// shared media
connect((_mediaButtons[OverviewPhotos] = new LinkButton(this, QString())), SIGNAL(clicked()), this, SLOT(onMediaPhotos()));
connect((_mediaButtons[OverviewVideos] = new LinkButton(this, QString())), SIGNAL(clicked()), this, SLOT(onMediaVideos()));
connect((_mediaButtons[OverviewAudioDocuments] = new LinkButton(this, QString())), SIGNAL(clicked()), this, SLOT(onMediaSongs()));
connect((_mediaButtons[OverviewDocuments] = new LinkButton(this, QString())), SIGNAL(clicked()), this, SLOT(onMediaDocuments()));
connect((_mediaButtons[OverviewAudios] = new LinkButton(this, QString())), SIGNAL(clicked()), this, SLOT(onMediaAudios()));
connect((_mediaButtons[OverviewMusicFiles] = new LinkButton(this, QString())), SIGNAL(clicked()), this, SLOT(onMediaSongs()));
connect((_mediaButtons[OverviewFiles] = new LinkButton(this, QString())), SIGNAL(clicked()), this, SLOT(onMediaDocuments()));
connect((_mediaButtons[OverviewVoiceFiles] = new LinkButton(this, QString())), SIGNAL(clicked()), this, SLOT(onMediaAudios()));
connect((_mediaButtons[OverviewLinks] = new LinkButton(this, QString())), SIGNAL(clicked()), this, SLOT(onMediaLinks()));
updateMediaLinks();
@ -261,7 +261,7 @@ void ProfileInner::loadProfilePhotos(int32 yFrom) {
int32 yTo = yFrom + (parentWidget() ? parentWidget()->height() : App::wnd()->height()) * 5;
MTP::clearLoaderPriorities();
int32 partfrom = _mediaButtons[OverviewAudios]->y() + _mediaButtons[OverviewAudios]->height() + st::profileHeaderSkip;
int32 partfrom = _mediaButtons[OverviewVoiceFiles]->y() + _mediaButtons[OverviewVoiceFiles]->height() + st::profileHeaderSkip;
yFrom -= partfrom;
yTo -= partfrom;
@ -279,7 +279,7 @@ void ProfileInner::loadProfilePhotos(int32 yFrom) {
void ProfileInner::onUpdatePhoto() {
saveError();
QStringList imgExtensions(cImgExtensions());
QStringList imgExtensions(cImgExtensions());
QString filter(qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;All files (*.*)"));
QImage img;
@ -440,15 +440,15 @@ void ProfileInner::onMediaVideos() {
}
void ProfileInner::onMediaSongs() {
App::main()->showMediaOverview(_peer, OverviewAudioDocuments);
App::main()->showMediaOverview(_peer, OverviewMusicFiles);
}
void ProfileInner::onMediaDocuments() {
App::main()->showMediaOverview(_peer, OverviewDocuments);
App::main()->showMediaOverview(_peer, OverviewFiles);
}
void ProfileInner::onMediaAudios() {
App::main()->showMediaOverview(_peer, OverviewAudios);
App::main()->showMediaOverview(_peer, OverviewVoiceFiles);
}
void ProfileInner::onMediaLinks() {
@ -464,7 +464,7 @@ void ProfileInner::onInvitationLink() {
void ProfileInner::onPublicLink() {
if (!_peerChannel) return;
if (_peerChannel->isPublic()) {
QApplication::clipboard()->setText(qsl("https://telegram.me/") + _peerChannel->username);
Ui::showLayer(new InformBox(lang(lng_channel_public_link_copied)));
@ -776,7 +776,7 @@ void ProfileInner::paintEvent(QPaintEvent *e) {
p.setOpacity(1);
}
}
int32 namew = _width - st::profilePhotoSize - st::profileNameLeft;
p.setPen(st::black->p);
if (_peer->isVerified()) {
@ -1271,7 +1271,7 @@ void ProfileInner::resizeEvent(QResizeEvent *e) {
_left = (width() - _width) / 2;
int32 top = 0, btnWidth = (_width - st::profileButtonSkip) / 2;
// profile
top += st::profilePadding.top();
int32 addbyname = 0;
@ -1446,7 +1446,7 @@ ProfileInner::~ProfileInner() {
}
_participantsData.clear();
}
void ProfileInner::openContextImage() {
}
@ -1711,9 +1711,9 @@ QString ProfileInner::overviewLinkText(int32 type, int32 count) {
switch (type) {
case OverviewPhotos: return lng_profile_photos(lt_count, count);
case OverviewVideos: return lng_profile_videos(lt_count, count);
case OverviewAudioDocuments: return lng_profile_songs(lt_count, count);
case OverviewDocuments: return lng_profile_files(lt_count, count);
case OverviewAudios: return lng_profile_audios(lt_count, count);
case OverviewMusicFiles: return lng_profile_songs(lt_count, count);
case OverviewFiles: return lng_profile_files(lt_count, count);
case OverviewVoiceFiles: return lng_profile_audios(lt_count, count);
case OverviewLinks: return lng_profile_shared_links(lt_count, count);
}
return QString();

View File

@ -1013,97 +1013,6 @@ void VideoData::setLocation(const FileLocation &loc) {
}
}
void AudioOpenLink::onClick(Qt::MouseButton button) const {
if (button != Qt::LeftButton) return;
AudioData *data = audio();
if (!data->date) return;
HistoryItem *item = App::hoveredLinkItem() ? App::hoveredLinkItem() : (App::contextItem() ? App::contextItem() : 0);
bool play = audioPlayer() && item;
const FileLocation &location(data->location(true));
if (!location.isEmpty() || (!data->data().isEmpty() && play)) {
if (play) {
AudioMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &playingState);
if (playing.msgId == item->fullId() && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
audioPlayer()->pauseresume(OverviewAudios);
} else {
AudioMsgId audio(data, item->fullId());
audioPlayer()->play(audio);
if (App::main()) {
App::main()->audioPlayProgress(audio);
App::main()->audioMarkRead(data);
}
}
} else {
psOpenFile(location.name());
if (App::main()) App::main()->audioMarkRead(data);
}
return;
}
if (data->status != FileReady) return;
QString filename;
if (!data->saveToCache()) {
bool mp3 = (data->mime == qstr("audio/mp3"));
filename = saveFileName(lang(lng_save_audio), mp3 ? qsl("MP3 Audio (*.mp3);;All files (*.*)") : qsl("OGG Opus Audio (*.ogg);;All files (*.*)"), qsl("audio"), mp3 ? qsl(".mp3") : qsl(".ogg"), false);
if (filename.isEmpty()) return;
}
data->save(filename, ActionOnLoadOpen, item ? item->fullId() : FullMsgId());
}
void AudioSaveLink::doSave(AudioData *data, bool forceSavingAs) {
if (!data->date) return;
QString already = data->already(true);
bool openWith = !already.isEmpty();
if (openWith && !forceSavingAs) {
QPoint pos(QCursor::pos());
if (!psShowOpenWithMenu(pos.x(), pos.y(), already)) {
psOpenFile(already, true);
}
} else {
QFileInfo alreadyInfo(already);
QDir alreadyDir(already.isEmpty() ? QDir() : alreadyInfo.dir());
bool mp3 = (data->mime == qstr("audio/mp3"));
QString name = already.isEmpty() ? (mp3 ? qsl(".mp3") : qsl(".ogg")) : alreadyInfo.fileName();
QString filename = saveFileName(lang(lng_save_audio), mp3 ? qsl("MP3 Audio (*.mp3);;All files (*.*)") : qsl("OGG Opus Audio (*.ogg);;All files (*.*)"), qsl("audio"), name, forceSavingAs, alreadyDir);
if (!filename.isEmpty()) {
ActionOnLoad action = already.isEmpty() ? ActionOnLoadNone : ActionOnLoadOpenWith;
FullMsgId actionMsgId = App::hoveredLinkItem() ? App::hoveredLinkItem()->fullId() : (App::contextItem() ? App::contextItem()->fullId() : FullMsgId());
data->save(filename, action, actionMsgId);
}
}
}
void AudioSaveLink::onClick(Qt::MouseButton button) const {
if (button != Qt::LeftButton) return;
doSave(audio());
}
void AudioCancelLink::onClick(Qt::MouseButton button) const {
AudioData *data = audio();
if (!data->date || button != Qt::LeftButton) return;
if (data->uploading()) {
HistoryItem *item = App::hoveredLinkItem() ? App::hoveredLinkItem() : (App::contextItem() ? App::contextItem() : 0);
if (HistoryMessage *msg = item->toHistoryMessage()) {
if (msg->getMedia() && msg->getMedia()->type() == MediaTypeAudio && static_cast<HistoryAudio*>(msg->getMedia())->audio() == data) {
App::contextItem(item);
App::main()->deleteLayer(-2);
}
}
} else {
data->cancel();
}
}
bool StickerData::setInstalled() const {
switch (set.type()) {
case mtpc_inputStickerSetID: {
@ -1122,239 +1031,44 @@ bool StickerData::setInstalled() const {
return false;
}
AudioData::AudioData(const AudioId &id, const uint64 &access, int32 date, const QString &mime, int32 duration, int32 dc, int32 size)
: id(id)
, access(access)
, date(date)
, mime(mime)
, duration(duration)
, dc(dc)
, size(size)
, status(FileReady)
, uploadOffset(0)
, _actionOnLoad(ActionOnLoadNone)
, _loader(0) {
_location = Local::readFileLocation(mediaKey(AudioFileLocation, dc, id));
}
bool AudioData::saveToCache() const {
return size < AudioVoiceMsgInMemory;
}
void AudioData::forget() {
_data.clear();
}
void AudioData::automaticLoad(const HistoryItem *item) {
if (loaded() || status != FileReady) return;
if (saveToCache() && _loader != CancelledMtpFileLoader) {
if (item) {
bool loadFromCloud = false;
if (item->history()->peer->isUser()) {
loadFromCloud = !(cAutoDownloadAudio() & dbiadNoPrivate);
} else {
loadFromCloud = !(cAutoDownloadAudio() & dbiadNoGroups);
}
save(QString(), _actionOnLoad, _actionOnLoadMsgId, loadFromCloud ? LoadFromCloudOrLocal : LoadFromLocalOnly, true);
}
}
}
void AudioData::automaticLoadSettingsChanged() {
if (loaded() || status != FileReady || !saveToCache() || _loader != CancelledMtpFileLoader) return;
_loader = 0;
}
void AudioData::performActionOnLoad() {
if (_actionOnLoad == ActionOnLoadNone) return;
const FileLocation &loc(location(true));
QString already = loc.name();
bool play = _actionOnLoadMsgId.msg && (_actionOnLoad == ActionOnLoadPlayInline || _actionOnLoad == ActionOnLoadOpen) && audioPlayer();
if (play) {
if (loaded()) {
AudioMsgId playing;
AudioPlayerState state = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &state);
if (playing.msgId == _actionOnLoadMsgId && !(state & AudioPlayerStoppedMask) && state != AudioPlayerFinishing) {
audioPlayer()->pauseresume(OverviewAudios);
} else {
audioPlayer()->play(AudioMsgId(this, _actionOnLoadMsgId));
if (App::main()) App::main()->audioMarkRead(this);
}
}
} else {
if (already.isEmpty()) return;
if (_actionOnLoad == ActionOnLoadOpenWith) {
if (already.isEmpty()) return;
QPoint pos(QCursor::pos());
if (!psShowOpenWithMenu(pos.x(), pos.y(), already)) {
psOpenFile(already, true);
}
if (App::main()) App::main()->audioMarkRead(this);
} else if (_actionOnLoad == ActionOnLoadOpen || _actionOnLoad == ActionOnLoadPlayInline) {
psOpenFile(already);
if (App::main()) App::main()->audioMarkRead(this);
}
}
_actionOnLoad = ActionOnLoadNone;
}
bool AudioData::loaded(bool check) const {
if (loading() && _loader->done()) {
if (_loader->fileType() == mtpc_storage_fileUnknown) {
_loader->deleteLater();
_loader->rpcInvalidate();
_loader = CancelledMtpFileLoader;
} else {
AudioData *that = const_cast<AudioData*>(this);
that->_location = FileLocation(mtpToStorageType(_loader->fileType()), _loader->fileName());
that->_data = _loader->bytes();
_loader->deleteLater();
_loader->rpcInvalidate();
_loader = 0;
}
notifyLayoutChanged();
}
return !_data.isEmpty() || !already(check).isEmpty();
}
bool AudioData::loading() const {
return _loader && _loader != CancelledMtpFileLoader;
}
bool AudioData::displayLoading() const {
return loading() ? (!_loader->loadingLocal() || !_loader->autoLoading()) : uploading();
}
float64 AudioData::progress() const {
if (uploading()) {
if (size > 0) {
return float64(uploadOffset) / size;
}
return 0;
}
return loading() ? _loader->currentProgress() : (loaded() ? 1 : 0);
}
int32 AudioData::loadOffset() const {
return loading() ? _loader->currentOffset() : 0;
}
bool AudioData::uploading() const {
return status == FileUploading;
}
void AudioData::save(const QString &toFile, ActionOnLoad action, const FullMsgId &actionMsgId, LoadFromCloudSetting fromCloud, bool autoLoading) {
if (loaded(true)) {
const FileLocation &l(location(true));
if (!toFile.isEmpty()) {
if (!_data.isEmpty()) {
QFile f(toFile);
f.open(QIODevice::WriteOnly);
f.write(_data);
} else if (l.accessEnable()) {
QFile(l.name()).copy(toFile);
l.accessDisable();
}
}
return;
}
if (_loader == CancelledMtpFileLoader) _loader = 0;
if (_loader) {
if (!_loader->setFileName(toFile)) {
cancel();
_loader = 0;
}
}
_actionOnLoad = action;
_actionOnLoadMsgId = actionMsgId;
if (_loader) {
if (fromCloud == LoadFromCloudOrLocal) _loader->permitLoadFromCloud();
} else {
status = FileReady;
_loader = new mtpFileLoader(dc, id, access, AudioFileLocation, toFile, size, (saveToCache() ? LoadToCacheAsWell : LoadToFileOnly), fromCloud, autoLoading);
_loader->connect(_loader, SIGNAL(progress(FileLoader*)), App::main(), SLOT(audioLoadProgress(FileLoader*)));
_loader->connect(_loader, SIGNAL(failed(FileLoader*,bool)), App::main(), SLOT(audioLoadFailed(FileLoader*,bool)));
_loader->start();
}
notifyLayoutChanged();
}
void AudioData::cancel() {
if (!loading()) return;
mtpFileLoader *l = _loader;
_loader = CancelledMtpFileLoader;
if (l) {
l->cancel();
l->deleteLater();
l->rpcInvalidate();
notifyLayoutChanged();
}
_actionOnLoad = ActionOnLoadNone;
}
void AudioData::notifyLayoutChanged() const {
const AudioItems &items(App::audioItems());
AudioItems::const_iterator i = items.constFind(const_cast<AudioData*>(this));
if (i != items.cend()) {
for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) {
Notify::historyItemLayoutChanged(j.key());
}
}
}
QString AudioData::already(bool check) const {
return location(check).name();
}
QByteArray AudioData::data() const {
return _data;
}
const FileLocation &AudioData::location(bool check) const {
if (check && !_location.check()) {
const_cast<AudioData*>(this)->_location = Local::readFileLocation(mediaKey(AudioFileLocation, dc, id));
}
return _location;
}
void AudioData::setLocation(const FileLocation &loc) {
if (loc.check()) {
_location = loc;
}
}
void DocumentOpenLink::doOpen(DocumentData *data, ActionOnLoad action) {
if (!data->date) return;
HistoryItem *item = App::hoveredLinkItem() ? App::hoveredLinkItem() : (App::contextItem() ? App::contextItem() : 0);
bool playVoice = data->voice() && audioPlayer() && item;
bool playMusic = data->song() && audioPlayer() && item;
bool playAnimation = data->isAnimation() && item && item->getMedia();
const FileLocation &location(data->location(true));
if (!location.isEmpty() || (!data->data().isEmpty() && (playMusic || playAnimation))) {
if (playMusic) {
if (!location.isEmpty() || (!data->data().isEmpty() && (playVoice || playMusic || playAnimation))) {
if (playVoice) {
AudioMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &playingState);
if (playing.msgId == item->fullId() && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
audioPlayer()->pauseresume(OverviewVoiceFiles);
} else {
AudioMsgId audio(data, item->fullId());
audioPlayer()->play(audio);
if (App::main()) {
App::main()->audioPlayProgress(audio);
App::main()->audioMarkRead(data);
}
}
} else if (playMusic) {
SongMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &playingState);
if (playing.msgId == item->fullId() && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
audioPlayer()->pauseresume(OverviewDocuments);
audioPlayer()->pauseresume(OverviewFiles);
} else {
SongMsgId song(data, item->fullId());
audioPlayer()->play(song);
if (App::main()) App::main()->documentPlayProgress(song);
}
} else if (data->voice()) {
psOpenFile(location.name());
if (App::main()) App::main()->audioMarkRead(data);
} else if (data->size < MediaViewImageSizeLimit) {
if (!data->data().isEmpty() && playAnimation) {
if (action == ActionOnLoadPlayInline) {
@ -1386,21 +1100,32 @@ void DocumentOpenLink::doOpen(DocumentData *data, ActionOnLoad action) {
QString filename;
if (!data->saveToCache()) {
QString name = data->name, filter;
QString name, filter, caption, prefix;
MimeType mimeType = mimeTypeForName(data->mime);
QStringList p = mimeType.globPatterns();
QString pattern = p.isEmpty() ? QString() : p.front();
if (name.isEmpty()) {
name = pattern.isEmpty() ? qsl(".unknown") : pattern.replace('*', QString());
}
if (pattern.isEmpty()) {
filter = QString();
if (data->voice()) {
bool mp3 = (data->mime == qstr("audio/mp3"));
name = mp3 ? qsl(".mp3") : qsl(".ogg");
filter = mp3 ? qsl("MP3 Audio (*.mp3);;All files (*.*)") : qsl("OGG Opus Audio (*.ogg);;All files (*.*)");
caption = lang(lng_save_audio);
prefix = qsl("audio");
} else {
filter = mimeType.filterString() + qsl(";;All files (*.*)");
if (data->name.isEmpty()) {
name = pattern.isEmpty() ? qsl(".unknown") : pattern.replace('*', QString());
} else {
name = data->name;
}
if (pattern.isEmpty()) {
filter = QString();
} else {
filter = mimeType.filterString() + qsl(";;All files (*.*)");
}
caption = lang(lng_save_file);
prefix = qsl("doc");
}
filename = saveFileName(lang(lng_save_file), filter, qsl("doc"), name, false);
filename = saveFileName(caption, filter, prefix, name, false);
if (filename.isEmpty()) return;
}
@ -1410,16 +1135,17 @@ void DocumentOpenLink::doOpen(DocumentData *data, ActionOnLoad action) {
void DocumentOpenLink::onClick(Qt::MouseButton button) const {
if (button != Qt::LeftButton) return;
doOpen(document());
doOpen(document(), document()->voice() ? ActionOnLoadNone : ActionOnLoadOpen);
}
void GifOpenLink::doOpen(DocumentData *data) {
return DocumentOpenLink::doOpen(data, ActionOnLoadPlayInline);
void VoiceSaveLink::onClick(Qt::MouseButton button) const {
if (button != Qt::LeftButton) return;
doOpen(document(), ActionOnLoadNone);
}
void GifOpenLink::onClick(Qt::MouseButton button) const {
if (button != Qt::LeftButton) return;
doOpen(document());
doOpen(document(), ActionOnLoadPlayInline);
}
void DocumentSaveLink::doSave(DocumentData *data, bool forceSavingAs) {
@ -1433,23 +1159,34 @@ void DocumentSaveLink::doSave(DocumentData *data, bool forceSavingAs) {
psOpenFile(already, true);
}
} else {
QFileInfo alreadyInfo(already);
QDir alreadyDir(already.isEmpty() ? QDir() : alreadyInfo.dir());
QString name = already.isEmpty() ? data->name : alreadyInfo.fileName(), filter;
QString caption, filter, prefix, name;
MimeType mimeType = mimeTypeForName(data->mime);
QStringList p = mimeType.globPatterns();
QString pattern = p.isEmpty() ? QString() : p.front();
if (name.isEmpty()) {
name = pattern.isEmpty() ? qsl(".unknown") : pattern.replace('*', QString());
}
if (pattern.isEmpty()) {
filter = QString();
if (data->voice()) {
bool mp3 = (data->mime == qstr("audio/mp3"));
caption = lang(lng_save_audio);
filter = mp3 ? qsl("MP3 Audio (*.mp3);;All files (*.*)") : qsl("OGG Opus Audio (*.ogg);;All files (*.*)");
prefix = qsl("audio");
name = already.isEmpty() ? (mp3 ? qsl(".mp3") : qsl(".ogg")) : alreadyInfo.fileName();
} else {
filter = mimeType.filterString() + qsl(";;All files (*.*)");
caption = lang(lng_save_file);
if (pattern.isEmpty()) {
filter = QString();
} else {
filter = mimeType.filterString() + qsl(";;All files (*.*)");
}
prefix = qsl("doc");
name = already.isEmpty() ? data->name : alreadyInfo.fileName();
if (name.isEmpty()) {
name = pattern.isEmpty() ? qsl(".unknown") : pattern.replace('*', QString());
}
}
QString filename = saveFileName(lang(lng_save_file), filter, qsl("doc"), name, forceSavingAs, alreadyDir);
QString filename = saveFileName(caption, filter, prefix, name, forceSavingAs, alreadyDir);
if (!filename.isEmpty()) {
ActionOnLoad action = already.isEmpty() ? ActionOnLoadNone : ActionOnLoadOpenWith;
FullMsgId actionMsgId = App::hoveredLinkItem() ? App::hoveredLinkItem()->fullId() : (App::contextItem() ? App::contextItem()->fullId() : FullMsgId());
@ -1482,6 +1219,14 @@ void DocumentCancelLink::onClick(Qt::MouseButton button) const {
}
}
VoiceData::~VoiceData() {
if (!waveform.isEmpty() && waveform.at(0) == -1 && waveform.size() > sizeof(TaskId)) {
TaskId taskId = 0;
memcpy(&taskId, waveform.constData() + 1, sizeof(taskId));
Local::cancelTask(taskId);
}
}
DocumentData::DocumentData(const DocumentId &id, const uint64 &access, int32 date, const QVector<MTPDocumentAttribute> &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size) : id(id)
, type(FileDocument)
, access(access)
@ -1496,8 +1241,8 @@ DocumentData::DocumentData(const DocumentId &id, const uint64 &access, int32 dat
, _duration(-1)
, _actionOnLoad(ActionOnLoadNone)
, _loader(0) {
_location = Local::readFileLocation(mediaKey(DocumentFileLocation, dc, id));
setattributes(attributes);
_location = Local::readFileLocation(mediaKey(voice() ? AudioFileLocation : DocumentFileLocation, dc, id));
}
void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes) {
@ -1535,11 +1280,27 @@ void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes
case mtpc_documentAttributeAudio: {
const MTPDdocumentAttributeAudio &d(attributes[i].c_documentAttributeAudio());
if (type == FileDocument) {
type = SongDocument;
SongData *song = new SongData();
_additional = song;
if (d.is_voice()) {
type = VoiceDocument;
VoiceData *voice = new VoiceData();
_additional = voice;
} else {
type = SongDocument;
SongData *song = new SongData();
_additional = song;
}
}
if (song()) {
if (voice()) {
voice()->duration = d.vduration.v;
VoiceWaveform waveform = documentWaveformDecode(qba(d.vwaveform));
uchar wavemax = 0;
for (int32 i = 0, l = waveform.size(); i < l; ++i) {
uchar waveat = waveform.at(i);
if (wavemax < waveat) wavemax = waveat;
}
voice()->waveform = waveform;
voice()->wavemax = wavemax;
} else if (song()) {
song()->duration = d.vduration.v;
song()->title = qs(d.vtitle);
song()->performer = qs(d.vperformer);
@ -1558,7 +1319,7 @@ void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes
}
bool DocumentData::saveToCache() const {
return (type == StickerDocument) || (isAnimation() && size < AnimationInMemory);
return (type == StickerDocument) || (isAnimation() && size < AnimationInMemory) || (voice() && size < AudioVoiceMsgInMemory);
}
void DocumentData::forget() {
@ -1586,12 +1347,22 @@ void DocumentData::automaticLoad(const HistoryItem *item) {
loadFromCloud = !(cAutoDownloadGif() & dbiadNoPrivate) || !(cAutoDownloadGif() & dbiadNoGroups);
}
save(QString(), _actionOnLoad, _actionOnLoadMsgId, loadFromCloud ? LoadFromCloudOrLocal : LoadFromLocalOnly, true);
} else if (voice()) {
if (item) {
bool loadFromCloud = false;
if (item->history()->peer->isUser()) {
loadFromCloud = !(cAutoDownloadAudio() & dbiadNoPrivate);
} else {
loadFromCloud = !(cAutoDownloadAudio() & dbiadNoGroups);
}
save(QString(), _actionOnLoad, _actionOnLoadMsgId, loadFromCloud ? LoadFromCloudOrLocal : LoadFromLocalOnly, true);
}
}
}
}
void DocumentData::automaticLoadSettingsChanged() {
if (loaded() || status != FileReady || !isAnimation() || !saveToCache() || _loader != CancelledMtpFileLoader) return;
if (loaded() || status != FileReady || (!isAnimation() && !voice()) || !saveToCache() || _loader != CancelledMtpFileLoader) return;
_loader = 0;
}
@ -1602,15 +1373,28 @@ void DocumentData::performActionOnLoad() {
QString already = loc.name();
HistoryItem *item = _actionOnLoadMsgId.msg ? App::histItemById(_actionOnLoadMsgId) : 0;
bool showImage = item && (size < MediaViewImageSizeLimit);
bool playVoice = voice() && audioPlayer() && (_actionOnLoad == ActionOnLoadPlayInline || _actionOnLoad == ActionOnLoadOpen) && item;
bool playMusic = song() && audioPlayer() && (_actionOnLoad == ActionOnLoadPlayInline || _actionOnLoad == ActionOnLoadOpen) && item;
bool playAnimation = isAnimation() && (_actionOnLoad == ActionOnLoadPlayInline || _actionOnLoad == ActionOnLoadOpen) && showImage && item->getMedia();
if (playMusic) {
if (playVoice) {
if (loaded()) {
AudioMsgId playing;
AudioPlayerState state = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &state);
if (playing.msgId == _actionOnLoadMsgId && !(state & AudioPlayerStoppedMask) && state != AudioPlayerFinishing) {
audioPlayer()->pauseresume(OverviewVoiceFiles);
} else {
audioPlayer()->play(AudioMsgId(this, _actionOnLoadMsgId));
if (App::main()) App::main()->audioMarkRead(this);
}
}
} else if (playMusic) {
if (loaded()) {
SongMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped;
audioPlayer()->currentState(&playing, &playingState);
if (playing.msgId == item->fullId() && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
audioPlayer()->pauseresume(OverviewDocuments);
audioPlayer()->pauseresume(OverviewFiles);
} else {
SongMsgId song(this, item->fullId());
audioPlayer()->play(song);
@ -1636,7 +1420,10 @@ void DocumentData::performActionOnLoad() {
psOpenFile(already, true);
}
} else if (_actionOnLoad == ActionOnLoadOpen || _actionOnLoad == ActionOnLoadPlayInline) {
if (loc.accessEnable()) {
if (voice()) {
psOpenFile(already);
if (App::main()) App::main()->audioMarkRead(this);
} else if (loc.accessEnable()) {
if (showImage && QImageReader(loc.name()).canRead()) {
if (_actionOnLoad == ActionOnLoadPlayInline) {
item->getMedia()->playInline(item);
@ -1735,7 +1522,8 @@ void DocumentData::save(const QString &toFile, ActionOnLoad action, const FullMs
if (fromCloud == LoadFromCloudOrLocal) _loader->permitLoadFromCloud();
} else {
status = FileReady;
_loader = new mtpFileLoader(dc, id, access, DocumentFileLocation, toFile, size, (saveToCache() ? LoadToCacheAsWell : LoadToFileOnly), fromCloud, autoLoading);
LocationType type = voice() ? AudioFileLocation : DocumentFileLocation;
_loader = new mtpFileLoader(dc, id, access, type, toFile, size, (saveToCache() ? LoadToCacheAsWell : LoadToFileOnly), fromCloud, autoLoading);
_loader->connect(_loader, SIGNAL(progress(FileLoader*)), App::main(), SLOT(documentLoadProgress(FileLoader*)));
_loader->connect(_loader, SIGNAL(failed(FileLoader*,bool)), App::main(), SLOT(documentLoadFailed(FileLoader*,bool)));
_loader->start();
@ -1769,6 +1557,24 @@ void DocumentData::notifyLayoutChanged() const {
}
}
VoiceWaveform documentWaveformDecode(const QByteArray &encoded5bit) {
VoiceWaveform result((encoded5bit.size() * 8) / 5, 0);
for (int32 i = 0, l = result.size(); i < l; ++i) { // read each 5 bit of encoded5bit as 0-31 unsigned char
int32 byte = (i * 5) / 8, shift = (i * 5) % 8;
result[i] = (((*(uint16*)(encoded5bit.constData() + byte)) >> shift) & 0x1F);
}
return result;
}
QByteArray documentWaveformEncode5bit(const VoiceWaveform &waveform) {
QByteArray result((waveform.size() * 5 + 7) / 8, 0);
for (int32 i = 0, l = waveform.size(); i < l; ++i) { // write each 0-31 unsigned char as 5 bit to result
int32 byte = (i * 5) / 8, shift = (i * 5) % 8;
(*(uint16*)(result.data() + byte)) |= (uint16(waveform.at(i) & 0x1F) << shift);
}
return result;
}
QString DocumentData::already(bool check) const {
if (check && _location.name().isEmpty()) return QString();
return location(check).name();
@ -1780,7 +1586,8 @@ QByteArray DocumentData::data() const {
const FileLocation &DocumentData::location(bool check) const {
if (check && !_location.check()) {
const_cast<DocumentData*>(this)->_location = Local::readFileLocation(mediaKey(DocumentFileLocation, dc, id));
LocationType type = voice() ? AudioFileLocation : DocumentFileLocation;
const_cast<DocumentData*>(this)->_location = Local::readFileLocation(mediaKey(type, dc, id));
}
return _location;
}

View File

@ -914,138 +914,13 @@ public:
};
class AudioData {
public:
AudioData(const AudioId &id, const uint64 &access = 0, int32 date = 0, const QString &mime = QString(), int32 duration = 0, int32 dc = 0, int32 size = 0);
void automaticLoad(const HistoryItem *item); // auto load voice message
void automaticLoadSettingsChanged();
bool loaded(bool check = false) const;
bool loading() const;
bool displayLoading() const;
void save(const QString &toFile, ActionOnLoad action = ActionOnLoadNone, const FullMsgId &actionMsgId = FullMsgId(), LoadFromCloudSetting fromCloud = LoadFromCloudOrLocal, bool autoLoading = false);
void cancel();
float64 progress() const;
int32 loadOffset() const;
bool uploading() const;
QString already(bool check = false) const;
QByteArray data() const;
const FileLocation &location(bool check = false) const;
void setLocation(const FileLocation &loc);
bool saveToCache() const;
void performActionOnLoad();
void forget();
void setData(const QByteArray &data) {
_data = data;
}
AudioId id;
uint64 access;
int32 date;
QString mime;
int32 duration;
int32 dc;
int32 size;
FileStatus status;
int32 uploadOffset;
int32 md5[8];
private:
FileLocation _location;
QByteArray _data;
ActionOnLoad _actionOnLoad;
FullMsgId _actionOnLoadMsgId;
mutable mtpFileLoader *_loader;
void notifyLayoutChanged() const;
};
struct AudioMsgId {
AudioMsgId() : audio(0) {
}
AudioMsgId(AudioData *audio, const FullMsgId &msgId) : audio(audio), msgId(msgId) {
}
AudioMsgId(AudioData *audio, ChannelId channelId, MsgId msgId) : audio(audio), msgId(channelId, msgId) {
}
operator bool() const {
return audio;
}
AudioData *audio;
FullMsgId msgId;
};
inline bool operator<(const AudioMsgId &a, const AudioMsgId &b) {
return quintptr(a.audio) < quintptr(b.audio) || (quintptr(a.audio) == quintptr(b.audio) && a.msgId < b.msgId);
}
inline bool operator==(const AudioMsgId &a, const AudioMsgId &b) {
return a.audio == b.audio && a.msgId == b.msgId;
}
inline bool operator!=(const AudioMsgId &a, const AudioMsgId &b) {
return !(a == b);
}
class AudioLink : public ITextLink {
TEXT_LINK_CLASS(AudioLink)
public:
AudioLink(AudioData *audio) : _audio(audio) {
}
AudioData *audio() const {
return _audio;
}
private:
AudioData *_audio;
};
class AudioSaveLink : public AudioLink {
TEXT_LINK_CLASS(AudioSaveLink)
public:
AudioSaveLink(AudioData *audio) : AudioLink(audio) {
}
static void doSave(AudioData *audio, bool forceSavingAs = false);
void onClick(Qt::MouseButton button) const;
};
class AudioOpenLink : public AudioLink {
TEXT_LINK_CLASS(AudioOpenLink)
public:
AudioOpenLink(AudioData *audio) : AudioLink(audio) {
}
void onClick(Qt::MouseButton button) const;
};
class AudioCancelLink : public AudioLink {
TEXT_LINK_CLASS(AudioCancelLink)
public:
AudioCancelLink(AudioData *audio) : AudioLink(audio) {
}
void onClick(Qt::MouseButton button) const;
};
enum DocumentType {
FileDocument = 0,
VideoDocument = 1,
SongDocument = 2,
StickerDocument = 3,
AnimatedDocument = 4,
VoiceDocument = 5,
};
struct DocumentAdditionalData {
@ -1072,6 +947,16 @@ struct SongData : public DocumentAdditionalData {
};
typedef QVector<char> VoiceWaveform; // [0] == -1 -- counting, [0] == -2 -- could not count
struct VoiceData : public DocumentAdditionalData {
VoiceData() : duration(0), wavemax(0) {
}
~VoiceData();
int32 duration;
VoiceWaveform waveform;
char wavemax;
};
bool fileIsImage(const QString &name, const QString &mime);
class DocumentData {
@ -1126,12 +1011,21 @@ public:
SongData *song() {
return (type == SongDocument) ? static_cast<SongData*>(_additional) : 0;
}
VoiceData *voice() {
return (type == VoiceDocument) ? static_cast<VoiceData*>(_additional) : 0;
}
const VoiceData *voice() const {
return (type == VoiceDocument) ? static_cast<VoiceData*>(_additional) : 0;
}
bool isAnimation() const {
return (type == AnimatedDocument) || !mime.compare(qstr("image/gif"), Qt::CaseInsensitive);
}
bool isGifv() const {
return (type == AnimatedDocument) && !mime.compare(qstr("video/mp4"), Qt::CaseInsensitive);
}
bool isMusic() const {
return (type == SongDocument) ? !static_cast<SongData*>(_additional)->title.isEmpty() : false;
}
int32 duration() const {
return (isAnimation() || type == VideoDocument) ? _duration : -1;
}
@ -1139,6 +1033,9 @@ public:
return !isAnimation() && (type != VideoDocument) && (_duration > 0);
}
void recountIsImage();
void setData(const QByteArray &data) {
_data = data;
}
~DocumentData();
@ -1172,6 +1069,9 @@ private:
};
VoiceWaveform documentWaveformDecode(const QByteArray &encoded5bit);
QByteArray documentWaveformEncode5bit(const VoiceWaveform &waveform);
struct SongMsgId {
SongMsgId() : song(0) {
}
@ -1196,6 +1096,31 @@ inline bool operator!=(const SongMsgId &a, const SongMsgId &b) {
return !(a == b);
}
struct AudioMsgId {
AudioMsgId() : audio(0) {
}
AudioMsgId(DocumentData *audio, const FullMsgId &msgId) : audio(audio), msgId(msgId) {
}
AudioMsgId(DocumentData *audio, ChannelId channelId, MsgId msgId) : audio(audio), msgId(channelId, msgId) {
}
operator bool() const {
return audio;
}
DocumentData *audio;
FullMsgId msgId;
};
inline bool operator<(const AudioMsgId &a, const AudioMsgId &b) {
return quintptr(a.audio) < quintptr(b.audio) || (quintptr(a.audio) == quintptr(b.audio) && a.msgId < b.msgId);
}
inline bool operator==(const AudioMsgId &a, const AudioMsgId &b) {
return a.audio == b.audio && a.msgId == b.msgId;
}
inline bool operator!=(const AudioMsgId &a, const AudioMsgId &b) {
return !(a == b);
}
class DocumentLink : public ITextLink {
TEXT_LINK_CLASS(DocumentLink)
@ -1233,13 +1158,22 @@ public:
};
class VoiceSaveLink : public DocumentOpenLink {
TEXT_LINK_CLASS(VoiceSaveLink)
public:
VoiceSaveLink(DocumentData *document) : DocumentOpenLink(document) {
}
void onClick(Qt::MouseButton button) const;
};
class GifOpenLink : public DocumentOpenLink {
TEXT_LINK_CLASS(GifOpenLink)
public:
GifOpenLink(DocumentData *document) : DocumentOpenLink(document) {
}
static void doOpen(DocumentData *document);
void onClick(Qt::MouseButton button) const;
};

View File

@ -532,18 +532,21 @@ inline void destroyImplementation(I *&ptr) {
class Interfaces;
typedef void(*InterfaceConstruct)(void *location, Interfaces *interfaces);
typedef void(*InterfaceDestruct)(void *location);
typedef void(*InterfaceAssign)(void *location, void *waslocation);
struct InterfaceWrapStruct {
InterfaceWrapStruct() : Size(0), Construct(0), Destruct(0) {
}
InterfaceWrapStruct(int size, InterfaceConstruct construct, InterfaceDestruct destruct)
InterfaceWrapStruct(int size, InterfaceConstruct construct, InterfaceDestruct destruct, InterfaceAssign assign)
: Size(size)
, Construct(construct)
, Destruct(destruct) {
, Destruct(destruct)
, Assign(assign) {
}
int Size;
InterfaceConstruct Construct;
InterfaceDestruct Destruct;
InterfaceAssign Assign;
};
template <int Value, int Denominator>
@ -560,6 +563,9 @@ struct InterfaceWrapTemplate {
static void Destruct(void *location) {
((Type*)location)->~Type();
}
static void Assign(void *location, void *waslocation) {
*((Type*)location) = *((Type*)waslocation);
}
};
extern InterfaceWrapStruct InterfaceWraps[64];
@ -578,7 +584,7 @@ public:
if (InterfaceIndexLast.testAndSetOrdered(last, last + 1)) {
t_assert(last < 64);
if (_index.testAndSetOrdered(0, last + 1)) {
InterfaceWraps[last] = InterfaceWrapStruct(InterfaceWrapTemplate<Type>::Size, InterfaceWrapTemplate<Type>::Construct, InterfaceWrapTemplate<Type>::Destruct);
InterfaceWraps[last] = InterfaceWrapStruct(InterfaceWrapTemplate<Type>::Size, InterfaceWrapTemplate<Type>::Construct, InterfaceWrapTemplate<Type>::Destruct, InterfaceWrapTemplate<Type>::Assign);
}
break;
}
@ -627,6 +633,10 @@ public:
int size, last;
int offsets[64];
bool equals(const uint64 &mask) const {
return _mask == mask;
}
private:
uint64 _mask;
@ -637,22 +647,25 @@ const InterfacesMetadata *GetInterfacesMetadata(uint64 mask);
class Interfaces {
public:
Interfaces(uint64 mask = 0) : _meta(GetInterfacesMetadata(mask)), _data(0) {
if (_meta->size) {
_data = malloc(_meta->size);
Interfaces(uint64 mask = 0) : _data(0) {
if (mask) {
const InterfacesMetadata *meta = GetInterfacesMetadata(mask);
int32 size = sizeof(const InterfacesMetadata *) + meta->size;
_data = malloc(size);
if (!_data) { // terminate if we can't allocate memory
throw "Can't allocate memory!";
}
for (int i = 0; i < _meta->last; ++i) {
int offset = _meta->offsets[i];
_meta() = meta;
for (int i = 0; i < meta->last; ++i) {
int offset = meta->offsets[i];
if (offset >= 0) {
try {
InterfaceWraps[i].Construct(_dataptrunsafe(offset), this);
} catch (...) {
while (i > 0) {
--i;
offset = _meta->offsets[--i];
offset = meta->offsets[--i];
if (offset >= 0) {
InterfaceWraps[i].Destruct(_dataptrunsafe(offset));
}
@ -663,10 +676,28 @@ public:
}
}
}
void UpdateInterfaces(uint64 mask = 0) {
if (!_data && !mask) return;
if (!_data || !_meta()->equals(mask)) {
Interfaces tmp(mask);
tmp.swap(*this);
if (_data && tmp._data) {
const InterfacesMetadata *meta = _meta(), *wasmeta = tmp._meta();
for (int i = 0; i < meta->last; ++i) {
int offset = meta->offsets[i], wasoffset = wasmeta->offsets[i];
if (offset >= 0 && wasoffset >= 0) {
InterfaceWraps[i].Assign(_dataptrunsafe(offset), tmp._dataptrunsafe(wasoffset));
}
}
}
}
}
~Interfaces() {
if (_data) {
for (int i = 0; i < _meta->last; ++i) {
int offset = _meta->offsets[i];
const InterfacesMetadata *meta = _meta();
for (int i = 0; i < meta->last; ++i) {
int offset = meta->offsets[i];
if (offset >= 0) {
InterfaceWraps[i].Destruct(_dataptrunsafe(offset));
}
@ -677,24 +708,33 @@ public:
template <typename Type>
Type *Get() {
return (Type*)_dataptr(_meta->offsets[Type::Index()]);
return static_cast<Type*>(_dataptr(_meta()->offsets[Type::Index()]));
}
template <typename Type>
const Type *Get() const {
return (const Type*)_dataptr(_meta->offsets[Type::Index()]);
return static_cast<const Type*>(_dataptr(_meta()->offsets[Type::Index()]));
}
private:
void *_dataptrunsafe(int skip) const {
return (char*)_data + skip;
return (char*)_data + sizeof(const InterfacesMetadata*) + skip;
}
void *_dataptr(int skip) const {
return (skip >= 0) ? _dataptrunsafe(skip) : 0;
}
const InterfacesMetadata *_meta;
const InterfacesMetadata *&_meta() const {
return *static_cast<const InterfacesMetadata**>(_data);
}
void *_data;
Interfaces(const Interfaces &other);
Interfaces &operator=(const Interfaces &other);
void swap(Interfaces &other) {
std::swap(_data, other._data);
}
};
template <typename R>

View File

@ -645,7 +645,7 @@ void Window::sendServiceHistoryRequest() {
int32 userFlags = MTPDuser::flag_first_name | MTPDuser::flag_phone | MTPDuser::flag_status | MTPDuser::flag_verified;
user = App::feedUsers(MTP_vector<MTPUser>(1, MTP_user(MTP_int(userFlags), MTP_int(ServiceUserId), MTPlong(), MTP_string("Telegram"), MTPstring(), MTPstring(), MTP_string("42777"), MTP_userProfilePhotoEmpty(), MTP_userStatusRecently(), MTPint(), MTPstring(), MTPstring())));
}
_serviceHistoryRequest = MTP::send(MTPmessages_GetHistory(user->input, MTP_int(0), MTP_int(0), MTP_int(1), MTP_int(0), MTP_int(0)), main->rpcDone(&MainWidget::serviceHistoryDone), main->rpcFail(&MainWidget::serviceHistoryFail));
_serviceHistoryRequest = MTP::send(MTPmessages_GetHistory(user->input, MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(1), MTP_int(0), MTP_int(0)), main->rpcDone(&MainWidget::serviceHistoryDone), main->rpcFail(&MainWidget::serviceHistoryFail));
}
void Window::setupMain(bool anim, const MTPUser *self) {