diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt index 9168bdd43b..5cd2bda889 100644 --- a/Telegram/Resources/style.txt +++ b/Telegram/Resources/style.txt @@ -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); diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index d36731ff79..ed66b1ba11 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -48,7 +48,6 @@ namespace { PhotosData photosData; VideosData videosData; - AudiosData audiosData; DocumentsData documentsData; typedef QHash 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()); } diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 2b224e07ca..c62278798d 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -37,7 +37,6 @@ class FileUploader; typedef QMap HistoryItemsMap; typedef QHash PhotoItems; typedef QHash VideoItems; -typedef QHash AudioItems; typedef QHash DocumentItems; typedef QHash WebPageItems; typedef QHash SharedContactItems; @@ -45,7 +44,6 @@ typedef QHash GifItems; typedef QHash PhotosData; typedef QHash VideosData; -typedef QHash AudiosData; typedef QHash 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 &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(); diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp index 7e65ac75fa..afc5e6bc07 100644 --- a/Telegram/SourceFiles/application.cpp +++ b/Telegram/SourceFiles/application.cpp @@ -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); diff --git a/Telegram/SourceFiles/audio.cpp b/Telegram/SourceFiles/audio.cpp index db981b3aa2..7771eb39e9 100644 --- a/Telegram/SourceFiles/audio.cpp +++ b/Telegram/SourceFiles/audio.cpp @@ -96,6 +96,7 @@ bool _checkALError() { Q_DECLARE_METATYPE(AudioMsgId); Q_DECLARE_METATYPE(SongMsgId); +Q_DECLARE_METATYPE(VoiceWaveform); void audioInit() { if (!capture) { capture = new AudioCapture(); @@ -206,6 +207,7 @@ void audioInit() { qRegisterMetaType(); qRegisterMetaType(); + qRegisterMetaType(); player = new AudioPlayer(); alcDevicePauseSOFT(audioDevice); @@ -368,8 +370,8 @@ void AudioPlayer::onStopped(const SongMsgId &song) { bool AudioPlayer::updateCurrentStarted(MediaOverviewType type, int32 pos) { Msg *data = 0; switch (type) { - case OverviewAudios: data = &_audioData[_audioCurrent]; break; - case OverviewDocuments: data = &_songData[_songCurrent]; break; + case OverviewVoiceFiles: data = &_audioData[_audioCurrent]; break; + case OverviewFiles: data = &_songData[_songCurrent]; break; } if (!data) return false; @@ -382,8 +384,8 @@ bool AudioPlayer::updateCurrentStarted(MediaOverviewType type, int32 pos) { if (!_checkALError()) { setStoppedState(data, AudioPlayerStoppedAtError); switch (type) { - case OverviewAudios: onError(_audioData[_audioCurrent].audio); break; - case OverviewDocuments: onError(_songData[_songCurrent].song); break; + case OverviewVoiceFiles: onError(_audioData[_audioCurrent].audio); break; + case OverviewFiles: onError(_songData[_songCurrent].song); break; } return false; } @@ -395,8 +397,8 @@ bool AudioPlayer::updateCurrentStarted(MediaOverviewType type, int32 pos) { bool AudioPlayer::fadedStop(MediaOverviewType type, bool *fadedStart) { Msg *current = 0; switch (type) { - case OverviewAudios: current = &_audioData[_audioCurrent]; break; - case OverviewDocuments: current = &_songData[_songCurrent]; break; + case OverviewVoiceFiles: current = &_audioData[_audioCurrent]; break; + case OverviewFiles: current = &_songData[_songCurrent]; break; } if (!current) return false; @@ -428,7 +430,7 @@ void AudioPlayer::play(const AudioMsgId &audio, int64 position) { bool fadedStart = false; AudioMsg *current = &_audioData[_audioCurrent]; if (current->audio != audio) { - if (fadedStop(OverviewAudios, &fadedStart)) { + if (fadedStop(OverviewVoiceFiles, &fadedStart)) { stopped = current->audio; } if (current->audio) { @@ -472,7 +474,7 @@ void AudioPlayer::play(const SongMsgId &song, int64 position) { bool fadedStart = false; SongMsg *current = &_songData[_songCurrent]; if (current->song != song) { - if (fadedStop(OverviewDocuments, &fadedStart)) { + if (fadedStop(OverviewFiles, &fadedStart)) { stopped = current->song; } if (current->song) { @@ -513,11 +515,11 @@ bool AudioPlayer::checkCurrentALError(MediaOverviewType type) { if (_checkALError()) return true; switch (type) { - case OverviewAudios: + case OverviewVoiceFiles: setStoppedState(&_audioData[_audioCurrent], AudioPlayerStoppedAtError); onError(_audioData[_audioCurrent].audio); break; - case OverviewDocuments: + case OverviewFiles: setStoppedState(&_songData[_songCurrent], AudioPlayerStoppedAtError); onError(_songData[_songCurrent].song); break; @@ -531,11 +533,11 @@ void AudioPlayer::pauseresume(MediaOverviewType type, bool fast) { Msg *current = 0; float64 suppressGain = 1.; switch (type) { - case OverviewAudios: + case OverviewVoiceFiles: current = &_audioData[_audioCurrent]; suppressGain = suppressAllGain; break; - case OverviewDocuments: + case OverviewFiles: current = &_songData[_songCurrent]; suppressGain = suppressSongGain * cSongVolume(); break; @@ -567,14 +569,14 @@ void AudioPlayer::pauseresume(MediaOverviewType type, bool fast) { alSourcePlay(current->source); if (!checkCurrentALError(type)) return; } - if (type == OverviewAudios) emit suppressSong(); + if (type == OverviewVoiceFiles) emit suppressSong(); } break; case AudioPlayerStarting: case AudioPlayerResuming: case AudioPlayerPlaying: current->state = AudioPlayerPausing; updateCurrentStarted(type); - if (type == OverviewAudios) emit unsuppressSong(); + if (type == OverviewVoiceFiles) emit unsuppressSong(); break; case AudioPlayerFinishing: current->state = AudioPlayerPausing; break; } @@ -584,18 +586,18 @@ void AudioPlayer::pauseresume(MediaOverviewType type, bool fast) { void AudioPlayer::seek(int64 position) { QMutexLocker lock(&playerMutex); - MediaOverviewType type = OverviewDocuments; + MediaOverviewType type = OverviewFiles; Msg *current = 0; float64 suppressGain = 1.; AudioMsgId audio; SongMsgId song; switch (type) { - case OverviewAudios: + case OverviewVoiceFiles: current = &_audioData[_audioCurrent]; audio = _audioData[_audioCurrent].audio; suppressGain = suppressAllGain; break; - case OverviewDocuments: + case OverviewFiles: current = &_songData[_songCurrent]; song = _songData[_songCurrent].song; suppressGain = suppressSongGain * cSongVolume(); @@ -629,7 +631,7 @@ void AudioPlayer::seek(int64 position) { case AudioPlayerPlaying: current->state = AudioPlayerPausing; updateCurrentStarted(type); - if (type == OverviewAudios) emit unsuppressSong(); + if (type == OverviewVoiceFiles) emit unsuppressSong(); break; case AudioPlayerFinishing: case AudioPlayerStopped: @@ -638,8 +640,8 @@ void AudioPlayer::seek(int64 position) { case AudioPlayerStoppedAtStart: lock.unlock(); switch (type) { - case OverviewAudios: if (audio) return play(audio, position); - case OverviewDocuments: if (song) return play(song, position); + case OverviewVoiceFiles: if (audio) return play(audio, position); + case OverviewFiles: if (song) return play(song, position); } } emit faderOnTimer(); @@ -647,7 +649,7 @@ void AudioPlayer::seek(int64 position) { void AudioPlayer::stop(MediaOverviewType type) { switch (type) { - case OverviewAudios: { + case OverviewVoiceFiles: { AudioMsgId current; { QMutexLocker lock(&playerMutex); @@ -657,7 +659,7 @@ void AudioPlayer::stop(MediaOverviewType type) { if (current) emit updated(current); } break; - case OverviewDocuments: { + case OverviewFiles: { SongMsgId current; { QMutexLocker lock(&playerMutex); @@ -754,8 +756,8 @@ void AudioPlayer::resumeDevice() { AudioCapture::AudioCapture() : _capture(new AudioCaptureInner(&_captureThread)) { connect(this, SIGNAL(captureOnStart()), _capture, SLOT(onStart())); connect(this, SIGNAL(captureOnStop(bool)), _capture, SLOT(onStop(bool))); - connect(_capture, SIGNAL(done(QByteArray,qint32)), this, SIGNAL(onDone(QByteArray,qint32))); - connect(_capture, SIGNAL(update(qint16,qint32)), this, SIGNAL(onUpdate(qint16,qint32))); + connect(_capture, SIGNAL(done(QByteArray,VoiceWaveform,qint32)), this, SIGNAL(onDone(QByteArray,VoiceWaveform,qint32))); + connect(_capture, SIGNAL(update(quint16,qint32)), this, SIGNAL(onUpdate(quint16,qint32))); connect(_capture, SIGNAL(error()), this, SIGNAL(onError())); connect(&_captureThread, SIGNAL(started()), _capture, SLOT(onInit())); connect(&_captureThread, SIGNAL(finished()), _capture, SLOT(deleteLater())); @@ -1109,19 +1111,18 @@ protected: }; -static const AVSampleFormat _toFormat = AV_SAMPLE_FMT_S16; -static const int64_t _toChannelLayout = AV_CH_LAYOUT_STEREO; -static const int32 _toChannels = 2; -class FFMpegLoader : public AudioPlayerLoader { +class AbstractFFMpegLoader : public AudioPlayerLoader { public: - FFMpegLoader(const FileLocation &file, const QByteArray &data) : AudioPlayerLoader(file, data), - freq(AudioVoiceMsgFrequency), fmt(AL_FORMAT_STEREO16), - sampleSize(2 * sizeof(short)), srcRate(AudioVoiceMsgFrequency), dstRate(AudioVoiceMsgFrequency), - maxResampleSamples(1024), dstSamplesData(0), len(0), - ioBuffer(0), ioContext(0), fmtContext(0), codec(0), codecContext(0), streamId(0), frame(0), swrContext(0), - _opened(false) { - frame = av_frame_alloc(); + AbstractFFMpegLoader(const FileLocation &file, const QByteArray &data) : AudioPlayerLoader(file, data) + , freq(AudioVoiceMsgFrequency) + , len(0) + , ioBuffer(0) + , ioContext(0) + , fmtContext(0) + , codec(0) + , streamId(0) + , _opened(false) { } bool open(qint64 position = 0) { @@ -1129,31 +1130,32 @@ public: return false; } + int res = 0; + char err[AV_ERROR_MAX_STRING_SIZE] = { 0 }; + ioBuffer = (uchar*)av_malloc(AVBlockSize); if (data.isEmpty()) { - ioContext = avio_alloc_context(ioBuffer, AVBlockSize, 0, static_cast(this), &FFMpegLoader::_read_file, 0, &FFMpegLoader::_seek_file); + ioContext = avio_alloc_context(ioBuffer, AVBlockSize, 0, reinterpret_cast(this), &AbstractFFMpegLoader::_read_file, 0, &AbstractFFMpegLoader::_seek_file); } else { - ioContext = avio_alloc_context(ioBuffer, AVBlockSize, 0, static_cast(this), &FFMpegLoader::_read_data, 0, &FFMpegLoader::_seek_data); + ioContext = avio_alloc_context(ioBuffer, AVBlockSize, 0, reinterpret_cast(this), &AbstractFFMpegLoader::_read_data, 0, &AbstractFFMpegLoader::_seek_data); } fmtContext = avformat_alloc_context(); if (!fmtContext) { - LOG(("Audio Error: Unable to avformat_alloc_context for file '%1', data size '%2'").arg(file.name()).arg(data.size())); + DEBUG_LOG(("Audio Read Error: Unable to avformat_alloc_context for file '%1', data size '%2'").arg(file.name()).arg(data.size())); return false; } fmtContext->pb = ioContext; - int res = 0; - char err[AV_ERROR_MAX_STRING_SIZE] = { 0 }; if ((res = avformat_open_input(&fmtContext, 0, 0, 0)) < 0) { ioBuffer = 0; - LOG(("Audio Error: Unable to avformat_open_input for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res))); + DEBUG_LOG(("Audio Read Error: Unable to avformat_open_input for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res))); return false; } _opened = true; if ((res = avformat_find_stream_info(fmtContext, 0)) < 0) { - LOG(("Audio Error: Unable to avformat_find_stream_info for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res))); + DEBUG_LOG(("Audio Read Error: Unable to avformat_find_stream_info for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res))); return false; } @@ -1163,20 +1165,130 @@ public: return false; } - // Get a pointer to the codec context for the audio stream - codecContext = fmtContext->streams[streamId]->codec; - av_opt_set_int(codecContext, "refcounted_frames", 1, 0); - if ((res = avcodec_open2(codecContext, codec, 0)) < 0) { - LOG(("Audio Error: Unable to avcodec_open2 for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res))); - return false; - } - - freq = codecContext->sample_rate; + freq = fmtContext->streams[streamId]->codec->sample_rate; if (fmtContext->streams[streamId]->duration == AV_NOPTS_VALUE) { len = (fmtContext->duration * freq) / AV_TIME_BASE; } else { len = (fmtContext->streams[streamId]->duration * freq * fmtContext->streams[streamId]->time_base.num) / fmtContext->streams[streamId]->time_base.den; } + + return true; + } + + int64 duration() { + return len; + } + + int32 frequency() { + return freq; + } + + ~AbstractFFMpegLoader() { + if (ioContext) av_free(ioContext); + if (_opened) { + avformat_close_input(&fmtContext); + } else if (ioBuffer) { + av_free(ioBuffer); + } + if (fmtContext) avformat_free_context(fmtContext); + } + +protected: + + int32 freq; + int64 len; + + uchar *ioBuffer; + AVIOContext *ioContext; + AVFormatContext *fmtContext; + AVCodec *codec; + int32 streamId; + + bool _opened; + +private: + + static int _read_data(void *opaque, uint8_t *buf, int buf_size) { + AbstractFFMpegLoader *l = reinterpret_cast(opaque); + + int32 nbytes = qMin(l->data.size() - l->dataPos, int32(buf_size)); + if (nbytes <= 0) { + return 0; + } + + memcpy(buf, l->data.constData() + l->dataPos, nbytes); + l->dataPos += nbytes; + return nbytes; + } + + static int64_t _seek_data(void *opaque, int64_t offset, int whence) { + AbstractFFMpegLoader *l = reinterpret_cast(opaque); + + int32 newPos = -1; + switch (whence) { + case SEEK_SET: newPos = offset; break; + case SEEK_CUR: newPos = l->dataPos + offset; break; + case SEEK_END: newPos = l->data.size() + offset; break; + } + if (newPos < 0 || newPos > l->data.size()) { + return -1; + } + l->dataPos = newPos; + return l->dataPos; + } + + static int _read_file(void *opaque, uint8_t *buf, int buf_size) { + AbstractFFMpegLoader *l = reinterpret_cast(opaque); + return int(l->f.read((char*)(buf), buf_size)); + } + + static int64_t _seek_file(void *opaque, int64_t offset, int whence) { + AbstractFFMpegLoader *l = reinterpret_cast(opaque); + + switch (whence) { + case SEEK_SET: return l->f.seek(offset) ? l->f.pos() : -1; + case SEEK_CUR: return l->f.seek(l->f.pos() + offset) ? l->f.pos() : -1; + case SEEK_END: return l->f.seek(l->f.size() + offset) ? l->f.pos() : -1; + } + return -1; + } +}; + +static const AVSampleFormat _toFormat = AV_SAMPLE_FMT_S16; +static const int64_t _toChannelLayout = AV_CH_LAYOUT_STEREO; +static const int32 _toChannels = 2; +class FFMpegLoader : public AbstractFFMpegLoader { +public: + + FFMpegLoader(const FileLocation &file, const QByteArray &data) : AbstractFFMpegLoader(file, data) + , sampleSize(2 * sizeof(uint16)) + , fmt(AL_FORMAT_STEREO16) + , srcRate(AudioVoiceMsgFrequency) + , dstRate(AudioVoiceMsgFrequency) + , maxResampleSamples(1024) + , dstSamplesData(0) + , codecContext(0) + , frame(0) + , swrContext(0) { + frame = av_frame_alloc(); + } + + bool open(qint64 position = 0) { + if (!AbstractFFMpegLoader::open(position)) { + return false; + } + + int res = 0; + char err[AV_ERROR_MAX_STRING_SIZE] = { 0 }; + + // Get a pointer to the codec context for the audio stream + av_opt_set_int(fmtContext->streams[streamId]->codec, "refcounted_frames", 1, 0); + if ((res = avcodec_open2(fmtContext->streams[streamId]->codec, codec, 0)) < 0) { + LOG(("Audio Error: Unable to avcodec_open2 for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res))); + return false; + } + codecContext = fmtContext->streams[streamId]->codec; + uint64_t layout = codecContext->channel_layout; inputFormat = codecContext->sample_fmt; switch (layout) { @@ -1185,7 +1297,7 @@ public: case AV_SAMPLE_FMT_U8: case AV_SAMPLE_FMT_U8P: fmt = AL_FORMAT_MONO8; sampleSize = 1; break; case AV_SAMPLE_FMT_S16: - case AV_SAMPLE_FMT_S16P: fmt = AL_FORMAT_MONO16; sampleSize = 2; break; + case AV_SAMPLE_FMT_S16P: fmt = AL_FORMAT_MONO16; sampleSize = sizeof(uint16); break; default: sampleSize = -1; // convert needed break; @@ -1193,8 +1305,8 @@ public: break; case AV_CH_LAYOUT_STEREO: switch (inputFormat) { - case AV_SAMPLE_FMT_U8: fmt = AL_FORMAT_STEREO8; sampleSize = sizeof(short); break; - case AV_SAMPLE_FMT_S16: fmt = AL_FORMAT_STEREO16; sampleSize = 2 * sizeof(short); break; + case AV_SAMPLE_FMT_U8: fmt = AL_FORMAT_STEREO8; sampleSize = 2; break; + case AV_SAMPLE_FMT_S16: fmt = AL_FORMAT_STEREO16; sampleSize = 2 * sizeof(uint16); break; default: sampleSize = -1; // convert needed break; @@ -1256,14 +1368,6 @@ public: return true; } - int64 duration() { - return len; - } - - int32 frequency() { - return freq; - } - int32 format() { return fmt; } @@ -1326,7 +1430,6 @@ public: } ~FFMpegLoader() { - if (ioContext) av_free(ioContext); if (codecContext) avcodec_close(codecContext); if (swrContext) swr_free(&swrContext); if (dstSamplesData) { @@ -1335,80 +1438,25 @@ public: } av_freep(&dstSamplesData); } - if (_opened) { - avformat_close_input(&fmtContext); - } else if (ioBuffer) { - av_free(ioBuffer); - } - if (fmtContext) avformat_free_context(fmtContext); av_frame_free(&frame); } +protected: + int32 sampleSize; + private: - int32 freq, fmt; - int32 sampleSize, srcRate, dstRate, maxResampleSamples; + int32 fmt; + int32 srcRate, dstRate, maxResampleSamples; uint8_t **dstSamplesData; - int64 len; - uchar *ioBuffer; - AVIOContext *ioContext; - AVFormatContext *fmtContext; - AVCodec *codec; AVCodecContext *codecContext; AVPacket avpkt; - int32 streamId; AVSampleFormat inputFormat; AVFrame *frame; SwrContext *swrContext; - bool _opened; - - static int _read_data(void *opaque, uint8_t *buf, int buf_size) { - FFMpegLoader *l = reinterpret_cast(opaque); - - int32 nbytes = qMin(l->data.size() - l->dataPos, int32(buf_size)); - if (nbytes <= 0) { - return 0; - } - - memcpy(buf, l->data.constData() + l->dataPos, nbytes); - l->dataPos += nbytes; - return nbytes; - } - - static int64_t _seek_data(void *opaque, int64_t offset, int whence) { - FFMpegLoader *l = reinterpret_cast(opaque); - - int32 newPos = -1; - switch (whence) { - case SEEK_SET: newPos = offset; break; - case SEEK_CUR: newPos = l->dataPos + offset; break; - case SEEK_END: newPos = l->data.size() + offset; break; - } - if (newPos < 0 || newPos > l->data.size()) { - return -1; - } - l->dataPos = newPos; - return l->dataPos; - } - - static int _read_file(void *opaque, uint8_t *buf, int buf_size) { - FFMpegLoader *l = reinterpret_cast(opaque); - return int(l->f.read((char*)(buf), buf_size)); - } - - static int64_t _seek_file(void *opaque, int64_t offset, int whence) { - FFMpegLoader *l = reinterpret_cast(opaque); - - switch (whence) { - case SEEK_SET: return l->f.seek(offset) ? l->f.pos() : -1; - case SEEK_CUR: return l->f.seek(l->f.pos() + offset) ? l->f.pos() : -1; - case SEEK_END: return l->f.seek(l->f.size() + offset) ? l->f.pos() : -1; - } - return -1; - } }; AudioPlayerLoaders::AudioPlayerLoaders(QThread *thread) : _audioLoader(0), _songLoader(0) { @@ -1436,7 +1484,7 @@ void AudioPlayerLoaders::onStart(const AudioMsgId &audio, qint64 position) { voice->_audioData[voice->_audioCurrent].loading = true; } - loadData(OverviewAudios, static_cast(&audio), position); + loadData(OverviewVoiceFiles, static_cast(&audio), position); } void AudioPlayerLoaders::onStart(const SongMsgId &song, qint64 position) { @@ -1452,13 +1500,13 @@ void AudioPlayerLoaders::onStart(const SongMsgId &song, qint64 position) { voice->_songData[voice->_songCurrent].loading = true; } - loadData(OverviewDocuments, static_cast(&song), position); + loadData(OverviewFiles, static_cast(&song), position); } void AudioPlayerLoaders::clear(MediaOverviewType type) { switch (type) { - case OverviewAudios: clearAudio(); break; - case OverviewDocuments: clearSong(); break; + case OverviewVoiceFiles: clearAudio(); break; + case OverviewFiles: clearSong(); break; } } @@ -1469,8 +1517,8 @@ void AudioPlayerLoaders::setStoppedState(AudioPlayer::Msg *m, AudioPlayerState s void AudioPlayerLoaders::emitError(MediaOverviewType type) { switch (type) { - case OverviewAudios: emit error(clearAudio()); break; - case OverviewDocuments: emit error(clearSong()); break; + case OverviewVoiceFiles: emit error(clearAudio()); break; + case OverviewFiles: emit error(clearSong()); break; } } @@ -1491,11 +1539,11 @@ SongMsgId AudioPlayerLoaders::clearSong() { } void AudioPlayerLoaders::onLoad(const AudioMsgId &audio) { - loadData(OverviewAudios, static_cast(&audio), 0); + loadData(OverviewVoiceFiles, static_cast(&audio), 0); } void AudioPlayerLoaders::onLoad(const SongMsgId &song) { - loadData(OverviewDocuments, static_cast(&song), 0); + loadData(OverviewFiles, static_cast(&song), 0); } void AudioPlayerLoaders::loadData(MediaOverviewType type, const void *objId, qint64 position) { @@ -1608,8 +1656,8 @@ void AudioPlayerLoaders::loadData(MediaOverviewType type, const void *objId, qin audioPlayer()->resumeDevice(); switch (type) { - case OverviewAudios: alSourcef(m->source, AL_GAIN, suppressAllGain); break; - case OverviewDocuments: alSourcef(m->source, AL_GAIN, suppressSongGain * cSongVolume()); break; + case OverviewVoiceFiles: alSourcef(m->source, AL_GAIN, suppressAllGain); break; + case OverviewFiles: alSourcef(m->source, AL_GAIN, suppressSongGain * cSongVolume()); break; } if (!_checkALError()) { setStoppedState(m, AudioPlayerStoppedAtError); @@ -1643,7 +1691,7 @@ AudioPlayerLoader *AudioPlayerLoaders::setupLoader(MediaOverviewType type, const AudioPlayer::Msg *m = 0; AudioPlayerLoader **l = 0; switch (type) { - case OverviewAudios: { + case OverviewVoiceFiles: { AudioPlayer::AudioMsg &msg(voice->_audioData[voice->_audioCurrent]); const AudioMsgId &audio(*static_cast(objId)); if (msg.audio != audio || !msg.loading) { @@ -1654,7 +1702,7 @@ AudioPlayerLoader *AudioPlayerLoaders::setupLoader(MediaOverviewType type, const l = &_audioLoader; isGoodId = (_audio == audio); } break; - case OverviewDocuments: { + case OverviewFiles: { AudioPlayer::SongMsg &msg(voice->_songData[voice->_songCurrent]); const SongMsgId &song(*static_cast(objId)); if (msg.song != song || !msg.loading) { @@ -1676,15 +1724,15 @@ AudioPlayerLoader *AudioPlayerLoaders::setupLoader(MediaOverviewType type, const delete *l; *l = 0; switch (type) { - case OverviewAudios: _audio = AudioMsgId(); break; - case OverviewDocuments: _song = SongMsgId(); break; + case OverviewVoiceFiles: _audio = AudioMsgId(); break; + case OverviewFiles: _song = SongMsgId(); break; } } if (!*l) { switch (type) { - case OverviewAudios: _audio = *static_cast(objId); break; - case OverviewDocuments: _song = *static_cast(objId); break; + case OverviewVoiceFiles: _audio = *static_cast(objId); break; + case OverviewFiles: _song = *static_cast(objId); break; } // QByteArray header = m->data.mid(0, 8); @@ -1737,13 +1785,13 @@ AudioPlayer::Msg *AudioPlayerLoaders::checkLoader(MediaOverviewType type) { AudioPlayer::Msg *m = 0; AudioPlayerLoader **l = 0; switch (type) { - case OverviewAudios: { + case OverviewVoiceFiles: { AudioPlayer::AudioMsg &msg(voice->_audioData[voice->_audioCurrent]); isGoodId = (msg.audio == _audio); l = &_audioLoader; m = &msg; } break; - case OverviewDocuments: { + case OverviewFiles: { AudioPlayer::SongMsg &msg(voice->_songData[voice->_songCurrent]); isGoodId = (msg.song == _song); l = &_songLoader; @@ -1799,10 +1847,30 @@ void AudioPlayerLoaders::onCancel(const SongMsgId &song) { } struct AudioCapturePrivate { - AudioCapturePrivate() : - device(0), fmt(0), ioBuffer(0), ioContext(0), fmtContext(0), stream(0), codec(0), codecContext(0), opened(false), - srcSamples(0), dstSamples(0), maxDstSamples(0), dstSamplesSize(0), fullSamples(0), srcSamplesData(0), dstSamplesData(0), - swrContext(0), lastUpdate(0), level(0), dataPos(0) { + AudioCapturePrivate() + : device(0) + , fmt(0) + , ioBuffer(0) + , ioContext(0) + , fmtContext(0) + , stream(0) + , codec(0) + , codecContext(0) + , opened(false) + , srcSamples(0) + , dstSamples(0) + , maxDstSamples(0) + , dstSamplesSize(0) + , fullSamples(0) + , srcSamplesData(0) + , dstSamplesData(0) + , swrContext(0) + , lastUpdate(0) + , levelMax(0) + , waveformMod(0) + , waveformEach(AudioVoiceMsgFrequency / 100) + , waveformPeak(0) + , dataPos(0) { } ALCdevice *device; AVOutputFormat *fmt; @@ -1819,11 +1887,15 @@ struct AudioCapturePrivate { SwrContext *swrContext; int32 lastUpdate; - int64 level; + uint16 levelMax; QByteArray data; int32 dataPos; + int64 waveformMod, waveformEach; + uint16 waveformPeak; + QVector waveform; + static int _read_data(void *opaque, uint8_t *buf, int buf_size) { AudioCapturePrivate *l = reinterpret_cast(opaque); @@ -2035,6 +2107,9 @@ void AudioCaptureInner::onStop(bool needResult) { d->fullSamples = 0; d->dataPos = 0; d->data.clear(); + d->waveformMod = 0; + d->waveformPeak = 0; + d->waveform.clear(); } else { float64 coef = 1. / fadeSamples, fadedFrom = 0; for (short *ptr = ((short*)_captured.data()) + capturedSamples, *end = ptr - fadeSamples; ptr != end; ++fadedFrom) { @@ -2056,6 +2131,9 @@ void AudioCaptureInner::onStop(bool needResult) { d->fullSamples = 0; d->dataPos = 0; d->data.clear(); + d->waveformMod = 0; + d->waveformPeak = 0; + d->waveform.clear(); } } } @@ -2068,7 +2146,37 @@ void AudioCaptureInner::onStop(bool needResult) { } QByteArray result = d->fullSamples ? d->data : QByteArray(); + VoiceWaveform waveform; qint32 samples = d->fullSamples; + if (samples && !d->waveform.isEmpty()) { + int64 count = d->waveform.size(), sum = 0; + if (count >= WaveformSamplesCount) { + QVector peaks; + peaks.reserve(WaveformSamplesCount); + + uint16 peak = 0; + for (int32 i = 0; i < count; ++i) { + uint16 sample = uint16(d->waveform.at(i)) * 256; + if (peak < sample) { + peak = sample; + } + sum += WaveformSamplesCount; + if (sum >= count) { + sum -= count; + peaks.push_back(peak); + peak = 0; + } + } + + int64 sum = std::accumulate(peaks.cbegin(), peaks.cend(), 0ULL); + peak = qMax(int32(sum * 1.8 / peaks.size()), 2500); + + waveform.resize(peaks.size()); + for (int32 i = 0, l = peaks.size(); i != l; ++i) { + waveform[i] = char(qMin(31U, uint32(qMin(peaks.at(i), peak)) * 31 / peak)); + } + } + } if (d->device) { alcCaptureStop(d->device); alcCaptureCloseDevice(d->device); @@ -2116,12 +2224,16 @@ void AudioCaptureInner::onStop(bool needResult) { d->codec = 0; d->lastUpdate = 0; - d->level = 0; + d->levelMax = 0; d->dataPos = 0; d->data.clear(); + + d->waveformMod = 0; + d->waveformPeak = 0; + d->waveform.clear(); } - if (needResult) emit done(result, samples); + if (needResult) emit done(result, waveform, samples); } void AudioCaptureInner::onTimeout() { @@ -2155,18 +2267,20 @@ void AudioCaptureInner::onTimeout() { int32 levelindex = d->fullSamples + (s / sizeof(short)); for (const short *ptr = (const short*)(_captured.constData() + s), *end = (const short*)(_captured.constData() + news); ptr < end; ++ptr, ++levelindex) { if (levelindex > skipSamples) { + uint16 value = qAbs(*ptr); if (levelindex < skipSamples + fadeSamples) { - d->level += qRound(qAbs(*ptr) * float64(levelindex - skipSamples) / fadeSamples); - } else { - d->level += qAbs(*ptr); + value = qRound(value * float64(levelindex - skipSamples) / fadeSamples); + } + if (d->levelMax < value) { + d->levelMax = value; } } } qint32 samplesFull = d->fullSamples + _captured.size() / sizeof(short), samplesSinceUpdate = samplesFull - d->lastUpdate; if (samplesSinceUpdate > AudioVoiceMsgUpdateView * AudioVoiceMsgFrequency / 1000) { - emit update(d->level / samplesSinceUpdate, samplesFull); + emit update(d->levelMax, samplesFull); d->lastUpdate = samplesFull; - d->level = 0; + d->levelMax = 0; } // Write frames int32 framesize = d->srcSamples * d->codecContext->channels * sizeof(short), encoded = 0; @@ -2206,7 +2320,7 @@ void AudioCaptureInner::writeFrame(int32 offset, int32 framesize) { if (d->fullSamples < skipSamples + fadeSamples) { int32 fadedCnt = qMin(samplesCnt, skipSamples + fadeSamples - d->fullSamples); float64 coef = 1. / fadeSamples, fadedFrom = d->fullSamples - skipSamples; - short *ptr = (short*)srcSamplesData[0], *zeroEnd = ptr + qMin(samplesCnt, qMax(0, skipSamples - d->fullSamples)), *end = ptr + fadedCnt; + short *ptr = srcSamplesDataChannel, *zeroEnd = ptr + qMin(samplesCnt, qMax(0, skipSamples - d->fullSamples)), *end = ptr + fadedCnt; for (; ptr != zeroEnd; ++ptr, ++fadedFrom) { *ptr = 0; } @@ -2215,6 +2329,19 @@ void AudioCaptureInner::writeFrame(int32 offset, int32 framesize) { } } + d->waveform.reserve(d->waveform.size() + (samplesCnt / d->waveformEach) + 1); + for (short *ptr = srcSamplesDataChannel, *end = ptr + samplesCnt; ptr != end; ++ptr) { + uint16 value = qAbs(*ptr); + if (d->waveformPeak < value) { + d->waveformPeak = value; + } + if (++d->waveformMod == d->waveformEach) { + d->waveformMod -= d->waveformEach; + d->waveform.push_back(uchar(d->waveformPeak / 256)); + d->waveformPeak = 0; + } + } + // Convert to final format d->dstSamples = av_rescale_rnd(swr_get_delay(d->swrContext, d->codecContext->sample_rate) + d->srcSamples, d->codecContext->sample_rate, d->codecContext->sample_rate, AV_ROUND_UP); @@ -2269,65 +2396,25 @@ void AudioCaptureInner::writeFrame(int32 offset, int32 framesize) { av_frame_free(&frame); } -class FFMpegAttributesReader : public AudioPlayerLoader { +class FFMpegAttributesReader : public AbstractFFMpegLoader { public: - FFMpegAttributesReader(const FileLocation &file, const QByteArray &data) : AudioPlayerLoader(file, data), - ioBuffer(0), ioContext(0), fmtContext(0), codec(0), streamId(0), - _opened(false) { + FFMpegAttributesReader(const FileLocation &file, const QByteArray &data) : AbstractFFMpegLoader(file, data) { } bool open(qint64 position = 0) { - if (!AudioPlayerLoader::openFile()) { + if (!AbstractFFMpegLoader::openFile()) { return false; } - ioBuffer = (uchar*)av_malloc(AVBlockSize); - if (data.isEmpty()) { - ioContext = avio_alloc_context(ioBuffer, AVBlockSize, 0, static_cast(this), &FFMpegAttributesReader::_read_file, 0, &FFMpegAttributesReader::_seek_file); - } else { - ioContext = avio_alloc_context(ioBuffer, AVBlockSize, 0, static_cast(this), &FFMpegAttributesReader::_read_data, 0, &FFMpegAttributesReader::_seek_data); - } - fmtContext = avformat_alloc_context(); - if (!fmtContext) { - DEBUG_LOG(("Audio Read Error: Unable to avformat_alloc_context for file '%1', data size '%2'").arg(fname).arg(data.size())); - return false; - } - fmtContext->pb = ioContext; - int res = 0; char err[AV_ERROR_MAX_STRING_SIZE] = { 0 }; - if ((res = avformat_open_input(&fmtContext, 0, 0, 0)) < 0) { - ioBuffer = 0; - DEBUG_LOG(("Audio Read Error: Unable to avformat_open_input for file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res))); + int videoStreamId = av_find_best_stream(fmtContext, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0); + if (videoStreamId >= 0) { + DEBUG_LOG(("Audio Read Error: Found video stream in file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(videoStreamId).arg(av_make_error_string(err, sizeof(err), streamId))); return false; } - _opened = true; - - if ((res = avformat_find_stream_info(fmtContext, 0)) < 0) { - DEBUG_LOG(("Audio Read Error: Unable to avformat_find_stream_info for file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res))); - return false; - } - - streamId = av_find_best_stream(fmtContext, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0); - if (streamId >= 0) { - DEBUG_LOG(("Audio Read Error: Found video stream in file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(streamId).arg(av_make_error_string(err, sizeof(err), streamId))); - return false; - } - - streamId = av_find_best_stream(fmtContext, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0); - if (streamId < 0) { - DEBUG_LOG(("Audio Read Error: Unable to av_find_best_stream for file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(streamId).arg(av_make_error_string(err, sizeof(err), streamId))); - return false; - } - - freq = fmtContext->streams[streamId]->codec->sample_rate; - if (fmtContext->streams[streamId]->duration == AV_NOPTS_VALUE) { - len = (fmtContext->duration * freq) / AV_TIME_BASE; - } else { - len = (fmtContext->streams[streamId]->duration * freq * fmtContext->streams[streamId]->time_base.num) / fmtContext->streams[streamId]->time_base.den; - } for (int32 i = 0, l = fmtContext->nb_streams; i < l; ++i) { AVStream *stream = fmtContext->streams[i]; @@ -2370,14 +2457,6 @@ public: //} } - int64 duration() { - return len; - } - - int32 frequency() { - return freq; - } - int32 format() { return 0; } @@ -2408,77 +2487,14 @@ public: } ~FFMpegAttributesReader() { - if (ioContext) av_free(ioContext); - if (_opened) { - avformat_close_input(&fmtContext); - } else if (ioBuffer) { - av_free(ioBuffer); - } - if (fmtContext) avformat_free_context(fmtContext); } private: - QString fname, data; - - int32 freq; - int64 len; QString _title, _performer; QImage _cover; QByteArray _coverBytes, _coverFormat; - uchar *ioBuffer; - AVIOContext *ioContext; - AVFormatContext *fmtContext; - AVCodec *codec; - int32 streamId; - - bool _opened; - - static int _read_data(void *opaque, uint8_t *buf, int buf_size) { - FFMpegAttributesReader *l = reinterpret_cast(opaque); - - int32 nbytes = qMin(l->data.size() - l->dataPos, int32(buf_size)); - if (nbytes <= 0) { - return 0; - } - - memcpy(buf, l->data.constData() + l->dataPos, nbytes); - l->dataPos += nbytes; - return nbytes; - } - - static int64_t _seek_data(void *opaque, int64_t offset, int whence) { - FFMpegAttributesReader *l = reinterpret_cast(opaque); - - int32 newPos = -1; - switch (whence) { - case SEEK_SET: newPos = offset; break; - case SEEK_CUR: newPos = l->dataPos + offset; break; - case SEEK_END: newPos = l->data.size() + offset; break; - } - if (newPos < 0 || newPos > l->data.size()) { - return -1; - } - l->dataPos = newPos; - return l->dataPos; - } - - static int _read_file(void *opaque, uint8_t *buf, int buf_size) { - FFMpegAttributesReader *l = reinterpret_cast(opaque); - return int(l->f.read((char*)(buf), buf_size)); - } - - static int64_t _seek_file(void *opaque, int64_t offset, int whence) { - FFMpegAttributesReader *l = reinterpret_cast(opaque); - - switch (whence) { - case SEEK_SET: return l->f.seek(offset) ? l->f.pos() : -1; - case SEEK_CUR: return l->f.seek(l->f.pos() + offset) ? l->f.pos() : -1; - case SEEK_END: return l->f.seek(l->f.size() + offset) ? l->f.pos() : -1; - } - return -1; - } }; MTPDocumentAttribute audioReadSongAttributes(const QString &fname, const QByteArray &data, QImage &cover, QByteArray &coverBytes, QByteArray &coverFormat) { @@ -2489,8 +2505,116 @@ MTPDocumentAttribute audioReadSongAttributes(const QString &fname, const QByteAr cover = reader.cover(); coverBytes = reader.coverBytes(); coverFormat = reader.coverFormat(); - return MTP_documentAttributeAudio(MTP_int(duration), MTP_string(reader.title()), MTP_string(reader.performer())); + return MTP_documentAttributeAudio(MTP_int(MTPDdocumentAttributeAudio::flag_title | MTPDdocumentAttributeAudio::flag_performer), MTP_int(duration), MTP_string(reader.title()), MTP_string(reader.performer()), MTPstring()); } } return MTP_documentAttributeFilename(MTP_string(fname)); } + +class FFMpegWaveformCounter : public FFMpegLoader { +public: + + FFMpegWaveformCounter(const FileLocation &file, const QByteArray &data) : FFMpegLoader(file, data) { + } + + bool open(qint64 position = 0) { + if (!FFMpegLoader::open(position)) { + return false; + } + + QByteArray buffer; + buffer.reserve(AudioVoiceMsgBufferSize); + int64 countbytes = sampleSize * duration(), processed = 0, sumbytes = 0; + if (duration() < WaveformSamplesCount) { + return false; + } + + QVector peaks; + peaks.reserve(WaveformSamplesCount); + + int32 fmt = format(); + uint16 peak = 0; + while (processed < countbytes) { + buffer.resize(0); + + int64 samples = 0; + int res = readMore(buffer, samples); + if (res < 0) { + break; + } + if (buffer.isEmpty()) { + continue; + } + + const char *data = buffer.data(); + if (fmt == AL_FORMAT_MONO8 || fmt == AL_FORMAT_STEREO8) { + for (int32 i = 0, l = buffer.size(); i + sizeof(uchar) <= l;) { + uint16 sample = qAbs((int32(*(uchar*)(data + i)) - 128) * 256); + if (peak < sample) { + peak = sample; + } + + i += sizeof(uchar); + sumbytes += WaveformSamplesCount; + if (sumbytes >= countbytes) { + sumbytes -= countbytes; + peaks.push_back(peak); + peak = 0; + } + } + } else if (fmt == AL_FORMAT_MONO16 || fmt == AL_FORMAT_STEREO16) { + for (int32 i = 0, l = buffer.size(); i + sizeof(uint16) <= l;) { + uint16 sample = qAbs(int32(*(int16*)(data + i))); + if (peak < sample) { + peak = sample; + } + + i += sizeof(uint16); + sumbytes += sizeof(uint16) * WaveformSamplesCount; + if (sumbytes >= countbytes) { + sumbytes -= countbytes; + peaks.push_back(peak); + peak = 0; + } + } + } + processed += sampleSize * samples; + } + if (sumbytes > 0 && peaks.size() < WaveformSamplesCount) { + peaks.push_back(peak); + } + + if (peaks.isEmpty()) { + return false; + } + + int64 sum = std::accumulate(peaks.cbegin(), peaks.cend(), 0ULL); + peak = qMax(int32(sum * 1.8 / peaks.size()), 2500); + + result.resize(peaks.size()); + for (int32 i = 0, l = peaks.size(); i != l; ++i) { + result[i] = char(qMin(31U, uint32(qMin(peaks.at(i), peak)) * 31 / peak)); + } + + return true; + } + + const VoiceWaveform &waveform() const { + return result; + } + + ~FFMpegWaveformCounter() { + } + +private: + VoiceWaveform result; + +}; + +VoiceWaveform audioCountWaveform(const FileLocation &file, const QByteArray &data) { + FFMpegWaveformCounter counter(file, data); + if (counter.open()) { + return counter.waveform(); + } + return VoiceWaveform(); +} diff --git a/Telegram/SourceFiles/audio.h b/Telegram/SourceFiles/audio.h index e21c273f78..f9259906e9 100644 --- a/Telegram/SourceFiles/audio.h +++ b/Telegram/SourceFiles/audio.h @@ -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); diff --git a/Telegram/SourceFiles/boxes/connectionbox.cpp b/Telegram/SourceFiles/boxes/connectionbox.cpp index a94fdd44db..27b2ce7ff4 100644 --- a/Telegram/SourceFiles/boxes/connectionbox.cpp +++ b/Telegram/SourceFiles/boxes/connectionbox.cpp @@ -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(); } diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h index f5797848c9..0878f1a6d7 100644 --- a/Telegram/SourceFiles/config.h +++ b/Telegram/SourceFiles/config.h @@ -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 diff --git a/Telegram/SourceFiles/fileuploader.cpp b/Telegram/SourceFiles/fileuploader.cpp index 607a2e91cc..c93f8dbb6a 100644 --- a/Telegram/SourceFiles/fileuploader.cpp +++ b/Telegram/SourceFiles/fileuploader.cpp @@ -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()); } } } diff --git a/Telegram/SourceFiles/fileuploader.h b/Telegram/SourceFiles/fileuploader.h index 895e7c677a..8e038fd9d1 100644 --- a/Telegram/SourceFiles/fileuploader.h +++ b/Telegram/SourceFiles/fileuploader.h @@ -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 dcMap; uint32 sentSize; uint32 sentSizes[MTPUploadSessionsCount]; - + FullMsgId uploading, _paused; Queue queue; Queue uploaded; diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 869ad41142..1fec50eeeb 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -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(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()) { + 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()) { + 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(); + create(captioned != 0); + if (HistoryDocumentNamed *named = Get()) { + if (const HistoryDocumentNamed *oin = other.Get()) { + 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()->_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()) { + 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(); + if (captioned && captioned->_caption.hasSkipBlock()) { + captioned->_caption.setSkipBlock(parent->skipBlockWidth(), parent->skipBlockHeight()); } - if (withThumb()) { + HistoryDocumentThumbed *thumbed = Get(); + 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()) { + _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(); + if (!captioned) { return HistoryFileMedia::resize(width, parent); } _width = qMin(width, _maxw); - bool wthumb = withThumb(); - if (wthumb) { + if (Get()) { _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()) { 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()) { + 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()) { + 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()) { 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()) { 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()) { 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()) { + result = lang(lng_in_dlg_audio); + } else { + const HistoryDocumentNamed *named = Get(); + result = (!named || named->_name.isEmpty()) ? lang(lng_in_dlg_file) : named->_name; + } + if (const HistoryDocumentCaptioned *captioned = Get()) { + 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() ? lng_in_dlg_audio : lng_in_dlg_file); + if (const HistoryDocumentNamed *named = Get()) { + if (!named->_name.isEmpty()) { + result.append(qsl(" : ")).append(named->_name); + } + } + if (const HistoryDocumentCaptioned *captioned = Get()) { + 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()) { + 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()) { + 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()) { + 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()) { + 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 ¤tTex _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(); diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index 9557904364..045144ccd1 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -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(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(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(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(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()) { + 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() ? 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 { diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 05c757ee77..baf099ec86 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -865,9 +865,9 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { HistoryItem *item = App::hoveredItem() ? App::hoveredItem() : App::hoveredLinkItem(); PhotoLink *lnkPhoto = dynamic_cast(_contextMenuLnk.data()); VideoLink *lnkVideo = dynamic_cast(_contextMenuLnk.data()); - AudioLink *lnkAudio = dynamic_cast(_contextMenuLnk.data()); DocumentLink *lnkDocument = dynamic_cast(_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(_contextMenuLnk.data())) { lnkVideo->video()->cancel(); - } else if (AudioLink *lnkAudio = dynamic_cast(_contextMenuLnk.data())) { - lnkAudio->audio()->cancel(); } else if (DocumentLink *lnkDocument = dynamic_cast(_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(_contextMenuLnk.data())) { already = lnkVideo->video()->already(true); - } else if (AudioLink *lnkAudio = dynamic_cast(_contextMenuLnk.data())) { - already = lnkAudio->audio()->already(true); } else if (DocumentLink *lnkDocument = dynamic_cast(_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(_contextMenuLnk.data()); - AudioLink *lnkAudio = dynamic_cast(_contextMenuLnk.data()); DocumentLink *lnkDocument = dynamic_cast(_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(_contextMenuLnk.data())) { VideoSaveLink::doSave(lnkVideo->video(), true); - } else if (AudioLink *lnkAudio = dynamic_cast(_contextMenuLnk.data())) { - AudioSaveLink::doSave(lnkAudio->audio(), true); } else if (DocumentLink *lnkDocument = dynamic_cast(_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(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(App::histItemById(newId)); - if (item) { - AudioData *audio = 0; - if (HistoryAudio *media = dynamic_cast(item->getMedia())) { - audio = media->audio(); - } - if (audio) { - uint64 randomId = MTP::nonce(); - 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(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); diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index eda8743a12..fcf4c53771 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -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(); diff --git a/Telegram/SourceFiles/layout.cpp b/Telegram/SourceFiles/layout.cpp index cf3c71c76a..8540930a8a 100644 --- a/Telegram/SourceFiles/layout.cpp +++ b/Telegram/SourceFiles/layout.cpp @@ -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; } diff --git a/Telegram/SourceFiles/layout.h b/Telegram/SourceFiles/layout.h index 39f9ecd149..7319613a1e 100644 --- a/Telegram/SourceFiles/layout.h +++ b/Telegram/SourceFiles/layout.h @@ -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; diff --git a/Telegram/SourceFiles/localimageloader.cpp b/Telegram/SourceFiles/localimageloader.cpp index d8137a8324..49d0cfaf26 100644 --- a/Telegram/SourceFiles/localimageloader.cpp +++ b/Telegram/SourceFiles/localimageloader.cpp @@ -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()) +FileLoadTask::FileLoadTask(const QByteArray &voice, int32 duration, const VoiceWaveform &waveform, const FileLoadTo &to) : _id(MTP::nonce()) , _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(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(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; } diff --git a/Telegram/SourceFiles/localimageloader.h b/Telegram/SourceFiles/localimageloader.h index 6078820afe..51edd73104 100644 --- a/Telegram/SourceFiles/localimageloader.h +++ b/Telegram/SourceFiles/localimageloader.h @@ -52,8 +52,8 @@ typedef QList ToPrepareMedias; typedef QMap 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; diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index 915bd35352..da64f2cb96 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -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); diff --git a/Telegram/SourceFiles/localstorage.h b/Telegram/SourceFiles/localstorage.h index 7bc16304bf..607ec9d0ff 100644 --- a/Telegram/SourceFiles/localstorage.h +++ b/Telegram/SourceFiles/localstorage.h @@ -144,6 +144,8 @@ namespace Local { int32 hasWebFiles(); qint64 storageWebFilesSize(); + void countVoiceWaveform(DocumentData *document); + void cancelTask(TaskId id); void writeStickers(); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 779a93bacc..d64f8004a6 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -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(); } diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index ffb357d81c..b20465ef8a 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -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); diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index 84af93dba5..a73603e016 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -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(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(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(media)->photo()->download(); break; - case MediaTypeDocument: + case MediaTypeFile: case MediaTypeGif: { DocumentData *doc = media->getDocument(); doc->thumb->load(); diff --git a/Telegram/SourceFiles/mtproto/mtpCoreTypes.h b/Telegram/SourceFiles/mtproto/mtpCoreTypes.h index 60d05a96aa..b0059077c1 100644 --- a/Telegram/SourceFiles/mtproto/mtpCoreTypes.h +++ b/Telegram/SourceFiles/mtproto/mtpCoreTypes.h @@ -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 class MTPBoxed : public bareT { diff --git a/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp b/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp index e7c7f20c97..bfbababece 100644 --- a/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp +++ b/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp @@ -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; } diff --git a/Telegram/SourceFiles/mtproto/mtpFileLoader.h b/Telegram/SourceFiles/mtproto/mtpFileLoader.h index d9f06aec1b..9446c979b5 100644 --- a/Telegram/SourceFiles/mtproto/mtpFileLoader.h +++ b/Telegram/SourceFiles/mtproto/mtpFileLoader.h @@ -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 diff --git a/Telegram/SourceFiles/mtproto/mtpScheme.cpp b/Telegram/SourceFiles/mtproto/mtpScheme.cpp index aa213c7eda..4da8bb3337 100644 --- a/Telegram/SourceFiles/mtproto/mtpScheme.cpp +++ b/Telegram/SourceFiles/mtproto/mtpScheme.cpp @@ -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); diff --git a/Telegram/SourceFiles/mtproto/mtpScheme.h b/Telegram/SourceFiles/mtproto/mtpScheme.h index 09450332c4..98bcc93e0e 100644 --- a/Telegram/SourceFiles/mtproto/mtpScheme.h +++ b/Telegram/SourceFiles/mtproto/mtpScheme.h @@ -90,8 +90,6 @@ enum { mtpc_inputMediaUploadedVideo = 0x82713fdf, mtpc_inputMediaUploadedThumbVideo = 0x7780ddf9, mtpc_inputMediaVideo = 0x936a4ebd, - mtpc_inputMediaUploadedAudio = 0x4e498cab, - mtpc_inputMediaAudio = 0x89938781, mtpc_inputMediaUploadedDocument = 0x1d89306d, mtpc_inputMediaUploadedThumbDocument = 0xad613491, mtpc_inputMediaDocument = 0x1a77f29c, @@ -109,7 +107,6 @@ enum { mtpc_inputFileLocation = 0x14637196, mtpc_inputVideoFileLocation = 0x3d0364ec, mtpc_inputEncryptedFileLocation = 0xf5235d55, - mtpc_inputAudioFileLocation = 0x74dc404d, mtpc_inputDocumentFileLocation = 0x4e45abe9, mtpc_inputPhotoCropAuto = 0xade6b004, mtpc_inputPhotoCrop = 0xd9915325, @@ -163,7 +160,6 @@ enum { mtpc_messageMediaContact = 0x5e7d2f39, mtpc_messageMediaUnsupported = 0x9f84f49e, mtpc_messageMediaDocument = 0xf3e02ea8, - mtpc_messageMediaAudio = 0xc6b68300, mtpc_messageMediaWebPage = 0xa32dd600, mtpc_messageMediaVenue = 0x7912b71f, mtpc_messageActionEmpty = 0xb6aef7b0, @@ -214,7 +210,6 @@ enum { mtpc_contact = 0xf911c994, mtpc_importedContact = 0xd0028438, mtpc_contactBlocked = 0x561bc879, - mtpc_contactSuggested = 0x3de191a1, mtpc_contactStatus = 0xd3680c61, mtpc_contacts_link = 0x3ace484c, mtpc_contacts_contactsNotModified = 0xb74ba9d2, @@ -222,7 +217,6 @@ enum { mtpc_contacts_importedContacts = 0xad524315, mtpc_contacts_blocked = 0x1c138d15, mtpc_contacts_blockedSlice = 0x900802a1, - mtpc_contacts_suggested = 0x5649dcc5, mtpc_messages_dialogs = 0x15ba6c40, mtpc_messages_dialogsSlice = 0x71e094f3, mtpc_messages_messages = 0x8c718e87, @@ -237,10 +231,10 @@ enum { mtpc_inputMessagesFilterPhotoVideo = 0x56e9f0e4, mtpc_inputMessagesFilterPhotoVideoDocuments = 0xd95e73bb, mtpc_inputMessagesFilterDocument = 0x9eddf188, - mtpc_inputMessagesFilterAudio = 0xcfc87522, - mtpc_inputMessagesFilterAudioDocuments = 0x5afbf764, mtpc_inputMessagesFilterUrl = 0x7ef0dd87, mtpc_inputMessagesFilterGif = 0xffc86587, + mtpc_inputMessagesFilterVoice = 0x50f5c392, + mtpc_inputMessagesFilterMusic = 0x3751b49e, mtpc_updateNewMessage = 0x1f2b0afd, mtpc_updateMessageID = 0x4e90bfd6, mtpc_updateDeleteMessages = 0xa20db0e5, @@ -283,6 +277,7 @@ enum { mtpc_updateStickerSets = 0x43ae3dec, mtpc_updateSavedGifs = 0x9375341e, mtpc_updateBotInlineQuery = 0xc01eea08, + mtpc_updateBotInlineSend = 0xf69e113, mtpc_updates_state = 0xa56c2a3e, mtpc_updates_differenceEmpty = 0x5d75a138, mtpc_updates_difference = 0xf49ca0, @@ -322,12 +317,8 @@ enum { mtpc_messages_dhConfig = 0x2c221edd, mtpc_messages_sentEncryptedMessage = 0x560f8935, mtpc_messages_sentEncryptedFile = 0x9493ff32, - mtpc_inputAudioEmpty = 0xd95adc84, - mtpc_inputAudio = 0x77d440ff, mtpc_inputDocumentEmpty = 0x72f0eaae, mtpc_inputDocument = 0x18798952, - mtpc_audioEmpty = 0x586988d8, - mtpc_audio = 0xf9e35055, mtpc_documentEmpty = 0x36f8c871, mtpc_document = 0xf9a39f4f, mtpc_help_support = 0x17c6b5f6, @@ -347,7 +338,9 @@ enum { mtpc_sendMessageChooseContactAction = 0x628cbc6f, mtpc_contacts_found = 0x1aa1f784, mtpc_inputPrivacyKeyStatusTimestamp = 0x4f96cb18, + mtpc_inputPrivacyKeyChatInvite = 0xbdfb0426, mtpc_privacyKeyStatusTimestamp = 0xbc2eab30, + mtpc_privacyKeyChatInvite = 0x500e6dfa, mtpc_inputPrivacyValueAllowContacts = 0xd09e07b, mtpc_inputPrivacyValueAllowAll = 0x184b35ce, mtpc_inputPrivacyValueAllowUsers = 0x131cc67f, @@ -367,7 +360,7 @@ enum { mtpc_documentAttributeAnimated = 0x11b58939, mtpc_documentAttributeSticker = 0x3a556302, mtpc_documentAttributeVideo = 0x5910cccb, - mtpc_documentAttributeAudio = 0xded218e0, + mtpc_documentAttributeAudio = 0x9852f9c6, mtpc_documentAttributeFilename = 0x15590068, mtpc_messages_stickersNotModified = 0xf1749a22, mtpc_messages_stickers = 0x8a8ecd32, @@ -388,7 +381,7 @@ enum { mtpc_account_noPassword = 0x96dabc18, mtpc_account_password = 0x7c18141c, mtpc_account_passwordSettings = 0xb7b72ab3, - mtpc_account_passwordInputSettings = 0xbcfc532c, + mtpc_account_passwordInputSettings = 0x86916deb, mtpc_auth_passwordRecovery = 0x137948a5, mtpc_receivedNotifyMessage = 0xa384b779, mtpc_chatInviteEmpty = 0x69df3769, @@ -512,7 +505,6 @@ enum { mtpc_contacts_getStatuses = 0xc4a353ee, mtpc_contacts_getContacts = 0x22c6aa08, mtpc_contacts_importContacts = 0xda30b32d, - mtpc_contacts_getSuggested = 0xcd773428, mtpc_contacts_deleteContact = 0x8e953744, mtpc_contacts_deleteContacts = 0x59ab389e, mtpc_contacts_block = 0x332b49fc, @@ -524,7 +516,7 @@ enum { mtpc_contacts_resolveUsername = 0xf93ccba3, mtpc_messages_getMessages = 0x4222fa74, mtpc_messages_getDialogs = 0x6b47f94d, - mtpc_messages_getHistory = 0x8a8ec2da, + mtpc_messages_getHistory = 0xafa92846, mtpc_messages_search = 0xd4569248, mtpc_messages_readHistory = 0xe306d3a, mtpc_messages_deleteHistory = 0xb7c13bd9, @@ -597,7 +589,7 @@ enum { mtpc_help_getAppChangelog = 0x5bab7fb2, mtpc_help_getTermsOfService = 0x37d78f83, mtpc_channels_getDialogs = 0xa9d3d249, - mtpc_channels_getImportantHistory = 0xddb929cb, + mtpc_channels_getImportantHistory = 0x8f494bb2, mtpc_channels_readHistory = 0xcc104937, mtpc_channels_deleteMessages = 0x84c1fd4e, mtpc_channels_deleteUserHistory = 0xd10dd71b, @@ -620,7 +612,8 @@ enum { mtpc_channels_inviteToChannel = 0x199f3a6c, mtpc_channels_kickFromChannel = 0xa672de14, mtpc_channels_exportInvite = 0xc7560885, - mtpc_channels_deleteChannel = 0xc0111fe3 + mtpc_channels_deleteChannel = 0xc0111fe3, + mtpc_channels_toggleInvites = 0x49609307 }; // Type forward declarations @@ -725,8 +718,6 @@ class MTPDinputMediaContact; class MTPDinputMediaUploadedVideo; class MTPDinputMediaUploadedThumbVideo; class MTPDinputMediaVideo; -class MTPDinputMediaUploadedAudio; -class MTPDinputMediaAudio; class MTPDinputMediaUploadedDocument; class MTPDinputMediaUploadedThumbDocument; class MTPDinputMediaDocument; @@ -750,7 +741,6 @@ class MTPinputFileLocation; class MTPDinputFileLocation; class MTPDinputVideoFileLocation; class MTPDinputEncryptedFileLocation; -class MTPDinputAudioFileLocation; class MTPDinputDocumentFileLocation; class MTPinputPhotoCrop; @@ -815,7 +805,6 @@ class MTPDmessageMediaVideo; class MTPDmessageMediaGeo; class MTPDmessageMediaContact; class MTPDmessageMediaDocument; -class MTPDmessageMediaAudio; class MTPDmessageMediaWebPage; class MTPDmessageMediaVenue; @@ -895,9 +884,6 @@ class MTPDimportedContact; class MTPcontactBlocked; class MTPDcontactBlocked; -class MTPcontactSuggested; -class MTPDcontactSuggested; - class MTPcontactStatus; class MTPDcontactStatus; @@ -914,9 +900,6 @@ class MTPcontacts_blocked; class MTPDcontacts_blocked; class MTPDcontacts_blockedSlice; -class MTPcontacts_suggested; -class MTPDcontacts_suggested; - class MTPmessages_dialogs; class MTPDmessages_dialogs; class MTPDmessages_dialogsSlice; @@ -978,6 +961,7 @@ class MTPDupdateChatParticipantAdmin; class MTPDupdateNewStickerSet; class MTPDupdateStickerSetsOrder; class MTPDupdateBotInlineQuery; +class MTPDupdateBotInlineSend; class MTPupdates_state; class MTPDupdates_state; @@ -1050,16 +1034,9 @@ class MTPmessages_sentEncryptedMessage; class MTPDmessages_sentEncryptedMessage; class MTPDmessages_sentEncryptedFile; -class MTPinputAudio; -class MTPDinputAudio; - class MTPinputDocument; class MTPDinputDocument; -class MTPaudio; -class MTPDaudioEmpty; -class MTPDaudio; - class MTPdocument; class MTPDdocumentEmpty; class MTPDdocument; @@ -1344,13 +1321,11 @@ typedef MTPBoxed MTPUserFull; typedef MTPBoxed MTPContact; typedef MTPBoxed MTPImportedContact; typedef MTPBoxed MTPContactBlocked; -typedef MTPBoxed MTPContactSuggested; typedef MTPBoxed MTPContactStatus; typedef MTPBoxed MTPcontacts_Link; typedef MTPBoxed MTPcontacts_Contacts; typedef MTPBoxed MTPcontacts_ImportedContacts; typedef MTPBoxed MTPcontacts_Blocked; -typedef MTPBoxed MTPcontacts_Suggested; typedef MTPBoxed MTPmessages_Dialogs; typedef MTPBoxed MTPmessages_Messages; typedef MTPBoxed MTPmessages_Chats; @@ -1376,9 +1351,7 @@ typedef MTPBoxed MTPInputEncryptedFile; typedef MTPBoxed MTPEncryptedMessage; typedef MTPBoxed MTPmessages_DhConfig; typedef MTPBoxed MTPmessages_SentEncryptedMessage; -typedef MTPBoxed MTPInputAudio; typedef MTPBoxed MTPInputDocument; -typedef MTPBoxed MTPAudio; typedef MTPBoxed MTPDocument; typedef MTPBoxed MTPhelp_Support; typedef MTPBoxed MTPNotifyPeer; @@ -2592,30 +2565,6 @@ public: return *(const MTPDinputMediaVideo*)data; } - MTPDinputMediaUploadedAudio &_inputMediaUploadedAudio() { - if (!data) throw mtpErrorUninitialized(); - if (_type != mtpc_inputMediaUploadedAudio) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaUploadedAudio); - split(); - return *(MTPDinputMediaUploadedAudio*)data; - } - const MTPDinputMediaUploadedAudio &c_inputMediaUploadedAudio() const { - if (!data) throw mtpErrorUninitialized(); - if (_type != mtpc_inputMediaUploadedAudio) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaUploadedAudio); - return *(const MTPDinputMediaUploadedAudio*)data; - } - - MTPDinputMediaAudio &_inputMediaAudio() { - if (!data) throw mtpErrorUninitialized(); - if (_type != mtpc_inputMediaAudio) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaAudio); - split(); - return *(MTPDinputMediaAudio*)data; - } - const MTPDinputMediaAudio &c_inputMediaAudio() const { - if (!data) throw mtpErrorUninitialized(); - if (_type != mtpc_inputMediaAudio) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaAudio); - return *(const MTPDinputMediaAudio*)data; - } - MTPDinputMediaUploadedDocument &_inputMediaUploadedDocument() { if (!data) throw mtpErrorUninitialized(); if (_type != mtpc_inputMediaUploadedDocument) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaUploadedDocument); @@ -2692,8 +2641,6 @@ private: explicit MTPinputMedia(MTPDinputMediaUploadedVideo *_data); explicit MTPinputMedia(MTPDinputMediaUploadedThumbVideo *_data); explicit MTPinputMedia(MTPDinputMediaVideo *_data); - explicit MTPinputMedia(MTPDinputMediaUploadedAudio *_data); - explicit MTPinputMedia(MTPDinputMediaAudio *_data); explicit MTPinputMedia(MTPDinputMediaUploadedDocument *_data); explicit MTPinputMedia(MTPDinputMediaUploadedThumbDocument *_data); explicit MTPinputMedia(MTPDinputMediaDocument *_data); @@ -2708,8 +2655,6 @@ private: friend MTPinputMedia MTP_inputMediaUploadedVideo(const MTPInputFile &_file, MTPint _duration, MTPint _w, MTPint _h, const MTPstring &_mime_type, const MTPstring &_caption); friend MTPinputMedia MTP_inputMediaUploadedThumbVideo(const MTPInputFile &_file, const MTPInputFile &_thumb, MTPint _duration, MTPint _w, MTPint _h, const MTPstring &_mime_type, const MTPstring &_caption); friend MTPinputMedia MTP_inputMediaVideo(const MTPInputVideo &_id, const MTPstring &_caption); - friend MTPinputMedia MTP_inputMediaUploadedAudio(const MTPInputFile &_file, MTPint _duration, const MTPstring &_mime_type); - friend MTPinputMedia MTP_inputMediaAudio(const MTPInputAudio &_id); friend MTPinputMedia MTP_inputMediaUploadedDocument(const MTPInputFile &_file, const MTPstring &_mime_type, const MTPVector &_attributes, const MTPstring &_caption); friend MTPinputMedia MTP_inputMediaUploadedThumbDocument(const MTPInputFile &_file, const MTPInputFile &_thumb, const MTPstring &_mime_type, const MTPVector &_attributes, const MTPstring &_caption); friend MTPinputMedia MTP_inputMediaDocument(const MTPInputDocument &_id, const MTPstring &_caption); @@ -2930,18 +2875,6 @@ public: return *(const MTPDinputEncryptedFileLocation*)data; } - MTPDinputAudioFileLocation &_inputAudioFileLocation() { - if (!data) throw mtpErrorUninitialized(); - if (_type != mtpc_inputAudioFileLocation) throw mtpErrorWrongTypeId(_type, mtpc_inputAudioFileLocation); - split(); - return *(MTPDinputAudioFileLocation*)data; - } - const MTPDinputAudioFileLocation &c_inputAudioFileLocation() const { - if (!data) throw mtpErrorUninitialized(); - if (_type != mtpc_inputAudioFileLocation) throw mtpErrorWrongTypeId(_type, mtpc_inputAudioFileLocation); - return *(const MTPDinputAudioFileLocation*)data; - } - MTPDinputDocumentFileLocation &_inputDocumentFileLocation() { if (!data) throw mtpErrorUninitialized(); if (_type != mtpc_inputDocumentFileLocation) throw mtpErrorWrongTypeId(_type, mtpc_inputDocumentFileLocation); @@ -2966,13 +2899,11 @@ private: explicit MTPinputFileLocation(MTPDinputFileLocation *_data); explicit MTPinputFileLocation(MTPDinputVideoFileLocation *_data); explicit MTPinputFileLocation(MTPDinputEncryptedFileLocation *_data); - explicit MTPinputFileLocation(MTPDinputAudioFileLocation *_data); explicit MTPinputFileLocation(MTPDinputDocumentFileLocation *_data); friend MTPinputFileLocation MTP_inputFileLocation(const MTPlong &_volume_id, MTPint _local_id, const MTPlong &_secret); friend MTPinputFileLocation MTP_inputVideoFileLocation(const MTPlong &_id, const MTPlong &_access_hash); friend MTPinputFileLocation MTP_inputEncryptedFileLocation(const MTPlong &_id, const MTPlong &_access_hash); - friend MTPinputFileLocation MTP_inputAudioFileLocation(const MTPlong &_id, const MTPlong &_access_hash); friend MTPinputFileLocation MTP_inputDocumentFileLocation(const MTPlong &_id, const MTPlong &_access_hash); mtpTypeId _type; @@ -3772,18 +3703,6 @@ public: return *(const MTPDmessageMediaDocument*)data; } - MTPDmessageMediaAudio &_messageMediaAudio() { - if (!data) throw mtpErrorUninitialized(); - if (_type != mtpc_messageMediaAudio) throw mtpErrorWrongTypeId(_type, mtpc_messageMediaAudio); - split(); - return *(MTPDmessageMediaAudio*)data; - } - const MTPDmessageMediaAudio &c_messageMediaAudio() const { - if (!data) throw mtpErrorUninitialized(); - if (_type != mtpc_messageMediaAudio) throw mtpErrorWrongTypeId(_type, mtpc_messageMediaAudio); - return *(const MTPDmessageMediaAudio*)data; - } - MTPDmessageMediaWebPage &_messageMediaWebPage() { if (!data) throw mtpErrorUninitialized(); if (_type != mtpc_messageMediaWebPage) throw mtpErrorWrongTypeId(_type, mtpc_messageMediaWebPage); @@ -3822,7 +3741,6 @@ private: explicit MTPmessageMedia(MTPDmessageMediaGeo *_data); explicit MTPmessageMedia(MTPDmessageMediaContact *_data); explicit MTPmessageMedia(MTPDmessageMediaDocument *_data); - explicit MTPmessageMedia(MTPDmessageMediaAudio *_data); explicit MTPmessageMedia(MTPDmessageMediaWebPage *_data); explicit MTPmessageMedia(MTPDmessageMediaVenue *_data); @@ -3833,7 +3751,6 @@ private: friend MTPmessageMedia MTP_messageMediaContact(const MTPstring &_phone_number, const MTPstring &_first_name, const MTPstring &_last_name, MTPint _user_id); friend MTPmessageMedia MTP_messageMediaUnsupported(); friend MTPmessageMedia MTP_messageMediaDocument(const MTPDocument &_document, const MTPstring &_caption); - friend MTPmessageMedia MTP_messageMediaAudio(const MTPAudio &_audio); friend MTPmessageMedia MTP_messageMediaWebPage(const MTPWebPage &_webpage); friend MTPmessageMedia MTP_messageMediaVenue(const MTPGeoPoint &_geo, const MTPstring &_title, const MTPstring &_address, const MTPstring &_provider, const MTPstring &_venue_id); @@ -4766,37 +4683,6 @@ private: }; typedef MTPBoxed MTPContactBlocked; -class MTPcontactSuggested : private mtpDataOwner { -public: - MTPcontactSuggested(); - MTPcontactSuggested(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contactSuggested) : mtpDataOwner(0) { - read(from, end, cons); - } - - MTPDcontactSuggested &_contactSuggested() { - if (!data) throw mtpErrorUninitialized(); - split(); - return *(MTPDcontactSuggested*)data; - } - const MTPDcontactSuggested &c_contactSuggested() const { - if (!data) throw mtpErrorUninitialized(); - return *(const MTPDcontactSuggested*)data; - } - - uint32 innerLength() const; - mtpTypeId type() const; - void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contactSuggested); - void write(mtpBuffer &to) const; - - typedef void ResponseType; - -private: - explicit MTPcontactSuggested(MTPDcontactSuggested *_data); - - friend MTPcontactSuggested MTP_contactSuggested(MTPint _user_id, MTPint _mutual_contacts); -}; -typedef MTPBoxed MTPContactSuggested; - class MTPcontactStatus : private mtpDataOwner { public: MTPcontactStatus(); @@ -4979,37 +4865,6 @@ private: }; typedef MTPBoxed MTPcontacts_Blocked; -class MTPcontacts_suggested : private mtpDataOwner { -public: - MTPcontacts_suggested(); - MTPcontacts_suggested(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_suggested) : mtpDataOwner(0) { - read(from, end, cons); - } - - MTPDcontacts_suggested &_contacts_suggested() { - if (!data) throw mtpErrorUninitialized(); - split(); - return *(MTPDcontacts_suggested*)data; - } - const MTPDcontacts_suggested &c_contacts_suggested() const { - if (!data) throw mtpErrorUninitialized(); - return *(const MTPDcontacts_suggested*)data; - } - - uint32 innerLength() const; - mtpTypeId type() const; - void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_suggested); - void write(mtpBuffer &to) const; - - typedef void ResponseType; - -private: - explicit MTPcontacts_suggested(MTPDcontacts_suggested *_data); - - friend MTPcontacts_suggested MTP_contacts_suggested(const MTPVector &_results, const MTPVector &_users); -}; -typedef MTPBoxed MTPcontacts_Suggested; - class MTPmessages_dialogs : private mtpDataOwner { public: MTPmessages_dialogs() : mtpDataOwner(0), _type(0) { @@ -5243,10 +5098,10 @@ private: friend MTPmessagesFilter MTP_inputMessagesFilterPhotoVideo(); friend MTPmessagesFilter MTP_inputMessagesFilterPhotoVideoDocuments(); friend MTPmessagesFilter MTP_inputMessagesFilterDocument(); - friend MTPmessagesFilter MTP_inputMessagesFilterAudio(); - friend MTPmessagesFilter MTP_inputMessagesFilterAudioDocuments(); friend MTPmessagesFilter MTP_inputMessagesFilterUrl(); friend MTPmessagesFilter MTP_inputMessagesFilterGif(); + friend MTPmessagesFilter MTP_inputMessagesFilterVoice(); + friend MTPmessagesFilter MTP_inputMessagesFilterMusic(); mtpTypeId _type; }; @@ -5740,6 +5595,18 @@ public: return *(const MTPDupdateBotInlineQuery*)data; } + MTPDupdateBotInlineSend &_updateBotInlineSend() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateBotInlineSend) throw mtpErrorWrongTypeId(_type, mtpc_updateBotInlineSend); + split(); + return *(MTPDupdateBotInlineSend*)data; + } + const MTPDupdateBotInlineSend &c_updateBotInlineSend() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_updateBotInlineSend) throw mtpErrorWrongTypeId(_type, mtpc_updateBotInlineSend); + return *(const MTPDupdateBotInlineSend*)data; + } + uint32 innerLength() const; mtpTypeId type() const; void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); @@ -5789,6 +5656,7 @@ private: explicit MTPupdate(MTPDupdateNewStickerSet *_data); explicit MTPupdate(MTPDupdateStickerSetsOrder *_data); explicit MTPupdate(MTPDupdateBotInlineQuery *_data); + explicit MTPupdate(MTPDupdateBotInlineSend *_data); friend MTPupdate MTP_updateNewMessage(const MTPMessage &_message, MTPint _pts, MTPint _pts_count); friend MTPupdate MTP_updateMessageID(MTPint _id, const MTPlong &_random_id); @@ -5832,6 +5700,7 @@ private: friend MTPupdate MTP_updateStickerSets(); friend MTPupdate MTP_updateSavedGifs(); friend MTPupdate MTP_updateBotInlineQuery(const MTPlong &_query_id, MTPint _user_id, const MTPstring &_query, const MTPstring &_offset); + friend MTPupdate MTP_updateBotInlineSend(MTPint _user_id, const MTPstring &_query, const MTPstring &_id); mtpTypeId _type; }; @@ -6697,44 +6566,6 @@ private: }; typedef MTPBoxed MTPmessages_SentEncryptedMessage; -class MTPinputAudio : private mtpDataOwner { -public: - MTPinputAudio() : mtpDataOwner(0), _type(0) { - } - MTPinputAudio(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { - read(from, end, cons); - } - - MTPDinputAudio &_inputAudio() { - if (!data) throw mtpErrorUninitialized(); - if (_type != mtpc_inputAudio) throw mtpErrorWrongTypeId(_type, mtpc_inputAudio); - split(); - return *(MTPDinputAudio*)data; - } - const MTPDinputAudio &c_inputAudio() const { - if (!data) throw mtpErrorUninitialized(); - if (_type != mtpc_inputAudio) throw mtpErrorWrongTypeId(_type, mtpc_inputAudio); - return *(const MTPDinputAudio*)data; - } - - uint32 innerLength() const; - mtpTypeId type() const; - void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); - void write(mtpBuffer &to) const; - - typedef void ResponseType; - -private: - explicit MTPinputAudio(mtpTypeId type); - explicit MTPinputAudio(MTPDinputAudio *_data); - - friend MTPinputAudio MTP_inputAudioEmpty(); - friend MTPinputAudio MTP_inputAudio(const MTPlong &_id, const MTPlong &_access_hash); - - mtpTypeId _type; -}; -typedef MTPBoxed MTPInputAudio; - class MTPinputDocument : private mtpDataOwner { public: MTPinputDocument() : mtpDataOwner(0), _type(0) { @@ -6773,57 +6604,6 @@ private: }; typedef MTPBoxed MTPInputDocument; -class MTPaudio : private mtpDataOwner { -public: - MTPaudio() : mtpDataOwner(0), _type(0) { - } - MTPaudio(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { - read(from, end, cons); - } - - MTPDaudioEmpty &_audioEmpty() { - if (!data) throw mtpErrorUninitialized(); - if (_type != mtpc_audioEmpty) throw mtpErrorWrongTypeId(_type, mtpc_audioEmpty); - split(); - return *(MTPDaudioEmpty*)data; - } - const MTPDaudioEmpty &c_audioEmpty() const { - if (!data) throw mtpErrorUninitialized(); - if (_type != mtpc_audioEmpty) throw mtpErrorWrongTypeId(_type, mtpc_audioEmpty); - return *(const MTPDaudioEmpty*)data; - } - - MTPDaudio &_audio() { - if (!data) throw mtpErrorUninitialized(); - if (_type != mtpc_audio) throw mtpErrorWrongTypeId(_type, mtpc_audio); - split(); - return *(MTPDaudio*)data; - } - const MTPDaudio &c_audio() const { - if (!data) throw mtpErrorUninitialized(); - if (_type != mtpc_audio) throw mtpErrorWrongTypeId(_type, mtpc_audio); - return *(const MTPDaudio*)data; - } - - uint32 innerLength() const; - mtpTypeId type() const; - void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); - void write(mtpBuffer &to) const; - - typedef void ResponseType; - -private: - explicit MTPaudio(mtpTypeId type); - explicit MTPaudio(MTPDaudioEmpty *_data); - explicit MTPaudio(MTPDaudio *_data); - - friend MTPaudio MTP_audioEmpty(const MTPlong &_id); - friend MTPaudio MTP_audio(const MTPlong &_id, const MTPlong &_access_hash, MTPint _date, MTPint _duration, const MTPstring &_mime_type, MTPint _size, MTPint _dc_id); - - mtpTypeId _type; -}; -typedef MTPBoxed MTPAudio; - class MTPdocument : private mtpDataOwner { public: MTPdocument() : mtpDataOwner(0), _type(0) { @@ -7064,43 +6844,51 @@ typedef MTPBoxed MTPcontacts_Found; class MTPinputPrivacyKey { public: - MTPinputPrivacyKey() { + MTPinputPrivacyKey() : _type(0) { } - MTPinputPrivacyKey(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_inputPrivacyKeyStatusTimestamp) { + MTPinputPrivacyKey(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : _type(0) { read(from, end, cons); } uint32 innerLength() const; mtpTypeId type() const; - void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_inputPrivacyKeyStatusTimestamp); + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); void write(mtpBuffer &to) const; typedef void ResponseType; private: + explicit MTPinputPrivacyKey(mtpTypeId type); friend MTPinputPrivacyKey MTP_inputPrivacyKeyStatusTimestamp(); + friend MTPinputPrivacyKey MTP_inputPrivacyKeyChatInvite(); + + mtpTypeId _type; }; typedef MTPBoxed MTPInputPrivacyKey; class MTPprivacyKey { public: - MTPprivacyKey() { + MTPprivacyKey() : _type(0) { } - MTPprivacyKey(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_privacyKeyStatusTimestamp) { + MTPprivacyKey(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : _type(0) { read(from, end, cons); } uint32 innerLength() const; mtpTypeId type() const; - void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_privacyKeyStatusTimestamp); + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); void write(mtpBuffer &to) const; typedef void ResponseType; private: + explicit MTPprivacyKey(mtpTypeId type); friend MTPprivacyKey MTP_privacyKeyStatusTimestamp(); + friend MTPprivacyKey MTP_privacyKeyChatInvite(); + + mtpTypeId _type; }; typedef MTPBoxed MTPPrivacyKey; @@ -7394,7 +7182,7 @@ private: friend MTPdocumentAttribute MTP_documentAttributeAnimated(); friend MTPdocumentAttribute MTP_documentAttributeSticker(const MTPstring &_alt, const MTPInputStickerSet &_stickerset); friend MTPdocumentAttribute MTP_documentAttributeVideo(MTPint _duration, MTPint _w, MTPint _h); - friend MTPdocumentAttribute MTP_documentAttributeAudio(MTPint _duration, const MTPstring &_title, const MTPstring &_performer); + friend MTPdocumentAttribute MTP_documentAttributeAudio(MTPint _flags, MTPint _duration, const MTPstring &_title, const MTPstring &_performer, const MTPbytes &_waveform); friend MTPdocumentAttribute MTP_documentAttributeFilename(const MTPstring &_file_name); mtpTypeId _type; @@ -9850,28 +9638,6 @@ public: MTPstring vcaption; }; -class MTPDinputMediaUploadedAudio : public mtpDataImpl { -public: - MTPDinputMediaUploadedAudio() { - } - MTPDinputMediaUploadedAudio(const MTPInputFile &_file, MTPint _duration, const MTPstring &_mime_type) : vfile(_file), vduration(_duration), vmime_type(_mime_type) { - } - - MTPInputFile vfile; - MTPint vduration; - MTPstring vmime_type; -}; - -class MTPDinputMediaAudio : public mtpDataImpl { -public: - MTPDinputMediaAudio() { - } - MTPDinputMediaAudio(const MTPInputAudio &_id) : vid(_id) { - } - - MTPInputAudio vid; -}; - class MTPDinputMediaUploadedDocument : public mtpDataImpl { public: MTPDinputMediaUploadedDocument() { @@ -10024,17 +9790,6 @@ public: MTPlong vaccess_hash; }; -class MTPDinputAudioFileLocation : public mtpDataImpl { -public: - MTPDinputAudioFileLocation() { - } - MTPDinputAudioFileLocation(const MTPlong &_id, const MTPlong &_access_hash) : vid(_id), vaccess_hash(_access_hash) { - } - - MTPlong vid; - MTPlong vaccess_hash; -}; - class MTPDinputDocumentFileLocation : public mtpDataImpl { public: MTPDinputDocumentFileLocation() { @@ -10314,6 +10069,7 @@ public: flag_verified = (1 << 7), flag_megagroup = (1 << 8), flag_restricted = (1 << 9), + flag_invites_enabled = (1 << 10), flag_username = (1 << 6), flag_restriction_reason = (1 << 9), }; @@ -10327,6 +10083,7 @@ public: bool is_verified() const { return vflags.v & flag_verified; } bool is_megagroup() const { return vflags.v & flag_megagroup; } bool is_restricted() const { return vflags.v & flag_restricted; } + bool is_invites_enabled() const { return vflags.v & flag_invites_enabled; } bool has_username() const { return vflags.v & flag_username; } bool has_restriction_reason() const { return vflags.v & flag_restriction_reason; } }; @@ -10621,16 +10378,6 @@ public: MTPstring vcaption; }; -class MTPDmessageMediaAudio : public mtpDataImpl { -public: - MTPDmessageMediaAudio() { - } - MTPDmessageMediaAudio(const MTPAudio &_audio) : vaudio(_audio) { - } - - MTPAudio vaudio; -}; - class MTPDmessageMediaWebPage : public mtpDataImpl { public: MTPDmessageMediaWebPage() { @@ -11056,17 +10803,6 @@ public: MTPint vdate; }; -class MTPDcontactSuggested : public mtpDataImpl { -public: - MTPDcontactSuggested() { - } - MTPDcontactSuggested(MTPint _user_id, MTPint _mutual_contacts) : vuser_id(_user_id), vmutual_contacts(_mutual_contacts) { - } - - MTPint vuser_id; - MTPint vmutual_contacts; -}; - class MTPDcontactStatus : public mtpDataImpl { public: MTPDcontactStatus() { @@ -11136,17 +10872,6 @@ public: MTPVector vusers; }; -class MTPDcontacts_suggested : public mtpDataImpl { -public: - MTPDcontacts_suggested() { - } - MTPDcontacts_suggested(const MTPVector &_results, const MTPVector &_users) : vresults(_results), vusers(_users) { - } - - MTPVector vresults; - MTPVector vusers; -}; - class MTPDmessages_dialogs : public mtpDataImpl { public: MTPDmessages_dialogs() { @@ -11720,6 +11445,18 @@ public: MTPstring voffset; }; +class MTPDupdateBotInlineSend : public mtpDataImpl { +public: + MTPDupdateBotInlineSend() { + } + MTPDupdateBotInlineSend(MTPint _user_id, const MTPstring &_query, const MTPstring &_id) : vuser_id(_user_id), vquery(_query), vid(_id) { + } + + MTPint vuser_id; + MTPstring vquery; + MTPstring vid; +}; + class MTPDupdates_state : public mtpDataImpl { public: MTPDupdates_state() { @@ -12257,17 +11994,6 @@ public: MTPEncryptedFile vfile; }; -class MTPDinputAudio : public mtpDataImpl { -public: - MTPDinputAudio() { - } - MTPDinputAudio(const MTPlong &_id, const MTPlong &_access_hash) : vid(_id), vaccess_hash(_access_hash) { - } - - MTPlong vid; - MTPlong vaccess_hash; -}; - class MTPDinputDocument : public mtpDataImpl { public: MTPDinputDocument() { @@ -12279,32 +12005,6 @@ public: MTPlong vaccess_hash; }; -class MTPDaudioEmpty : public mtpDataImpl { -public: - MTPDaudioEmpty() { - } - MTPDaudioEmpty(const MTPlong &_id) : vid(_id) { - } - - MTPlong vid; -}; - -class MTPDaudio : public mtpDataImpl { -public: - MTPDaudio() { - } - MTPDaudio(const MTPlong &_id, const MTPlong &_access_hash, MTPint _date, MTPint _duration, const MTPstring &_mime_type, MTPint _size, MTPint _dc_id) : vid(_id), vaccess_hash(_access_hash), vdate(_date), vduration(_duration), vmime_type(_mime_type), vsize(_size), vdc_id(_dc_id) { - } - - MTPlong vid; - MTPlong vaccess_hash; - MTPint vdate; - MTPint vduration; - MTPstring vmime_type; - MTPint vsize; - MTPint vdc_id; -}; - class MTPDdocumentEmpty : public mtpDataImpl { public: MTPDdocumentEmpty() { @@ -12515,12 +12215,26 @@ class MTPDdocumentAttributeAudio : public mtpDataImpl { @@ -15991,45 +15705,6 @@ public: } }; -class MTPcontacts_getSuggested { // RPC method 'contacts.getSuggested' -public: - MTPint vlimit; - - MTPcontacts_getSuggested() { - } - MTPcontacts_getSuggested(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_getSuggested) { - read(from, end, cons); - } - MTPcontacts_getSuggested(MTPint _limit) : vlimit(_limit) { - } - - uint32 innerLength() const { - return vlimit.innerLength(); - } - mtpTypeId type() const { - return mtpc_contacts_getSuggested; - } - void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_contacts_getSuggested) { - vlimit.read(from, end); - } - void write(mtpBuffer &to) const { - vlimit.write(to); - } - - typedef MTPcontacts_Suggested ResponseType; -}; -class MTPcontacts_GetSuggested : public MTPBoxed { -public: - MTPcontacts_GetSuggested() { - } - MTPcontacts_GetSuggested(const MTPcontacts_getSuggested &v) : MTPBoxed(v) { - } - MTPcontacts_GetSuggested(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { - } - MTPcontacts_GetSuggested(MTPint _limit) : MTPBoxed(MTPcontacts_getSuggested(_limit)) { - } -}; - class MTPcontacts_deleteContact { // RPC method 'contacts.deleteContact' public: MTPInputUser vid; @@ -16470,6 +16145,7 @@ class MTPmessages_getHistory { // RPC method 'messages.getHistory' public: MTPInputPeer vpeer; MTPint voffset_id; + MTPint voffset_date; MTPint vadd_offset; MTPint vlimit; MTPint vmax_id; @@ -16480,11 +16156,11 @@ public: MTPmessages_getHistory(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getHistory) { read(from, end, cons); } - MTPmessages_getHistory(const MTPInputPeer &_peer, MTPint _offset_id, MTPint _add_offset, MTPint _limit, MTPint _max_id, MTPint _min_id) : vpeer(_peer), voffset_id(_offset_id), vadd_offset(_add_offset), vlimit(_limit), vmax_id(_max_id), vmin_id(_min_id) { + MTPmessages_getHistory(const MTPInputPeer &_peer, MTPint _offset_id, MTPint _offset_date, MTPint _add_offset, MTPint _limit, MTPint _max_id, MTPint _min_id) : vpeer(_peer), voffset_id(_offset_id), voffset_date(_offset_date), vadd_offset(_add_offset), vlimit(_limit), vmax_id(_max_id), vmin_id(_min_id) { } uint32 innerLength() const { - return vpeer.innerLength() + voffset_id.innerLength() + vadd_offset.innerLength() + vlimit.innerLength() + vmax_id.innerLength() + vmin_id.innerLength(); + return vpeer.innerLength() + voffset_id.innerLength() + voffset_date.innerLength() + vadd_offset.innerLength() + vlimit.innerLength() + vmax_id.innerLength() + vmin_id.innerLength(); } mtpTypeId type() const { return mtpc_messages_getHistory; @@ -16492,6 +16168,7 @@ public: void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getHistory) { vpeer.read(from, end); voffset_id.read(from, end); + voffset_date.read(from, end); vadd_offset.read(from, end); vlimit.read(from, end); vmax_id.read(from, end); @@ -16500,6 +16177,7 @@ public: void write(mtpBuffer &to) const { vpeer.write(to); voffset_id.write(to); + voffset_date.write(to); vadd_offset.write(to); vlimit.write(to); vmax_id.write(to); @@ -16516,7 +16194,7 @@ public: } MTPmessages_GetHistory(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { } - MTPmessages_GetHistory(const MTPInputPeer &_peer, MTPint _offset_id, MTPint _add_offset, MTPint _limit, MTPint _max_id, MTPint _min_id) : MTPBoxed(MTPmessages_getHistory(_peer, _offset_id, _add_offset, _limit, _max_id, _min_id)) { + MTPmessages_GetHistory(const MTPInputPeer &_peer, MTPint _offset_id, MTPint _offset_date, MTPint _add_offset, MTPint _limit, MTPint _max_id, MTPint _min_id) : MTPBoxed(MTPmessages_getHistory(_peer, _offset_id, _offset_date, _add_offset, _limit, _max_id, _min_id)) { } }; @@ -19672,6 +19350,7 @@ class MTPchannels_getImportantHistory { // RPC method 'channels.getImportantHist public: MTPInputChannel vchannel; MTPint voffset_id; + MTPint voffset_date; MTPint vadd_offset; MTPint vlimit; MTPint vmax_id; @@ -19682,11 +19361,11 @@ public: MTPchannels_getImportantHistory(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_channels_getImportantHistory) { read(from, end, cons); } - MTPchannels_getImportantHistory(const MTPInputChannel &_channel, MTPint _offset_id, MTPint _add_offset, MTPint _limit, MTPint _max_id, MTPint _min_id) : vchannel(_channel), voffset_id(_offset_id), vadd_offset(_add_offset), vlimit(_limit), vmax_id(_max_id), vmin_id(_min_id) { + MTPchannels_getImportantHistory(const MTPInputChannel &_channel, MTPint _offset_id, MTPint _offset_date, MTPint _add_offset, MTPint _limit, MTPint _max_id, MTPint _min_id) : vchannel(_channel), voffset_id(_offset_id), voffset_date(_offset_date), vadd_offset(_add_offset), vlimit(_limit), vmax_id(_max_id), vmin_id(_min_id) { } uint32 innerLength() const { - return vchannel.innerLength() + voffset_id.innerLength() + vadd_offset.innerLength() + vlimit.innerLength() + vmax_id.innerLength() + vmin_id.innerLength(); + return vchannel.innerLength() + voffset_id.innerLength() + voffset_date.innerLength() + vadd_offset.innerLength() + vlimit.innerLength() + vmax_id.innerLength() + vmin_id.innerLength(); } mtpTypeId type() const { return mtpc_channels_getImportantHistory; @@ -19694,6 +19373,7 @@ public: void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_channels_getImportantHistory) { vchannel.read(from, end); voffset_id.read(from, end); + voffset_date.read(from, end); vadd_offset.read(from, end); vlimit.read(from, end); vmax_id.read(from, end); @@ -19702,6 +19382,7 @@ public: void write(mtpBuffer &to) const { vchannel.write(to); voffset_id.write(to); + voffset_date.write(to); vadd_offset.write(to); vlimit.write(to); vmax_id.write(to); @@ -19718,7 +19399,7 @@ public: } MTPchannels_GetImportantHistory(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { } - MTPchannels_GetImportantHistory(const MTPInputChannel &_channel, MTPint _offset_id, MTPint _add_offset, MTPint _limit, MTPint _max_id, MTPint _min_id) : MTPBoxed(MTPchannels_getImportantHistory(_channel, _offset_id, _add_offset, _limit, _max_id, _min_id)) { + MTPchannels_GetImportantHistory(const MTPInputChannel &_channel, MTPint _offset_id, MTPint _offset_date, MTPint _add_offset, MTPint _limit, MTPint _max_id, MTPint _min_id) : MTPBoxed(MTPchannels_getImportantHistory(_channel, _offset_id, _offset_date, _add_offset, _limit, _max_id, _min_id)) { } }; @@ -20696,6 +20377,48 @@ public: } }; +class MTPchannels_toggleInvites { // RPC method 'channels.toggleInvites' +public: + MTPInputChannel vchannel; + MTPBool venabled; + + MTPchannels_toggleInvites() { + } + MTPchannels_toggleInvites(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_channels_toggleInvites) { + read(from, end, cons); + } + MTPchannels_toggleInvites(const MTPInputChannel &_channel, MTPBool _enabled) : vchannel(_channel), venabled(_enabled) { + } + + uint32 innerLength() const { + return vchannel.innerLength() + venabled.innerLength(); + } + mtpTypeId type() const { + return mtpc_channels_toggleInvites; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_channels_toggleInvites) { + vchannel.read(from, end); + venabled.read(from, end); + } + void write(mtpBuffer &to) const { + vchannel.write(to); + venabled.write(to); + } + + typedef MTPUpdates ResponseType; +}; +class MTPchannels_ToggleInvites : public MTPBoxed { +public: + MTPchannels_ToggleInvites() { + } + MTPchannels_ToggleInvites(const MTPchannels_toggleInvites &v) : MTPBoxed(v) { + } + MTPchannels_ToggleInvites(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPchannels_ToggleInvites(const MTPInputChannel &_channel, MTPBool _enabled) : MTPBoxed(MTPchannels_toggleInvites(_channel, _enabled)) { + } +}; + // Inline methods definition inline MTPresPQ::MTPresPQ() : mtpDataOwner(new MTPDresPQ()) { @@ -21968,14 +21691,6 @@ inline uint32 MTPinputMedia::innerLength() const { const MTPDinputMediaVideo &v(c_inputMediaVideo()); return v.vid.innerLength() + v.vcaption.innerLength(); } - case mtpc_inputMediaUploadedAudio: { - const MTPDinputMediaUploadedAudio &v(c_inputMediaUploadedAudio()); - return v.vfile.innerLength() + v.vduration.innerLength() + v.vmime_type.innerLength(); - } - case mtpc_inputMediaAudio: { - const MTPDinputMediaAudio &v(c_inputMediaAudio()); - return v.vid.innerLength(); - } case mtpc_inputMediaUploadedDocument: { const MTPDinputMediaUploadedDocument &v(c_inputMediaUploadedDocument()); return v.vfile.innerLength() + v.vmime_type.innerLength() + v.vattributes.innerLength() + v.vcaption.innerLength(); @@ -22058,18 +21773,6 @@ inline void MTPinputMedia::read(const mtpPrime *&from, const mtpPrime *end, mtpT v.vid.read(from, end); v.vcaption.read(from, end); } break; - case mtpc_inputMediaUploadedAudio: _type = cons; { - if (!data) setData(new MTPDinputMediaUploadedAudio()); - MTPDinputMediaUploadedAudio &v(_inputMediaUploadedAudio()); - v.vfile.read(from, end); - v.vduration.read(from, end); - v.vmime_type.read(from, end); - } break; - case mtpc_inputMediaAudio: _type = cons; { - if (!data) setData(new MTPDinputMediaAudio()); - MTPDinputMediaAudio &v(_inputMediaAudio()); - v.vid.read(from, end); - } break; case mtpc_inputMediaUploadedDocument: _type = cons; { if (!data) setData(new MTPDinputMediaUploadedDocument()); MTPDinputMediaUploadedDocument &v(_inputMediaUploadedDocument()); @@ -22157,16 +21860,6 @@ inline void MTPinputMedia::write(mtpBuffer &to) const { v.vid.write(to); v.vcaption.write(to); } break; - case mtpc_inputMediaUploadedAudio: { - const MTPDinputMediaUploadedAudio &v(c_inputMediaUploadedAudio()); - v.vfile.write(to); - v.vduration.write(to); - v.vmime_type.write(to); - } break; - case mtpc_inputMediaAudio: { - const MTPDinputMediaAudio &v(c_inputMediaAudio()); - v.vid.write(to); - } break; case mtpc_inputMediaUploadedDocument: { const MTPDinputMediaUploadedDocument &v(c_inputMediaUploadedDocument()); v.vfile.write(to); @@ -22212,8 +21905,6 @@ inline MTPinputMedia::MTPinputMedia(mtpTypeId type) : mtpDataOwner(0), _type(typ case mtpc_inputMediaUploadedVideo: setData(new MTPDinputMediaUploadedVideo()); break; case mtpc_inputMediaUploadedThumbVideo: setData(new MTPDinputMediaUploadedThumbVideo()); break; case mtpc_inputMediaVideo: setData(new MTPDinputMediaVideo()); break; - case mtpc_inputMediaUploadedAudio: setData(new MTPDinputMediaUploadedAudio()); break; - case mtpc_inputMediaAudio: setData(new MTPDinputMediaAudio()); break; case mtpc_inputMediaUploadedDocument: setData(new MTPDinputMediaUploadedDocument()); break; case mtpc_inputMediaUploadedThumbDocument: setData(new MTPDinputMediaUploadedThumbDocument()); break; case mtpc_inputMediaDocument: setData(new MTPDinputMediaDocument()); break; @@ -22236,10 +21927,6 @@ inline MTPinputMedia::MTPinputMedia(MTPDinputMediaUploadedThumbVideo *_data) : m } inline MTPinputMedia::MTPinputMedia(MTPDinputMediaVideo *_data) : mtpDataOwner(_data), _type(mtpc_inputMediaVideo) { } -inline MTPinputMedia::MTPinputMedia(MTPDinputMediaUploadedAudio *_data) : mtpDataOwner(_data), _type(mtpc_inputMediaUploadedAudio) { -} -inline MTPinputMedia::MTPinputMedia(MTPDinputMediaAudio *_data) : mtpDataOwner(_data), _type(mtpc_inputMediaAudio) { -} inline MTPinputMedia::MTPinputMedia(MTPDinputMediaUploadedDocument *_data) : mtpDataOwner(_data), _type(mtpc_inputMediaUploadedDocument) { } inline MTPinputMedia::MTPinputMedia(MTPDinputMediaUploadedThumbDocument *_data) : mtpDataOwner(_data), _type(mtpc_inputMediaUploadedThumbDocument) { @@ -22274,12 +21961,6 @@ inline MTPinputMedia MTP_inputMediaUploadedThumbVideo(const MTPInputFile &_file, inline MTPinputMedia MTP_inputMediaVideo(const MTPInputVideo &_id, const MTPstring &_caption) { return MTPinputMedia(new MTPDinputMediaVideo(_id, _caption)); } -inline MTPinputMedia MTP_inputMediaUploadedAudio(const MTPInputFile &_file, MTPint _duration, const MTPstring &_mime_type) { - return MTPinputMedia(new MTPDinputMediaUploadedAudio(_file, _duration, _mime_type)); -} -inline MTPinputMedia MTP_inputMediaAudio(const MTPInputAudio &_id) { - return MTPinputMedia(new MTPDinputMediaAudio(_id)); -} inline MTPinputMedia MTP_inputMediaUploadedDocument(const MTPInputFile &_file, const MTPstring &_mime_type, const MTPVector &_attributes, const MTPstring &_caption) { return MTPinputMedia(new MTPDinputMediaUploadedDocument(_file, _mime_type, _attributes, _caption)); } @@ -22535,10 +22216,6 @@ inline uint32 MTPinputFileLocation::innerLength() const { const MTPDinputEncryptedFileLocation &v(c_inputEncryptedFileLocation()); return v.vid.innerLength() + v.vaccess_hash.innerLength(); } - case mtpc_inputAudioFileLocation: { - const MTPDinputAudioFileLocation &v(c_inputAudioFileLocation()); - return v.vid.innerLength() + v.vaccess_hash.innerLength(); - } case mtpc_inputDocumentFileLocation: { const MTPDinputDocumentFileLocation &v(c_inputDocumentFileLocation()); return v.vid.innerLength() + v.vaccess_hash.innerLength(); @@ -22572,12 +22249,6 @@ inline void MTPinputFileLocation::read(const mtpPrime *&from, const mtpPrime *en v.vid.read(from, end); v.vaccess_hash.read(from, end); } break; - case mtpc_inputAudioFileLocation: _type = cons; { - if (!data) setData(new MTPDinputAudioFileLocation()); - MTPDinputAudioFileLocation &v(_inputAudioFileLocation()); - v.vid.read(from, end); - v.vaccess_hash.read(from, end); - } break; case mtpc_inputDocumentFileLocation: _type = cons; { if (!data) setData(new MTPDinputDocumentFileLocation()); MTPDinputDocumentFileLocation &v(_inputDocumentFileLocation()); @@ -22605,11 +22276,6 @@ inline void MTPinputFileLocation::write(mtpBuffer &to) const { v.vid.write(to); v.vaccess_hash.write(to); } break; - case mtpc_inputAudioFileLocation: { - const MTPDinputAudioFileLocation &v(c_inputAudioFileLocation()); - v.vid.write(to); - v.vaccess_hash.write(to); - } break; case mtpc_inputDocumentFileLocation: { const MTPDinputDocumentFileLocation &v(c_inputDocumentFileLocation()); v.vid.write(to); @@ -22622,7 +22288,6 @@ inline MTPinputFileLocation::MTPinputFileLocation(mtpTypeId type) : mtpDataOwner case mtpc_inputFileLocation: setData(new MTPDinputFileLocation()); break; case mtpc_inputVideoFileLocation: setData(new MTPDinputVideoFileLocation()); break; case mtpc_inputEncryptedFileLocation: setData(new MTPDinputEncryptedFileLocation()); break; - case mtpc_inputAudioFileLocation: setData(new MTPDinputAudioFileLocation()); break; case mtpc_inputDocumentFileLocation: setData(new MTPDinputDocumentFileLocation()); break; default: throw mtpErrorBadTypeId(type, "MTPinputFileLocation"); } @@ -22633,8 +22298,6 @@ inline MTPinputFileLocation::MTPinputFileLocation(MTPDinputVideoFileLocation *_d } inline MTPinputFileLocation::MTPinputFileLocation(MTPDinputEncryptedFileLocation *_data) : mtpDataOwner(_data), _type(mtpc_inputEncryptedFileLocation) { } -inline MTPinputFileLocation::MTPinputFileLocation(MTPDinputAudioFileLocation *_data) : mtpDataOwner(_data), _type(mtpc_inputAudioFileLocation) { -} inline MTPinputFileLocation::MTPinputFileLocation(MTPDinputDocumentFileLocation *_data) : mtpDataOwner(_data), _type(mtpc_inputDocumentFileLocation) { } inline MTPinputFileLocation MTP_inputFileLocation(const MTPlong &_volume_id, MTPint _local_id, const MTPlong &_secret) { @@ -22646,9 +22309,6 @@ inline MTPinputFileLocation MTP_inputVideoFileLocation(const MTPlong &_id, const inline MTPinputFileLocation MTP_inputEncryptedFileLocation(const MTPlong &_id, const MTPlong &_access_hash) { return MTPinputFileLocation(new MTPDinputEncryptedFileLocation(_id, _access_hash)); } -inline MTPinputFileLocation MTP_inputAudioFileLocation(const MTPlong &_id, const MTPlong &_access_hash) { - return MTPinputFileLocation(new MTPDinputAudioFileLocation(_id, _access_hash)); -} inline MTPinputFileLocation MTP_inputDocumentFileLocation(const MTPlong &_id, const MTPlong &_access_hash) { return MTPinputFileLocation(new MTPDinputDocumentFileLocation(_id, _access_hash)); } @@ -23796,10 +23456,6 @@ inline uint32 MTPmessageMedia::innerLength() const { const MTPDmessageMediaDocument &v(c_messageMediaDocument()); return v.vdocument.innerLength() + v.vcaption.innerLength(); } - case mtpc_messageMediaAudio: { - const MTPDmessageMediaAudio &v(c_messageMediaAudio()); - return v.vaudio.innerLength(); - } case mtpc_messageMediaWebPage: { const MTPDmessageMediaWebPage &v(c_messageMediaWebPage()); return v.vwebpage.innerLength(); @@ -23851,11 +23507,6 @@ inline void MTPmessageMedia::read(const mtpPrime *&from, const mtpPrime *end, mt v.vdocument.read(from, end); v.vcaption.read(from, end); } break; - case mtpc_messageMediaAudio: _type = cons; { - if (!data) setData(new MTPDmessageMediaAudio()); - MTPDmessageMediaAudio &v(_messageMediaAudio()); - v.vaudio.read(from, end); - } break; case mtpc_messageMediaWebPage: _type = cons; { if (!data) setData(new MTPDmessageMediaWebPage()); MTPDmessageMediaWebPage &v(_messageMediaWebPage()); @@ -23901,10 +23552,6 @@ inline void MTPmessageMedia::write(mtpBuffer &to) const { v.vdocument.write(to); v.vcaption.write(to); } break; - case mtpc_messageMediaAudio: { - const MTPDmessageMediaAudio &v(c_messageMediaAudio()); - v.vaudio.write(to); - } break; case mtpc_messageMediaWebPage: { const MTPDmessageMediaWebPage &v(c_messageMediaWebPage()); v.vwebpage.write(to); @@ -23928,7 +23575,6 @@ inline MTPmessageMedia::MTPmessageMedia(mtpTypeId type) : mtpDataOwner(0), _type case mtpc_messageMediaContact: setData(new MTPDmessageMediaContact()); break; case mtpc_messageMediaUnsupported: break; case mtpc_messageMediaDocument: setData(new MTPDmessageMediaDocument()); break; - case mtpc_messageMediaAudio: setData(new MTPDmessageMediaAudio()); break; case mtpc_messageMediaWebPage: setData(new MTPDmessageMediaWebPage()); break; case mtpc_messageMediaVenue: setData(new MTPDmessageMediaVenue()); break; default: throw mtpErrorBadTypeId(type, "MTPmessageMedia"); @@ -23944,8 +23590,6 @@ inline MTPmessageMedia::MTPmessageMedia(MTPDmessageMediaContact *_data) : mtpDat } inline MTPmessageMedia::MTPmessageMedia(MTPDmessageMediaDocument *_data) : mtpDataOwner(_data), _type(mtpc_messageMediaDocument) { } -inline MTPmessageMedia::MTPmessageMedia(MTPDmessageMediaAudio *_data) : mtpDataOwner(_data), _type(mtpc_messageMediaAudio) { -} inline MTPmessageMedia::MTPmessageMedia(MTPDmessageMediaWebPage *_data) : mtpDataOwner(_data), _type(mtpc_messageMediaWebPage) { } inline MTPmessageMedia::MTPmessageMedia(MTPDmessageMediaVenue *_data) : mtpDataOwner(_data), _type(mtpc_messageMediaVenue) { @@ -23971,9 +23615,6 @@ inline MTPmessageMedia MTP_messageMediaUnsupported() { inline MTPmessageMedia MTP_messageMediaDocument(const MTPDocument &_document, const MTPstring &_caption) { return MTPmessageMedia(new MTPDmessageMediaDocument(_document, _caption)); } -inline MTPmessageMedia MTP_messageMediaAudio(const MTPAudio &_audio) { - return MTPmessageMedia(new MTPDmessageMediaAudio(_audio)); -} inline MTPmessageMedia MTP_messageMediaWebPage(const MTPWebPage &_webpage) { return MTPmessageMedia(new MTPDmessageMediaWebPage(_webpage)); } @@ -25202,35 +24843,6 @@ inline MTPcontactBlocked MTP_contactBlocked(MTPint _user_id, MTPint _date) { return MTPcontactBlocked(new MTPDcontactBlocked(_user_id, _date)); } -inline MTPcontactSuggested::MTPcontactSuggested() : mtpDataOwner(new MTPDcontactSuggested()) { -} - -inline uint32 MTPcontactSuggested::innerLength() const { - const MTPDcontactSuggested &v(c_contactSuggested()); - return v.vuser_id.innerLength() + v.vmutual_contacts.innerLength(); -} -inline mtpTypeId MTPcontactSuggested::type() const { - return mtpc_contactSuggested; -} -inline void MTPcontactSuggested::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { - if (cons != mtpc_contactSuggested) throw mtpErrorUnexpected(cons, "MTPcontactSuggested"); - - if (!data) setData(new MTPDcontactSuggested()); - MTPDcontactSuggested &v(_contactSuggested()); - v.vuser_id.read(from, end); - v.vmutual_contacts.read(from, end); -} -inline void MTPcontactSuggested::write(mtpBuffer &to) const { - const MTPDcontactSuggested &v(c_contactSuggested()); - v.vuser_id.write(to); - v.vmutual_contacts.write(to); -} -inline MTPcontactSuggested::MTPcontactSuggested(MTPDcontactSuggested *_data) : mtpDataOwner(_data) { -} -inline MTPcontactSuggested MTP_contactSuggested(MTPint _user_id, MTPint _mutual_contacts) { - return MTPcontactSuggested(new MTPDcontactSuggested(_user_id, _mutual_contacts)); -} - inline MTPcontactStatus::MTPcontactStatus() : mtpDataOwner(new MTPDcontactStatus()) { } @@ -25442,35 +25054,6 @@ inline MTPcontacts_blocked MTP_contacts_blockedSlice(MTPint _count, const MTPVec return MTPcontacts_blocked(new MTPDcontacts_blockedSlice(_count, _blocked, _users)); } -inline MTPcontacts_suggested::MTPcontacts_suggested() : mtpDataOwner(new MTPDcontacts_suggested()) { -} - -inline uint32 MTPcontacts_suggested::innerLength() const { - const MTPDcontacts_suggested &v(c_contacts_suggested()); - return v.vresults.innerLength() + v.vusers.innerLength(); -} -inline mtpTypeId MTPcontacts_suggested::type() const { - return mtpc_contacts_suggested; -} -inline void MTPcontacts_suggested::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { - if (cons != mtpc_contacts_suggested) throw mtpErrorUnexpected(cons, "MTPcontacts_suggested"); - - if (!data) setData(new MTPDcontacts_suggested()); - MTPDcontacts_suggested &v(_contacts_suggested()); - v.vresults.read(from, end); - v.vusers.read(from, end); -} -inline void MTPcontacts_suggested::write(mtpBuffer &to) const { - const MTPDcontacts_suggested &v(c_contacts_suggested()); - v.vresults.write(to); - v.vusers.write(to); -} -inline MTPcontacts_suggested::MTPcontacts_suggested(MTPDcontacts_suggested *_data) : mtpDataOwner(_data) { -} -inline MTPcontacts_suggested MTP_contacts_suggested(const MTPVector &_results, const MTPVector &_users) { - return MTPcontacts_suggested(new MTPDcontacts_suggested(_results, _users)); -} - inline uint32 MTPmessages_dialogs::innerLength() const { switch (_type) { case mtpc_messages_dialogs: { @@ -25756,10 +25339,10 @@ inline void MTPmessagesFilter::read(const mtpPrime *&from, const mtpPrime *end, case mtpc_inputMessagesFilterPhotoVideo: _type = cons; break; case mtpc_inputMessagesFilterPhotoVideoDocuments: _type = cons; break; case mtpc_inputMessagesFilterDocument: _type = cons; break; - case mtpc_inputMessagesFilterAudio: _type = cons; break; - case mtpc_inputMessagesFilterAudioDocuments: _type = cons; break; case mtpc_inputMessagesFilterUrl: _type = cons; break; case mtpc_inputMessagesFilterGif: _type = cons; break; + case mtpc_inputMessagesFilterVoice: _type = cons; break; + case mtpc_inputMessagesFilterMusic: _type = cons; break; default: throw mtpErrorUnexpected(cons, "MTPmessagesFilter"); } } @@ -25775,10 +25358,10 @@ inline MTPmessagesFilter::MTPmessagesFilter(mtpTypeId type) : _type(type) { case mtpc_inputMessagesFilterPhotoVideo: break; case mtpc_inputMessagesFilterPhotoVideoDocuments: break; case mtpc_inputMessagesFilterDocument: break; - case mtpc_inputMessagesFilterAudio: break; - case mtpc_inputMessagesFilterAudioDocuments: break; case mtpc_inputMessagesFilterUrl: break; case mtpc_inputMessagesFilterGif: break; + case mtpc_inputMessagesFilterVoice: break; + case mtpc_inputMessagesFilterMusic: break; default: throw mtpErrorBadTypeId(type, "MTPmessagesFilter"); } } @@ -25800,18 +25383,18 @@ inline MTPmessagesFilter MTP_inputMessagesFilterPhotoVideoDocuments() { inline MTPmessagesFilter MTP_inputMessagesFilterDocument() { return MTPmessagesFilter(mtpc_inputMessagesFilterDocument); } -inline MTPmessagesFilter MTP_inputMessagesFilterAudio() { - return MTPmessagesFilter(mtpc_inputMessagesFilterAudio); -} -inline MTPmessagesFilter MTP_inputMessagesFilterAudioDocuments() { - return MTPmessagesFilter(mtpc_inputMessagesFilterAudioDocuments); -} inline MTPmessagesFilter MTP_inputMessagesFilterUrl() { return MTPmessagesFilter(mtpc_inputMessagesFilterUrl); } inline MTPmessagesFilter MTP_inputMessagesFilterGif() { return MTPmessagesFilter(mtpc_inputMessagesFilterGif); } +inline MTPmessagesFilter MTP_inputMessagesFilterVoice() { + return MTPmessagesFilter(mtpc_inputMessagesFilterVoice); +} +inline MTPmessagesFilter MTP_inputMessagesFilterMusic() { + return MTPmessagesFilter(mtpc_inputMessagesFilterMusic); +} inline uint32 MTPupdate::innerLength() const { switch (_type) { @@ -25975,6 +25558,10 @@ inline uint32 MTPupdate::innerLength() const { const MTPDupdateBotInlineQuery &v(c_updateBotInlineQuery()); return v.vquery_id.innerLength() + v.vuser_id.innerLength() + v.vquery.innerLength() + v.voffset.innerLength(); } + case mtpc_updateBotInlineSend: { + const MTPDupdateBotInlineSend &v(c_updateBotInlineSend()); + return v.vuser_id.innerLength() + v.vquery.innerLength() + v.vid.innerLength(); + } } return 0; } @@ -26252,6 +25839,13 @@ inline void MTPupdate::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeI v.vquery.read(from, end); v.voffset.read(from, end); } break; + case mtpc_updateBotInlineSend: _type = cons; { + if (!data) setData(new MTPDupdateBotInlineSend()); + MTPDupdateBotInlineSend &v(_updateBotInlineSend()); + v.vuser_id.read(from, end); + v.vquery.read(from, end); + v.vid.read(from, end); + } break; default: throw mtpErrorUnexpected(cons, "MTPupdate"); } } @@ -26482,6 +26076,12 @@ inline void MTPupdate::write(mtpBuffer &to) const { v.vquery.write(to); v.voffset.write(to); } break; + case mtpc_updateBotInlineSend: { + const MTPDupdateBotInlineSend &v(c_updateBotInlineSend()); + v.vuser_id.write(to); + v.vquery.write(to); + v.vid.write(to); + } break; } } inline MTPupdate::MTPupdate(mtpTypeId type) : mtpDataOwner(0), _type(type) { @@ -26528,6 +26128,7 @@ inline MTPupdate::MTPupdate(mtpTypeId type) : mtpDataOwner(0), _type(type) { case mtpc_updateStickerSets: break; case mtpc_updateSavedGifs: break; case mtpc_updateBotInlineQuery: setData(new MTPDupdateBotInlineQuery()); break; + case mtpc_updateBotInlineSend: setData(new MTPDupdateBotInlineSend()); break; default: throw mtpErrorBadTypeId(type, "MTPupdate"); } } @@ -26611,6 +26212,8 @@ inline MTPupdate::MTPupdate(MTPDupdateStickerSetsOrder *_data) : mtpDataOwner(_d } inline MTPupdate::MTPupdate(MTPDupdateBotInlineQuery *_data) : mtpDataOwner(_data), _type(mtpc_updateBotInlineQuery) { } +inline MTPupdate::MTPupdate(MTPDupdateBotInlineSend *_data) : mtpDataOwner(_data), _type(mtpc_updateBotInlineSend) { +} inline MTPupdate MTP_updateNewMessage(const MTPMessage &_message, MTPint _pts, MTPint _pts_count) { return MTPupdate(new MTPDupdateNewMessage(_message, _pts, _pts_count)); } @@ -26737,6 +26340,9 @@ inline MTPupdate MTP_updateSavedGifs() { inline MTPupdate MTP_updateBotInlineQuery(const MTPlong &_query_id, MTPint _user_id, const MTPstring &_query, const MTPstring &_offset) { return MTPupdate(new MTPDupdateBotInlineQuery(_query_id, _user_id, _query, _offset)); } +inline MTPupdate MTP_updateBotInlineSend(MTPint _user_id, const MTPstring &_query, const MTPstring &_id) { + return MTPupdate(new MTPDupdateBotInlineSend(_user_id, _query, _id)); +} inline MTPupdates_state::MTPupdates_state() : mtpDataOwner(new MTPDupdates_state()) { } @@ -27983,57 +27589,6 @@ inline MTPmessages_sentEncryptedMessage MTP_messages_sentEncryptedFile(MTPint _d return MTPmessages_sentEncryptedMessage(new MTPDmessages_sentEncryptedFile(_date, _file)); } -inline uint32 MTPinputAudio::innerLength() const { - switch (_type) { - case mtpc_inputAudio: { - const MTPDinputAudio &v(c_inputAudio()); - return v.vid.innerLength() + v.vaccess_hash.innerLength(); - } - } - return 0; -} -inline mtpTypeId MTPinputAudio::type() const { - if (!_type) throw mtpErrorUninitialized(); - return _type; -} -inline void MTPinputAudio::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { - if (cons != _type) setData(0); - switch (cons) { - case mtpc_inputAudioEmpty: _type = cons; break; - case mtpc_inputAudio: _type = cons; { - if (!data) setData(new MTPDinputAudio()); - MTPDinputAudio &v(_inputAudio()); - v.vid.read(from, end); - v.vaccess_hash.read(from, end); - } break; - default: throw mtpErrorUnexpected(cons, "MTPinputAudio"); - } -} -inline void MTPinputAudio::write(mtpBuffer &to) const { - switch (_type) { - case mtpc_inputAudio: { - const MTPDinputAudio &v(c_inputAudio()); - v.vid.write(to); - v.vaccess_hash.write(to); - } break; - } -} -inline MTPinputAudio::MTPinputAudio(mtpTypeId type) : mtpDataOwner(0), _type(type) { - switch (type) { - case mtpc_inputAudioEmpty: break; - case mtpc_inputAudio: setData(new MTPDinputAudio()); break; - default: throw mtpErrorBadTypeId(type, "MTPinputAudio"); - } -} -inline MTPinputAudio::MTPinputAudio(MTPDinputAudio *_data) : mtpDataOwner(_data), _type(mtpc_inputAudio) { -} -inline MTPinputAudio MTP_inputAudioEmpty() { - return MTPinputAudio(mtpc_inputAudioEmpty); -} -inline MTPinputAudio MTP_inputAudio(const MTPlong &_id, const MTPlong &_access_hash) { - return MTPinputAudio(new MTPDinputAudio(_id, _access_hash)); -} - inline uint32 MTPinputDocument::innerLength() const { switch (_type) { case mtpc_inputDocument: { @@ -28085,81 +27640,6 @@ inline MTPinputDocument MTP_inputDocument(const MTPlong &_id, const MTPlong &_ac return MTPinputDocument(new MTPDinputDocument(_id, _access_hash)); } -inline uint32 MTPaudio::innerLength() const { - switch (_type) { - case mtpc_audioEmpty: { - const MTPDaudioEmpty &v(c_audioEmpty()); - return v.vid.innerLength(); - } - case mtpc_audio: { - const MTPDaudio &v(c_audio()); - return v.vid.innerLength() + v.vaccess_hash.innerLength() + v.vdate.innerLength() + v.vduration.innerLength() + v.vmime_type.innerLength() + v.vsize.innerLength() + v.vdc_id.innerLength(); - } - } - return 0; -} -inline mtpTypeId MTPaudio::type() const { - if (!_type) throw mtpErrorUninitialized(); - return _type; -} -inline void MTPaudio::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { - if (cons != _type) setData(0); - switch (cons) { - case mtpc_audioEmpty: _type = cons; { - if (!data) setData(new MTPDaudioEmpty()); - MTPDaudioEmpty &v(_audioEmpty()); - v.vid.read(from, end); - } break; - case mtpc_audio: _type = cons; { - if (!data) setData(new MTPDaudio()); - MTPDaudio &v(_audio()); - v.vid.read(from, end); - v.vaccess_hash.read(from, end); - v.vdate.read(from, end); - v.vduration.read(from, end); - v.vmime_type.read(from, end); - v.vsize.read(from, end); - v.vdc_id.read(from, end); - } break; - default: throw mtpErrorUnexpected(cons, "MTPaudio"); - } -} -inline void MTPaudio::write(mtpBuffer &to) const { - switch (_type) { - case mtpc_audioEmpty: { - const MTPDaudioEmpty &v(c_audioEmpty()); - v.vid.write(to); - } break; - case mtpc_audio: { - const MTPDaudio &v(c_audio()); - v.vid.write(to); - v.vaccess_hash.write(to); - v.vdate.write(to); - v.vduration.write(to); - v.vmime_type.write(to); - v.vsize.write(to); - v.vdc_id.write(to); - } break; - } -} -inline MTPaudio::MTPaudio(mtpTypeId type) : mtpDataOwner(0), _type(type) { - switch (type) { - case mtpc_audioEmpty: setData(new MTPDaudioEmpty()); break; - case mtpc_audio: setData(new MTPDaudio()); break; - default: throw mtpErrorBadTypeId(type, "MTPaudio"); - } -} -inline MTPaudio::MTPaudio(MTPDaudioEmpty *_data) : mtpDataOwner(_data), _type(mtpc_audioEmpty) { -} -inline MTPaudio::MTPaudio(MTPDaudio *_data) : mtpDataOwner(_data), _type(mtpc_audio) { -} -inline MTPaudio MTP_audioEmpty(const MTPlong &_id) { - return MTPaudio(new MTPDaudioEmpty(_id)); -} -inline MTPaudio MTP_audio(const MTPlong &_id, const MTPlong &_access_hash, MTPint _date, MTPint _duration, const MTPstring &_mime_type, MTPint _size, MTPint _dc_id) { - return MTPaudio(new MTPDaudio(_id, _access_hash, _date, _duration, _mime_type, _size, _dc_id)); -} - inline uint32 MTPdocument::innerLength() const { switch (_type) { case mtpc_documentEmpty: { @@ -28491,28 +27971,64 @@ inline uint32 MTPinputPrivacyKey::innerLength() const { return 0; } inline mtpTypeId MTPinputPrivacyKey::type() const { - return mtpc_inputPrivacyKeyStatusTimestamp; + if (!_type) throw mtpErrorUninitialized(); + return _type; } inline void MTPinputPrivacyKey::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + switch (cons) { + case mtpc_inputPrivacyKeyStatusTimestamp: _type = cons; break; + case mtpc_inputPrivacyKeyChatInvite: _type = cons; break; + default: throw mtpErrorUnexpected(cons, "MTPinputPrivacyKey"); + } } inline void MTPinputPrivacyKey::write(mtpBuffer &to) const { + switch (_type) { + } +} +inline MTPinputPrivacyKey::MTPinputPrivacyKey(mtpTypeId type) : _type(type) { + switch (type) { + case mtpc_inputPrivacyKeyStatusTimestamp: break; + case mtpc_inputPrivacyKeyChatInvite: break; + default: throw mtpErrorBadTypeId(type, "MTPinputPrivacyKey"); + } } inline MTPinputPrivacyKey MTP_inputPrivacyKeyStatusTimestamp() { - return MTPinputPrivacyKey(); + return MTPinputPrivacyKey(mtpc_inputPrivacyKeyStatusTimestamp); +} +inline MTPinputPrivacyKey MTP_inputPrivacyKeyChatInvite() { + return MTPinputPrivacyKey(mtpc_inputPrivacyKeyChatInvite); } inline uint32 MTPprivacyKey::innerLength() const { return 0; } inline mtpTypeId MTPprivacyKey::type() const { - return mtpc_privacyKeyStatusTimestamp; + if (!_type) throw mtpErrorUninitialized(); + return _type; } inline void MTPprivacyKey::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + switch (cons) { + case mtpc_privacyKeyStatusTimestamp: _type = cons; break; + case mtpc_privacyKeyChatInvite: _type = cons; break; + default: throw mtpErrorUnexpected(cons, "MTPprivacyKey"); + } } inline void MTPprivacyKey::write(mtpBuffer &to) const { + switch (_type) { + } +} +inline MTPprivacyKey::MTPprivacyKey(mtpTypeId type) : _type(type) { + switch (type) { + case mtpc_privacyKeyStatusTimestamp: break; + case mtpc_privacyKeyChatInvite: break; + default: throw mtpErrorBadTypeId(type, "MTPprivacyKey"); + } } inline MTPprivacyKey MTP_privacyKeyStatusTimestamp() { - return MTPprivacyKey(); + return MTPprivacyKey(mtpc_privacyKeyStatusTimestamp); +} +inline MTPprivacyKey MTP_privacyKeyChatInvite() { + return MTPprivacyKey(mtpc_privacyKeyChatInvite); } inline uint32 MTPinputPrivacyRule::innerLength() const { @@ -28782,7 +28298,7 @@ inline uint32 MTPdocumentAttribute::innerLength() const { } case mtpc_documentAttributeAudio: { const MTPDdocumentAttributeAudio &v(c_documentAttributeAudio()); - return v.vduration.innerLength() + v.vtitle.innerLength() + v.vperformer.innerLength(); + return v.vflags.innerLength() + v.vduration.innerLength() + (v.has_title() ? v.vtitle.innerLength() : 0) + (v.has_performer() ? v.vperformer.innerLength() : 0) + (v.has_waveform() ? v.vwaveform.innerLength() : 0); } case mtpc_documentAttributeFilename: { const MTPDdocumentAttributeFilename &v(c_documentAttributeFilename()); @@ -28821,9 +28337,11 @@ inline void MTPdocumentAttribute::read(const mtpPrime *&from, const mtpPrime *en case mtpc_documentAttributeAudio: _type = cons; { if (!data) setData(new MTPDdocumentAttributeAudio()); MTPDdocumentAttributeAudio &v(_documentAttributeAudio()); + v.vflags.read(from, end); v.vduration.read(from, end); - v.vtitle.read(from, end); - v.vperformer.read(from, end); + if (v.has_title()) { v.vtitle.read(from, end); } else { v.vtitle = MTPstring(); } + if (v.has_performer()) { v.vperformer.read(from, end); } else { v.vperformer = MTPstring(); } + if (v.has_waveform()) { v.vwaveform.read(from, end); } else { v.vwaveform = MTPbytes(); } } break; case mtpc_documentAttributeFilename: _type = cons; { if (!data) setData(new MTPDdocumentAttributeFilename()); @@ -28853,9 +28371,11 @@ inline void MTPdocumentAttribute::write(mtpBuffer &to) const { } break; case mtpc_documentAttributeAudio: { const MTPDdocumentAttributeAudio &v(c_documentAttributeAudio()); + v.vflags.write(to); v.vduration.write(to); - v.vtitle.write(to); - v.vperformer.write(to); + if (v.has_title()) v.vtitle.write(to); + if (v.has_performer()) v.vperformer.write(to); + if (v.has_waveform()) v.vwaveform.write(to); } break; case mtpc_documentAttributeFilename: { const MTPDdocumentAttributeFilename &v(c_documentAttributeFilename()); @@ -28896,8 +28416,8 @@ inline MTPdocumentAttribute MTP_documentAttributeSticker(const MTPstring &_alt, inline MTPdocumentAttribute MTP_documentAttributeVideo(MTPint _duration, MTPint _w, MTPint _h) { return MTPdocumentAttribute(new MTPDdocumentAttributeVideo(_duration, _w, _h)); } -inline MTPdocumentAttribute MTP_documentAttributeAudio(MTPint _duration, const MTPstring &_title, const MTPstring &_performer) { - return MTPdocumentAttribute(new MTPDdocumentAttributeAudio(_duration, _title, _performer)); +inline MTPdocumentAttribute MTP_documentAttributeAudio(MTPint _flags, MTPint _duration, const MTPstring &_title, const MTPstring &_performer, const MTPbytes &_waveform) { + return MTPdocumentAttribute(new MTPDdocumentAttributeAudio(_flags, _duration, _title, _performer, _waveform)); } inline MTPdocumentAttribute MTP_documentAttributeFilename(const MTPstring &_file_name) { return MTPdocumentAttribute(new MTPDdocumentAttributeFilename(_file_name)); diff --git a/Telegram/SourceFiles/mtproto/scheme.tl b/Telegram/SourceFiles/mtproto/scheme.tl index 64bfa2eaa8..d8c3c7bb9a 100644 --- a/Telegram/SourceFiles/mtproto/scheme.tl +++ b/Telegram/SourceFiles/mtproto/scheme.tl @@ -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 caption:string = InputMedia; inputMediaUploadedThumbDocument#ad613491 file:InputFile thumb:InputFile mime_type:string attributes:Vector 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 = 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 retry_contac contacts.blocked#1c138d15 blocked:Vector users:Vector = contacts.Blocked; contacts.blockedSlice#900802a1 count:int blocked:Vector users:Vector = contacts.Blocked; -contacts.suggested#5649dcc5 results:Vector users:Vector = contacts.Suggested; - messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = 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 = 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 = Document; @@ -492,8 +479,10 @@ sendMessageChooseContactAction#628cbc6f = SendMessageAction; contacts.found#1aa1f784 results:Vector chats:Vector users:Vector = 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; contacts.getContacts#22c6aa08 hash:string = contacts.Contacts; contacts.importContacts#da30b32d contacts:Vector replace:Bool = contacts.ImportedContacts; -contacts.getSuggested#cd773428 limit:int = contacts.Suggested; contacts.deleteContact#8e953744 id:InputUser = contacts.Link; contacts.deleteContacts#59ab389e id:Vector = Bool; contacts.block#332b49fc id:InputUser = Bool; @@ -730,7 +718,7 @@ contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; messages.getMessages#4222fa74 id:Vector = 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 = messages.AffectedMessages; channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; @@ -832,3 +820,4 @@ channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector = 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; diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index 0c9c0698ba..84905568bb 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -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(_contextMenuLnk.data()); VideoLink *lnkVideo = dynamic_cast(_contextMenuLnk.data()); - AudioLink *lnkAudio = dynamic_cast(_contextMenuLnk.data()); DocumentLink *lnkDocument = dynamic_cast(_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(_contextMenuLnk.data()); - AudioLink *lnkAudio = dynamic_cast(_contextMenuLnk.data()); DocumentLink *lnkDocument = dynamic_cast(_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(_contextMenuLnk.data()); - AudioLink *lnkAudio = dynamic_cast(_contextMenuLnk.data()); DocumentLink *lnkDocument = dynamic_cast(_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(_contextMenuLnk.data()); - AudioLink *lnkAudio = dynamic_cast(_contextMenuLnk.data()); DocumentLink *lnkDocument = dynamic_cast(_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(_contextMenuLnk.data()); - AudioLink *lnkAudio = dynamic_cast(_contextMenuLnk.data()); DocumentLink *lnkDocument = dynamic_cast(_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(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())); diff --git a/Telegram/SourceFiles/playerwidget.cpp b/Telegram/SourceFiles/playerwidget.cpp index 7fdaa1b6dd..1ab72f6c51 100644 --- a/Telegram/SourceFiles/playerwidget.cpp +++ b/Telegram/SourceFiles/playerwidget.cpp @@ -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(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); } diff --git a/Telegram/SourceFiles/profilewidget.cpp b/Telegram/SourceFiles/profilewidget.cpp index a98dee9507..53df0dedfb 100644 --- a/Telegram/SourceFiles/profilewidget.cpp +++ b/Telegram/SourceFiles/profilewidget.cpp @@ -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(); diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index 274b34f29b..d396ebcb88 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -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(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(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(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(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 &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 &attributes) { @@ -1535,11 +1280,27 @@ void DocumentData::setattributes(const QVector &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 &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(this)->_location = Local::readFileLocation(mediaKey(DocumentFileLocation, dc, id)); + LocationType type = voice() ? AudioFileLocation : DocumentFileLocation; + const_cast(this)->_location = Local::readFileLocation(mediaKey(type, dc, id)); } return _location; } diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index 78e899e56e..38ed72308b 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -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 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(_additional) : 0; } + VoiceData *voice() { + return (type == VoiceDocument) ? static_cast(_additional) : 0; + } + const VoiceData *voice() const { + return (type == VoiceDocument) ? static_cast(_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(_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; }; diff --git a/Telegram/SourceFiles/types.h b/Telegram/SourceFiles/types.h index 4647bada86..11fe4f8108 100644 --- a/Telegram/SourceFiles/types.h +++ b/Telegram/SourceFiles/types.h @@ -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 @@ -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::Size, InterfaceWrapTemplate::Construct, InterfaceWrapTemplate::Destruct); + InterfaceWraps[last] = InterfaceWrapStruct(InterfaceWrapTemplate::Size, InterfaceWrapTemplate::Construct, InterfaceWrapTemplate::Destruct, InterfaceWrapTemplate::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 Type *Get() { - return (Type*)_dataptr(_meta->offsets[Type::Index()]); + return static_cast(_dataptr(_meta()->offsets[Type::Index()])); } template const Type *Get() const { - return (const Type*)_dataptr(_meta->offsets[Type::Index()]); + return static_cast(_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(_data); + } void *_data; + Interfaces(const Interfaces &other); + Interfaces &operator=(const Interfaces &other); + + void swap(Interfaces &other) { + std::swap(_data, other._data); + } + }; template diff --git a/Telegram/SourceFiles/window.cpp b/Telegram/SourceFiles/window.cpp index 89fbecc527..801b0d0f24 100644 --- a/Telegram/SourceFiles/window.cpp +++ b/Telegram/SourceFiles/window.cpp @@ -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(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) {