mirror of https://github.com/procxx/kepka.git
audio player done
This commit is contained in:
parent
61a2a44584
commit
1268774517
|
@ -368,6 +368,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
|||
"lng_profile_files_header" = "Files overview";
|
||||
"lng_profile_audios" = "{count:_not_used_|# voice message|# voice messages} »";
|
||||
"lng_profile_audios_header" = "Voice messages overview";
|
||||
"lng_profile_audio_files_header" = "Playlist";
|
||||
"lng_profile_show_all_types" = "Show all types";
|
||||
"lng_profile_copy_phone" = "Copy phone number";
|
||||
|
||||
|
@ -602,7 +603,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_new_version_wrap" = "Telegram Desktop was updated to version {version}\n\n{changes}\n\nFull version history is available here:\n{link}";
|
||||
"lng_new_version_minor" = "— Bug fixes and other minor improvements";
|
||||
"lng_new_version_text" = "— Forward photos, media and stickers with drag-n-drop\n— Drag-n-drop text messages by timestamp to forward them\n— Larger stickers panel\n— IPv6 checkbox added to Connection Type in Settings";
|
||||
"lng_new_version_text" = "— Improved in-app media playback\n— Bug fixes and other minor improvements";
|
||||
|
||||
"lng_menu_insert_unicode" = "Insert Unicode control character";
|
||||
|
||||
|
|
|
@ -1971,3 +1971,29 @@ botDescSkip: 8px;
|
|||
|
||||
suppressAll: 0.2;
|
||||
suppressSong: 0.05;
|
||||
|
||||
playerHeight: 44px;
|
||||
playerBg: #e4e9ef;
|
||||
playerFg: #54748f;
|
||||
playerTimeFg: #a4afba;
|
||||
playerLineHeight: 3px;
|
||||
playerMoverSize: size(2px, 7px);
|
||||
playerLineActive: #6389a8;
|
||||
playerLineInactive: #bac7d4;
|
||||
playerSkip: 8px;
|
||||
playerNameStyle: textStyle(defaultTextStyle) {
|
||||
lnkColor: #6389a8;
|
||||
lnkDownColor: #6389a8;
|
||||
lnkFlags: font(fsize semibold);
|
||||
lnkOverFlags: font(fsize semibold);
|
||||
}
|
||||
playerPlay: sprite(377px, 109px, 19px, 22px);
|
||||
playerPause: sprite(379px, 131px, 17px, 20px);
|
||||
playerNext: sprite(374px, 151px, 22px, 14px);
|
||||
playerPrev: sprite(374px, 165px, 22px, 14px);
|
||||
playerClose: sprite(361px, 97px, 12px, 12px);
|
||||
playerFull: sprite(365px, 109px, 12px, 12px);
|
||||
playerVolume: sprite(352px, 179px, 44px, 12px);
|
||||
playerInactiveOpacity: 0.8;
|
||||
playerUnavailableOpacity: 0.3;
|
||||
playerDuration: 200;
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 168 KiB |
Binary file not shown.
Before Width: | Height: | Size: 221 KiB After Width: | Height: | Size: 222 KiB |
|
@ -273,8 +273,9 @@ _loader(new AudioPlayerLoaders(&_loaderThread)) {
|
|||
connect(this, SIGNAL(suppressSong()), _fader, SLOT(onSuppressSong()));
|
||||
connect(this, SIGNAL(unsuppressSong()), _fader, SLOT(onUnsuppressSong()));
|
||||
connect(this, SIGNAL(suppressAll()), _fader, SLOT(onSuppressAll()));
|
||||
connect(this, SIGNAL(loaderOnStart(const AudioMsgId&)), _loader, SLOT(onStart(const AudioMsgId&)));
|
||||
connect(this, SIGNAL(loaderOnStart(const SongMsgId&)), _loader, SLOT(onStart(const SongMsgId&)));
|
||||
connect(this, SIGNAL(songVolumeChanged()), _fader, SLOT(onSongVolumeChanged()));
|
||||
connect(this, SIGNAL(loaderOnStart(const AudioMsgId&,qint64)), _loader, SLOT(onStart(const AudioMsgId&,qint64)));
|
||||
connect(this, SIGNAL(loaderOnStart(const SongMsgId&,qint64)), _loader, SLOT(onStart(const SongMsgId&,qint64)));
|
||||
connect(this, SIGNAL(loaderOnCancel(const AudioMsgId&)), _loader, SLOT(onCancel(const AudioMsgId&)));
|
||||
connect(this, SIGNAL(loaderOnCancel(const SongMsgId&)), _loader, SLOT(onCancel(const SongMsgId&)));
|
||||
connect(&_faderThread, SIGNAL(started()), _fader, SLOT(onInit()));
|
||||
|
@ -292,6 +293,8 @@ _loader(new AudioPlayerLoaders(&_loaderThread)) {
|
|||
connect(_fader, SIGNAL(audioStopped(const SongMsgId&)), this, SLOT(onStopped(const SongMsgId&)));
|
||||
connect(_fader, SIGNAL(error(const AudioMsgId&)), this, SLOT(onError(const AudioMsgId&)));
|
||||
connect(_fader, SIGNAL(error(const SongMsgId&)), this, SLOT(onError(const SongMsgId&)));
|
||||
connect(this, SIGNAL(stoppedOnError(const AudioMsgId&)), this, SIGNAL(stopped(const AudioMsgId&)), Qt::QueuedConnection);
|
||||
connect(this, SIGNAL(stoppedOnError(const SongMsgId&)), this, SIGNAL(stopped(const SongMsgId&)), Qt::QueuedConnection);
|
||||
_loaderThread.start();
|
||||
_faderThread.start();
|
||||
}
|
||||
|
@ -335,12 +338,12 @@ AudioPlayer::~AudioPlayer() {
|
|||
}
|
||||
|
||||
void AudioPlayer::onError(const AudioMsgId &audio) {
|
||||
emit stopped(audio);
|
||||
emit stoppedOnError(audio);
|
||||
emit unsuppressSong();
|
||||
}
|
||||
|
||||
void AudioPlayer::onError(const SongMsgId &song) {
|
||||
emit stopped(song);
|
||||
emit stoppedOnError(song);
|
||||
}
|
||||
|
||||
void AudioPlayer::onStopped(const AudioMsgId &audio) {
|
||||
|
@ -366,20 +369,20 @@ bool AudioPlayer::updateCurrentStarted(MediaOverviewType type, int32 pos) {
|
|||
} else {
|
||||
pos = 0;
|
||||
}
|
||||
}
|
||||
if (!_checkALError()) {
|
||||
data->state = AudioPlayerStopped;
|
||||
setStoppedState(data, AudioPlayerStoppedAtError);
|
||||
switch (type) {
|
||||
case OverviewAudios: onError(_audioData[_audioCurrent].audio); break;
|
||||
case OverviewDocuments: onError(_songData[_songCurrent].song); break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
data->started = data->position = pos + data->skipStart;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioPlayer::startedOther(MediaOverviewType type, bool &fadedStart) {
|
||||
bool AudioPlayer::fadedStop(MediaOverviewType type, bool *fadedStart) {
|
||||
Msg *current = 0;
|
||||
switch (type) {
|
||||
case OverviewAudios: current = &_audioData[_audioCurrent]; break;
|
||||
|
@ -393,20 +396,21 @@ bool AudioPlayer::startedOther(MediaOverviewType type, bool &fadedStart) {
|
|||
case AudioPlayerPlaying:
|
||||
current->state = AudioPlayerFinishing;
|
||||
updateCurrentStarted(type);
|
||||
fadedStart = true;
|
||||
if (fadedStart) *fadedStart = true;
|
||||
break;
|
||||
case AudioPlayerPausing:
|
||||
current->state = AudioPlayerFinishing;
|
||||
fadedStart = true;
|
||||
if (fadedStart) *fadedStart = true;
|
||||
break;
|
||||
case AudioPlayerPaused:
|
||||
current->state = AudioPlayerStopped;
|
||||
case AudioPlayerPausedAtEnd:
|
||||
setStoppedState(current);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AudioPlayer::play(const AudioMsgId &audio) {
|
||||
void AudioPlayer::play(const AudioMsgId &audio, int64 position) {
|
||||
AudioMsgId stopped;
|
||||
{
|
||||
QMutexLocker lock(&playerMutex);
|
||||
|
@ -414,7 +418,7 @@ void AudioPlayer::play(const AudioMsgId &audio) {
|
|||
bool fadedStart = false;
|
||||
AudioMsg *current = &_audioData[_audioCurrent];
|
||||
if (current->audio != audio) {
|
||||
if (startedOther(OverviewAudios, fadedStart)) {
|
||||
if (fadedStop(OverviewAudios, &fadedStart)) {
|
||||
stopped = current->audio;
|
||||
}
|
||||
if (current->audio) {
|
||||
|
@ -438,19 +442,19 @@ void AudioPlayer::play(const AudioMsgId &audio) {
|
|||
current->fname = audio.audio->already(true);
|
||||
current->data = audio.audio->data;
|
||||
if (current->fname.isEmpty() && current->data.isEmpty()) {
|
||||
current->state = AudioPlayerStopped;
|
||||
setStoppedState(current, AudioPlayerStoppedAtError);
|
||||
onError(audio);
|
||||
} else if (updateCurrentStarted(OverviewAudios, 0)) {
|
||||
} else {
|
||||
current->state = fadedStart ? AudioPlayerStarting : AudioPlayerPlaying;
|
||||
current->loading = true;
|
||||
emit loaderOnStart(audio);
|
||||
emit loaderOnStart(audio, position);
|
||||
emit suppressSong();
|
||||
}
|
||||
}
|
||||
if (stopped) emit updated(stopped);
|
||||
}
|
||||
|
||||
void AudioPlayer::play(const SongMsgId &song) {
|
||||
void AudioPlayer::play(const SongMsgId &song, int64 position) {
|
||||
SongMsgId stopped;
|
||||
{
|
||||
QMutexLocker lock(&playerMutex);
|
||||
|
@ -458,7 +462,7 @@ void AudioPlayer::play(const SongMsgId &song) {
|
|||
bool fadedStart = false;
|
||||
SongMsg *current = &_songData[_songCurrent];
|
||||
if (current->song != song) {
|
||||
if (startedOther(OverviewDocuments, fadedStart)) {
|
||||
if (fadedStop(OverviewDocuments, &fadedStart)) {
|
||||
stopped = current->song;
|
||||
}
|
||||
if (current->song) {
|
||||
|
@ -482,18 +486,38 @@ void AudioPlayer::play(const SongMsgId &song) {
|
|||
current->fname = song.song->already(true);
|
||||
current->data = song.song->data;
|
||||
if (current->fname.isEmpty() && current->data.isEmpty()) {
|
||||
current->state = AudioPlayerStopped;
|
||||
onError(song);
|
||||
} else if (updateCurrentStarted(OverviewDocuments, 0)) {
|
||||
setStoppedState(current);
|
||||
if (!song.song->loader) {
|
||||
DocumentOpenLink::doOpen(song.song);
|
||||
song.song->openOnSave = song.song->openOnSaveMsgId = 0;
|
||||
if (song.song->loader) song.song->loader->start(true, true);
|
||||
}
|
||||
} else {
|
||||
current->state = fadedStart ? AudioPlayerStarting : AudioPlayerPlaying;
|
||||
current->loading = true;
|
||||
emit loaderOnStart(song);
|
||||
emit loaderOnStart(song, position);
|
||||
}
|
||||
}
|
||||
if (stopped) emit updated(stopped);
|
||||
}
|
||||
|
||||
void AudioPlayer::pauseresume(MediaOverviewType type) {
|
||||
bool AudioPlayer::checkCurrentALError(MediaOverviewType type) {
|
||||
if (_checkALError()) return true;
|
||||
|
||||
switch (type) {
|
||||
case OverviewAudios:
|
||||
setStoppedState(&_audioData[_audioCurrent], AudioPlayerStoppedAtError);
|
||||
onError(_audioData[_audioCurrent].audio);
|
||||
break;
|
||||
case OverviewDocuments:
|
||||
setStoppedState(&_songData[_songCurrent], AudioPlayerStoppedAtError);
|
||||
onError(_songData[_songCurrent].song);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AudioPlayer::pauseresume(MediaOverviewType type, bool fast) {
|
||||
QMutexLocker lock(&playerMutex);
|
||||
|
||||
Msg *current = 0;
|
||||
|
@ -505,21 +529,38 @@ void AudioPlayer::pauseresume(MediaOverviewType type) {
|
|||
break;
|
||||
case OverviewDocuments:
|
||||
current = &_songData[_songCurrent];
|
||||
suppressGain = suppressSongGain;
|
||||
suppressGain = suppressSongGain * cSongVolume();
|
||||
break;
|
||||
}
|
||||
switch (current->state) {
|
||||
case AudioPlayerPausing:
|
||||
case AudioPlayerPaused:
|
||||
case AudioPlayerPausedAtEnd: {
|
||||
if (current->state == AudioPlayerPaused) {
|
||||
updateCurrentStarted(type);
|
||||
} else if (current->state == AudioPlayerPausedAtEnd) {
|
||||
if (alIsSource(current->source)) {
|
||||
alSourcei(current->source, AL_SAMPLE_OFFSET, qMax(current->position - current->skipStart, 0LL));
|
||||
if (!checkCurrentALError(type)) return;
|
||||
}
|
||||
current->state = AudioPlayerResuming;
|
||||
resumeDevice();
|
||||
}
|
||||
current->state = fast ? AudioPlayerPlaying : AudioPlayerResuming;
|
||||
|
||||
ALint state = AL_INITIAL;
|
||||
alGetSourcei(current->source, AL_SOURCE_STATE, &state);
|
||||
if (!checkCurrentALError(type)) return;
|
||||
|
||||
if (state != AL_PLAYING) {
|
||||
audioPlayer()->resumeDevice();
|
||||
|
||||
alSourcef(current->source, AL_GAIN, suppressGain);
|
||||
if (!checkCurrentALError(type)) return;
|
||||
|
||||
alSourcePlay(current->source);
|
||||
if (!checkCurrentALError(type)) return;
|
||||
}
|
||||
if (type == OverviewAudios) emit suppressSong();
|
||||
break;
|
||||
} break;
|
||||
case AudioPlayerStarting:
|
||||
case AudioPlayerResuming:
|
||||
case AudioPlayerPlaying:
|
||||
|
@ -532,6 +573,78 @@ void AudioPlayer::pauseresume(MediaOverviewType type) {
|
|||
emit faderOnTimer();
|
||||
}
|
||||
|
||||
void AudioPlayer::seek(int64 position) {
|
||||
QMutexLocker lock(&playerMutex);
|
||||
|
||||
MediaOverviewType type = OverviewDocuments;
|
||||
Msg *current = 0;
|
||||
float64 suppressGain = 1.;
|
||||
AudioMsgId audio;
|
||||
SongMsgId song;
|
||||
switch (type) {
|
||||
case OverviewAudios:
|
||||
current = &_audioData[_audioCurrent];
|
||||
audio = _audioData[_audioCurrent].audio;
|
||||
suppressGain = suppressAllGain;
|
||||
break;
|
||||
case OverviewDocuments:
|
||||
current = &_songData[_songCurrent];
|
||||
song = _songData[_songCurrent].song;
|
||||
suppressGain = suppressSongGain * cSongVolume();
|
||||
break;
|
||||
}
|
||||
|
||||
bool isSource = alIsSource(current->source);
|
||||
bool fastSeek = (position >= current->skipStart && position < current->duration - current->skipEnd - (current->skipEnd ? AudioVoiceMsgFrequency : 0));
|
||||
if (fastSeek && isSource) {
|
||||
alSourcei(current->source, AL_SAMPLE_OFFSET, position - current->skipStart);
|
||||
if (!checkCurrentALError(type)) return;
|
||||
alSourcef(current->source, AL_GAIN, 1. * suppressGain);
|
||||
if (!checkCurrentALError(type)) return;
|
||||
updateCurrentStarted(type, position - current->skipStart);
|
||||
} else {
|
||||
setStoppedState(current);
|
||||
if (isSource) alSourceStop(current->source);
|
||||
}
|
||||
switch (current->state) {
|
||||
case AudioPlayerPausing:
|
||||
case AudioPlayerPaused:
|
||||
case AudioPlayerPausedAtEnd: {
|
||||
if (current->state == AudioPlayerPausedAtEnd) {
|
||||
current->state = AudioPlayerPaused;
|
||||
}
|
||||
lock.unlock();
|
||||
return pauseresume(type, true);
|
||||
} break;
|
||||
case AudioPlayerStarting:
|
||||
case AudioPlayerResuming:
|
||||
case AudioPlayerPlaying:
|
||||
current->state = AudioPlayerPausing;
|
||||
updateCurrentStarted(type);
|
||||
if (type == OverviewAudios) emit unsuppressSong();
|
||||
break;
|
||||
case AudioPlayerFinishing:
|
||||
case AudioPlayerStopped:
|
||||
case AudioPlayerStoppedAtEnd:
|
||||
case AudioPlayerStoppedAtError:
|
||||
case AudioPlayerStoppedAtStart:
|
||||
lock.unlock();
|
||||
switch (type) {
|
||||
case OverviewAudios: if (audio) return play(audio, position);
|
||||
case OverviewDocuments: if (song) return play(song, position);
|
||||
}
|
||||
}
|
||||
emit faderOnTimer();
|
||||
}
|
||||
|
||||
void AudioPlayer::stop(MediaOverviewType type) {
|
||||
fadedStop(type);
|
||||
switch (type) {
|
||||
case OverviewAudios: if (_audioData[_audioCurrent].audio) emit updated(_audioData[_audioCurrent].audio); break;
|
||||
case OverviewDocuments: if (_songData[_songCurrent].song) emit updated(_songData[_songCurrent].song); break;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioPlayer::currentState(AudioMsgId *audio, AudioPlayerState *state, int64 *position, int64 *duration, int32 *frequency) {
|
||||
QMutexLocker lock(&playerMutex);
|
||||
AudioMsg *current = &_audioData[_audioCurrent];
|
||||
|
@ -553,17 +666,22 @@ void AudioPlayer::currentState(Msg *current, AudioPlayerState *state, int64 *pos
|
|||
if (frequency) *frequency = current->frequency;
|
||||
}
|
||||
|
||||
void AudioPlayer::setStoppedState(Msg *current, AudioPlayerState state) {
|
||||
current->state = state;
|
||||
current->position = 0;
|
||||
}
|
||||
|
||||
void AudioPlayer::clearStoppedAtStart(const AudioMsgId &audio) {
|
||||
QMutexLocker lock(&playerMutex);
|
||||
if (_audioData[_audioCurrent].audio == audio && _audioData[_audioCurrent].state == AudioPlayerStoppedAtStart) {
|
||||
_audioData[_audioCurrent].state = AudioPlayerStopped;
|
||||
setStoppedState(&_audioData[_audioCurrent]);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioPlayer::clearStoppedAtStart(const SongMsgId &song) {
|
||||
QMutexLocker lock(&playerMutex);
|
||||
if (_songData[_songCurrent].song == song && _songData[_songCurrent].state == AudioPlayerStoppedAtStart) {
|
||||
_songData[_songCurrent].state = AudioPlayerStopped;
|
||||
setStoppedState(&_songData[_songCurrent]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -676,7 +794,7 @@ void AudioPlayerFader::onTimer() {
|
|||
|
||||
for (int32 i = 0; i < AudioVoiceMsgSimultaneously; ++i) {
|
||||
AudioPlayer::AudioMsg &m(voice->_audioData[i]);
|
||||
if (m.state == AudioPlayerStopped || m.state == AudioPlayerStoppedAtStart || m.state == AudioPlayerPaused || !m.source) continue;
|
||||
if ((m.state & AudioPlayerStoppedMask) || m.state == AudioPlayerPaused || !m.source) continue;
|
||||
|
||||
int32 emitSignals = updateOnePlayback(&m, hasPlaying, hasFading, suppressAllGain, suppressAudioChanged);
|
||||
if (emitSignals & EmitError) emit error(m.audio);
|
||||
|
@ -687,14 +805,15 @@ void AudioPlayerFader::onTimer() {
|
|||
|
||||
for (int32 i = 0; i < AudioSongSimultaneously; ++i) {
|
||||
AudioPlayer::SongMsg &m(voice->_songData[i]);
|
||||
if (m.state == AudioPlayerStopped || m.state == AudioPlayerStoppedAtStart || m.state == AudioPlayerPaused || !m.source) continue;
|
||||
if ((m.state & AudioPlayerStoppedMask) || m.state == AudioPlayerPaused || !m.source) continue;
|
||||
|
||||
int32 emitSignals = updateOnePlayback(&m, hasPlaying, hasFading, suppressSongGain, suppressSongChanged);
|
||||
int32 emitSignals = updateOnePlayback(&m, hasPlaying, hasFading, suppressSongGain * cSongVolume(), suppressSongChanged || _songVolumeChanged);
|
||||
if (emitSignals & EmitError) emit error(m.song);
|
||||
if (emitSignals & EmitStopped) emit audioStopped(m.song);
|
||||
if (emitSignals & EmitPositionUpdated) emit playPositionUpdated(m.song);
|
||||
if (emitSignals & EmitNeedToPreload) emit needToPreload(m.song);
|
||||
}
|
||||
_songVolumeChanged = false;
|
||||
|
||||
if (!hasFading) {
|
||||
if (!hasPlaying) {
|
||||
|
@ -724,11 +843,9 @@ int32 AudioPlayerFader::updateOnePlayback(AudioPlayer::Msg *m, bool &hasPlaying,
|
|||
ALint pos = 0;
|
||||
ALint state = AL_INITIAL;
|
||||
alGetSourcei(m->source, AL_SAMPLE_OFFSET, &pos);
|
||||
if (!_checkALError()) { setStoppedState(m, AudioPlayerStoppedAtError); return EmitError; }
|
||||
alGetSourcei(m->source, AL_SOURCE_STATE, &state);
|
||||
if (!_checkALError()) {
|
||||
m->state = AudioPlayerStopped;
|
||||
return EmitError;
|
||||
}
|
||||
if (!_checkALError()) { setStoppedState(m, AudioPlayerStoppedAtError); return EmitError; }
|
||||
|
||||
int32 emitSignals = 0;
|
||||
switch (m->state) {
|
||||
|
@ -746,17 +863,33 @@ int32 AudioPlayerFader::updateOnePlayback(AudioPlayer::Msg *m, bool &hasPlaying,
|
|||
if (state != AL_PLAYING) {
|
||||
fading = false;
|
||||
if (m->source) {
|
||||
alSourcef(m->source, AL_GAIN, 1);
|
||||
alSourceStop(m->source);
|
||||
if (!_checkALError()) { setStoppedState(m, AudioPlayerStoppedAtError); return EmitError; }
|
||||
alSourcef(m->source, AL_GAIN, 1);
|
||||
if (!_checkALError()) { setStoppedState(m, AudioPlayerStoppedAtError); return EmitError; }
|
||||
}
|
||||
if (m->state == AudioPlayerPausing) {
|
||||
m->state = AudioPlayerPausedAtEnd;
|
||||
} else {
|
||||
setStoppedState(m, AudioPlayerStoppedAtEnd);
|
||||
}
|
||||
m->state = AudioPlayerStopped;
|
||||
emitSignals |= EmitStopped;
|
||||
} else if (1000 * (pos + m->skipStart - m->started) >= AudioFadeDuration * m->frequency) {
|
||||
fading = false;
|
||||
alSourcef(m->source, AL_GAIN, 1. * suppressGain);
|
||||
if (!_checkALError()) { setStoppedState(m, AudioPlayerStoppedAtError); return EmitError; }
|
||||
switch (m->state) {
|
||||
case AudioPlayerFinishing: alSourceStop(m->source); m->state = AudioPlayerStopped; break;
|
||||
case AudioPlayerPausing: alSourcePause(m->source); m->state = AudioPlayerPaused; break;
|
||||
case AudioPlayerFinishing:
|
||||
alSourceStop(m->source);
|
||||
if (!_checkALError()) { setStoppedState(m, AudioPlayerStoppedAtError); return EmitError; }
|
||||
setStoppedState(m);
|
||||
state = AL_STOPPED;
|
||||
break;
|
||||
case AudioPlayerPausing:
|
||||
alSourcePause(m->source);
|
||||
if (!_checkALError()) { setStoppedState(m, AudioPlayerStoppedAtError); return EmitError; }
|
||||
m->state = AudioPlayerPaused;
|
||||
break;
|
||||
case AudioPlayerStarting:
|
||||
case AudioPlayerResuming:
|
||||
m->state = AudioPlayerPlaying;
|
||||
|
@ -769,18 +902,22 @@ int32 AudioPlayerFader::updateOnePlayback(AudioPlayer::Msg *m, bool &hasPlaying,
|
|||
newGain = 1. - newGain;
|
||||
}
|
||||
alSourcef(m->source, AL_GAIN, newGain * suppressGain);
|
||||
if (!_checkALError()) { setStoppedState(m, AudioPlayerStoppedAtError); return EmitError; }
|
||||
}
|
||||
} else if (playing && (state == AL_PLAYING || !m->loading)) {
|
||||
if (state != AL_PLAYING) {
|
||||
playing = false;
|
||||
if (m->source) {
|
||||
alSourceStop(m->source);
|
||||
if (!_checkALError()) { setStoppedState(m, AudioPlayerStoppedAtError); return EmitError; }
|
||||
alSourcef(m->source, AL_GAIN, 1);
|
||||
if (!_checkALError()) { setStoppedState(m, AudioPlayerStoppedAtError); return EmitError; }
|
||||
}
|
||||
m->state = AudioPlayerStopped;
|
||||
setStoppedState(m, AudioPlayerStoppedAtEnd);
|
||||
emitSignals |= EmitStopped;
|
||||
} else if (suppressGainChanged) {
|
||||
alSourcef(m->source, AL_GAIN, suppressGain);
|
||||
if (!_checkALError()) { setStoppedState(m, AudioPlayerStoppedAtError); return EmitError; }
|
||||
}
|
||||
}
|
||||
if (state == AL_PLAYING && pos + m->skipStart - m->position >= AudioCheckPositionDelta) {
|
||||
|
@ -799,6 +936,11 @@ int32 AudioPlayerFader::updateOnePlayback(AudioPlayer::Msg *m, bool &hasPlaying,
|
|||
return emitSignals;
|
||||
}
|
||||
|
||||
void AudioPlayerFader::setStoppedState(AudioPlayer::Msg *m, AudioPlayerState state) {
|
||||
m->state = state;
|
||||
m->position = 0;
|
||||
}
|
||||
|
||||
void AudioPlayerFader::onPauseTimer() {
|
||||
QMutexLocker lock(&_pauseMutex);
|
||||
if (_pauseFlag) {
|
||||
|
@ -838,6 +980,11 @@ void AudioPlayerFader::onSuppressAll() {
|
|||
onTimer();
|
||||
}
|
||||
|
||||
void AudioPlayerFader::onSongVolumeChanged() {
|
||||
_songVolumeChanged = true;
|
||||
onTimer();
|
||||
}
|
||||
|
||||
void AudioPlayerFader::resumeDevice() {
|
||||
QMutexLocker lock(&_pauseMutex);
|
||||
_pauseFlag = false;
|
||||
|
@ -859,7 +1006,7 @@ public:
|
|||
return this->fname == fname && this->data.size() == data.size();
|
||||
}
|
||||
|
||||
virtual bool open() = 0;
|
||||
virtual bool open(qint64 position = 0) = 0;
|
||||
virtual int64 duration() = 0;
|
||||
virtual int32 frequency() = 0;
|
||||
virtual int32 format() = 0;
|
||||
|
@ -904,7 +1051,7 @@ public:
|
|||
frame = av_frame_alloc();
|
||||
}
|
||||
|
||||
bool open() {
|
||||
bool open(qint64 position = 0) {
|
||||
if (!AudioPlayerLoader::openFile()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -950,7 +1097,7 @@ public:
|
|||
}
|
||||
|
||||
freq = fmtContext->streams[streamId]->codec->sample_rate;
|
||||
len = (fmtContext->streams[streamId]->duration * freq) / fmtContext->streams[streamId]->time_base.den;
|
||||
len = (fmtContext->streams[streamId]->duration * freq * fmtContext->streams[streamId]->time_base.num) / fmtContext->streams[streamId]->time_base.den;
|
||||
uint64_t layout = fmtContext->streams[streamId]->codec->channel_layout;
|
||||
inputFormat = fmtContext->streams[streamId]->codec->sample_fmt;
|
||||
switch (layout) {
|
||||
|
@ -1016,6 +1163,16 @@ public:
|
|||
return false;
|
||||
}
|
||||
}
|
||||
if (position) {
|
||||
int64 ts = (position * fmtContext->streams[streamId]->time_base.den) / (freq * fmtContext->streams[streamId]->time_base.num);
|
||||
if (av_seek_frame(fmtContext, streamId, ts, AVSEEK_FLAG_ANY) < 0) {
|
||||
if (av_seek_frame(fmtContext, streamId, ts, 0) < 0) {
|
||||
}
|
||||
}
|
||||
//if (dstSamplesData) {
|
||||
// position = qRound(srcRate * (position / float64(dstRate)));
|
||||
//}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1180,18 +1337,18 @@ AudioPlayerLoaders::~AudioPlayerLoaders() {
|
|||
void AudioPlayerLoaders::onInit() {
|
||||
}
|
||||
|
||||
void AudioPlayerLoaders::onStart(const AudioMsgId &audio) {
|
||||
void AudioPlayerLoaders::onStart(const AudioMsgId &audio, qint64 position) {
|
||||
_audio = AudioMsgId();
|
||||
delete _audioLoader;
|
||||
_audioLoader = 0;
|
||||
onLoad(audio);
|
||||
loadData(OverviewAudios, static_cast<const void*>(&audio), position);
|
||||
}
|
||||
|
||||
void AudioPlayerLoaders::onStart(const SongMsgId &song) {
|
||||
void AudioPlayerLoaders::onStart(const SongMsgId &song, qint64 position) {
|
||||
_song = SongMsgId();
|
||||
delete _songLoader;
|
||||
_songLoader = 0;
|
||||
onLoad(song);
|
||||
loadData(OverviewDocuments, static_cast<const void*>(&song), position);
|
||||
}
|
||||
|
||||
void AudioPlayerLoaders::clear(MediaOverviewType type) {
|
||||
|
@ -1201,6 +1358,11 @@ void AudioPlayerLoaders::clear(MediaOverviewType type) {
|
|||
}
|
||||
}
|
||||
|
||||
void AudioPlayerLoaders::setStoppedState(AudioPlayer::Msg *m, AudioPlayerState state) {
|
||||
m->state = state;
|
||||
m->position = 0;
|
||||
}
|
||||
|
||||
void AudioPlayerLoaders::emitError(MediaOverviewType type) {
|
||||
switch (type) {
|
||||
case OverviewAudios: emit error(clearAudio()); break;
|
||||
|
@ -1225,16 +1387,16 @@ SongMsgId AudioPlayerLoaders::clearSong() {
|
|||
}
|
||||
|
||||
void AudioPlayerLoaders::onLoad(const AudioMsgId &audio) {
|
||||
loadData(OverviewAudios, static_cast<const void*>(&audio));
|
||||
loadData(OverviewAudios, static_cast<const void*>(&audio), 0);
|
||||
}
|
||||
|
||||
void AudioPlayerLoaders::onLoad(const SongMsgId &song) {
|
||||
loadData(OverviewDocuments, static_cast<const void*>(&song));
|
||||
loadData(OverviewDocuments, static_cast<const void*>(&song), 0);
|
||||
}
|
||||
|
||||
void AudioPlayerLoaders::loadData(MediaOverviewType type, const void *objId) {
|
||||
void AudioPlayerLoaders::loadData(MediaOverviewType type, const void *objId, qint64 position) {
|
||||
SetupError err = SetupNoErrorStarted;
|
||||
AudioPlayerLoader *l = setupLoader(type, objId, err);
|
||||
AudioPlayerLoader *l = setupLoader(type, objId, err, position);
|
||||
if (!l) {
|
||||
if (err == SetupErrorAtStart) {
|
||||
emitError(type);
|
||||
|
@ -1277,19 +1439,22 @@ void AudioPlayerLoaders::loadData(MediaOverviewType type, const void *objId) {
|
|||
}
|
||||
m->nextBuffer = 0;
|
||||
}
|
||||
m->skipStart = position;
|
||||
m->skipEnd = m->duration - position;
|
||||
m->position = 0;
|
||||
m->started = 0;
|
||||
}
|
||||
if (samplesAdded) {
|
||||
if (!m->source) {
|
||||
alGenSources(1, &m->source);
|
||||
alSourcef(m->source, AL_PITCH, 1.f);
|
||||
alSourcef(m->source, AL_GAIN, 1.f);
|
||||
alSource3f(m->source, AL_POSITION, 0, 0, 0);
|
||||
alSource3f(m->source, AL_VELOCITY, 0, 0, 0);
|
||||
alSourcei(m->source, AL_LOOPING, 0);
|
||||
}
|
||||
if (!m->buffers[m->nextBuffer]) alGenBuffers(3, m->buffers);
|
||||
if (!_checkALError()) {
|
||||
m->state = AudioPlayerStopped;
|
||||
setStoppedState(m, AudioPlayerStoppedAtError);
|
||||
emitError(type);
|
||||
return;
|
||||
}
|
||||
|
@ -1307,7 +1472,7 @@ void AudioPlayerLoaders::loadData(MediaOverviewType type, const void *objId) {
|
|||
m->nextBuffer = (m->nextBuffer + 1) % 3;
|
||||
|
||||
if (!_checkALError()) {
|
||||
m->state = AudioPlayerStopped;
|
||||
setStoppedState(m, AudioPlayerStoppedAtError);
|
||||
emitError(type);
|
||||
return;
|
||||
}
|
||||
|
@ -1326,18 +1491,34 @@ void AudioPlayerLoaders::loadData(MediaOverviewType type, const void *objId) {
|
|||
if (_checkALError()) {
|
||||
if (state != AL_PLAYING) {
|
||||
audioPlayer()->resumeDevice();
|
||||
|
||||
switch (type) {
|
||||
case OverviewAudios: alSourcef(m->source, AL_GAIN, suppressAllGain); break;
|
||||
case OverviewDocuments: alSourcef(m->source, AL_GAIN, suppressSongGain); break;
|
||||
case OverviewDocuments: alSourcef(m->source, AL_GAIN, suppressSongGain * cSongVolume()); break;
|
||||
}
|
||||
if (!_checkALError()) {
|
||||
setStoppedState(m, AudioPlayerStoppedAtError);
|
||||
emitError(type);
|
||||
return;
|
||||
}
|
||||
|
||||
alSourcePlay(m->source);
|
||||
if (!_checkALError()) {
|
||||
setStoppedState(m, AudioPlayerStoppedAtError);
|
||||
emitError(type);
|
||||
return;
|
||||
}
|
||||
|
||||
emit needToCheck();
|
||||
}
|
||||
} else {
|
||||
setStoppedState(m, AudioPlayerStoppedAtError);
|
||||
emitError(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AudioPlayerLoader *AudioPlayerLoaders::setupLoader(MediaOverviewType type, const void *objId, SetupError &err) {
|
||||
AudioPlayerLoader *AudioPlayerLoaders::setupLoader(MediaOverviewType type, const void *objId, SetupError &err, qint64 position) {
|
||||
err = SetupErrorAtStart;
|
||||
QMutexLocker lock(&playerMutex);
|
||||
AudioPlayer *voice = audioPlayer();
|
||||
|
@ -1410,7 +1591,7 @@ AudioPlayerLoader *AudioPlayerLoaders::setupLoader(MediaOverviewType type, const
|
|||
*l = new FFMpegLoader(m->fname, m->data);
|
||||
|
||||
int ret;
|
||||
if (!(*l)->open()) {
|
||||
if (!(*l)->open(position)) {
|
||||
m->state = AudioPlayerStoppedAtStart;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1422,10 +1603,6 @@ AudioPlayerLoader *AudioPlayerLoaders::setupLoader(MediaOverviewType type, const
|
|||
m->duration = duration;
|
||||
m->frequency = (*l)->frequency();
|
||||
if (!m->frequency) m->frequency = AudioVoiceMsgFrequency;
|
||||
m->skipStart = 0;
|
||||
m->skipEnd = duration;
|
||||
m->position = 0;
|
||||
m->started = 0;
|
||||
err = SetupNoErrorStarted;
|
||||
} else {
|
||||
if (!m->skipEnd) {
|
||||
|
@ -1985,7 +2162,7 @@ public:
|
|||
_opened(false) {
|
||||
}
|
||||
|
||||
bool open() {
|
||||
bool open(qint64 position = 0) {
|
||||
if (!AudioPlayerLoader::openFile()) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -25,14 +25,19 @@ void audioPlayNotify();
|
|||
void audioFinish();
|
||||
|
||||
enum AudioPlayerState {
|
||||
AudioPlayerStopped,
|
||||
AudioPlayerStoppedAtStart,
|
||||
AudioPlayerStarting,
|
||||
AudioPlayerPlaying,
|
||||
AudioPlayerFinishing,
|
||||
AudioPlayerPausing,
|
||||
AudioPlayerPaused,
|
||||
AudioPlayerResuming,
|
||||
AudioPlayerStopped = 0x01,
|
||||
AudioPlayerStoppedAtEnd = 0x02,
|
||||
AudioPlayerStoppedAtError = 0x03,
|
||||
AudioPlayerStoppedAtStart = 0x04,
|
||||
AudioPlayerStoppedMask = 0x07,
|
||||
|
||||
AudioPlayerStarting = 0x08,
|
||||
AudioPlayerPlaying = 0x10,
|
||||
AudioPlayerFinishing = 0x18,
|
||||
AudioPlayerPausing = 0x20,
|
||||
AudioPlayerPaused = 0x28,
|
||||
AudioPlayerPausedAtEnd = 0x30,
|
||||
AudioPlayerResuming = 0x38,
|
||||
};
|
||||
|
||||
class AudioPlayerFader;
|
||||
|
@ -45,9 +50,11 @@ public:
|
|||
|
||||
AudioPlayer();
|
||||
|
||||
void play(const AudioMsgId &audio);
|
||||
void play(const SongMsgId &song);
|
||||
void pauseresume(MediaOverviewType type);
|
||||
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 stop(MediaOverviewType type);
|
||||
|
||||
void currentState(AudioMsgId *audio, AudioPlayerState *state = 0, int64 *position = 0, int64 *duration = 0, int32 *frequency = 0);
|
||||
void currentState(SongMsgId *song, AudioPlayerState *state = 0, int64 *position = 0, int64 *duration = 0, int32 *frequency = 0);
|
||||
|
@ -75,21 +82,28 @@ signals:
|
|||
void stopped(const AudioMsgId &audio);
|
||||
void stopped(const SongMsgId &song);
|
||||
|
||||
void loaderOnStart(const AudioMsgId &audio);
|
||||
void loaderOnStart(const SongMsgId &song);
|
||||
void stoppedOnError(const AudioMsgId &audio);
|
||||
void stoppedOnError(const SongMsgId &song);
|
||||
|
||||
void loaderOnStart(const AudioMsgId &audio, qint64 position);
|
||||
void loaderOnStart(const SongMsgId &song, qint64 position);
|
||||
|
||||
void loaderOnCancel(const AudioMsgId &audio);
|
||||
void loaderOnCancel(const SongMsgId &song);
|
||||
|
||||
void faderOnTimer();
|
||||
|
||||
void suppressSong();
|
||||
void unsuppressSong();
|
||||
void suppressAll();
|
||||
|
||||
void songVolumeChanged();
|
||||
|
||||
private:
|
||||
|
||||
bool startedOther(MediaOverviewType type, bool &fadedStart);
|
||||
bool fadedStop(MediaOverviewType type, bool *fadedStart = 0);
|
||||
bool updateCurrentStarted(MediaOverviewType type, int32 pos = -1);
|
||||
bool checkCurrentALError(MediaOverviewType type);
|
||||
|
||||
struct Msg {
|
||||
Msg() : position(0), duration(0), frequency(AudioVoiceMsgFrequency), skipStart(0), skipEnd(0), loading(0), started(0),
|
||||
|
@ -124,6 +138,7 @@ private:
|
|||
};
|
||||
|
||||
void currentState(Msg *current, AudioPlayerState *state, int64 *position, int64 *duration, int32 *frequency);
|
||||
void setStoppedState(Msg *current, AudioPlayerState state = AudioPlayerStopped);
|
||||
|
||||
int32 _audioCurrent;
|
||||
AudioMsg _audioData[AudioVoiceMsgSimultaneously];
|
||||
|
@ -210,6 +225,7 @@ public slots:
|
|||
void onSuppressSong();
|
||||
void onUnsuppressSong();
|
||||
void onSuppressAll();
|
||||
void onSongVolumeChanged();
|
||||
|
||||
private:
|
||||
|
||||
|
@ -220,12 +236,13 @@ private:
|
|||
EmitNeedToPreload = 0x08,
|
||||
};
|
||||
int32 updateOnePlayback(AudioPlayer::Msg *m, bool &hasPlaying, bool &hasFading, float64 suppressGain, bool suppressGainChanged);
|
||||
void setStoppedState(AudioPlayer::Msg *m, AudioPlayerState state = AudioPlayerStopped);
|
||||
|
||||
QTimer _timer, _pauseTimer;
|
||||
QMutex _pauseMutex;
|
||||
bool _pauseFlag, _paused;
|
||||
|
||||
bool _suppressAll, _suppressAllAnim, _suppressSong, _suppressSongAnim;
|
||||
bool _suppressAll, _suppressAllAnim, _suppressSong, _suppressSongAnim, _songVolumeChanged;
|
||||
anim::fvalue _suppressAllGain, _suppressSongGain;
|
||||
uint64 _suppressAllStart, _suppressSongStart;
|
||||
|
||||
|
@ -250,8 +267,8 @@ public slots:
|
|||
|
||||
void onInit();
|
||||
|
||||
void onStart(const AudioMsgId &audio);
|
||||
void onStart(const SongMsgId &audio);
|
||||
void onStart(const AudioMsgId &audio, qint64 position);
|
||||
void onStart(const SongMsgId &audio, qint64 position);
|
||||
|
||||
void onLoad(const AudioMsgId &audio);
|
||||
void onLoad(const SongMsgId &audio);
|
||||
|
@ -269,6 +286,7 @@ private:
|
|||
|
||||
void emitError(MediaOverviewType type);
|
||||
void clear(MediaOverviewType type);
|
||||
void setStoppedState(AudioPlayer::Msg *m, AudioPlayerState state = AudioPlayerStopped);
|
||||
AudioMsgId clearAudio();
|
||||
SongMsgId clearSong();
|
||||
|
||||
|
@ -278,8 +296,8 @@ private:
|
|||
SetupErrorLoadedFull = 2,
|
||||
SetupNoErrorStarted = 3,
|
||||
};
|
||||
void loadData(MediaOverviewType type, const void *objId);
|
||||
AudioPlayerLoader *setupLoader(MediaOverviewType type, const void *objId, SetupError &err);
|
||||
void loadData(MediaOverviewType type, const void *objId, qint64 position);
|
||||
AudioPlayerLoader *setupLoader(MediaOverviewType type, const void *objId, SetupError &err, qint64 position);
|
||||
AudioPlayer::Msg *checkLoader(MediaOverviewType type);
|
||||
|
||||
};
|
||||
|
|
|
@ -87,7 +87,7 @@ enum {
|
|||
AudioVoiceMsgSimultaneously = 4,
|
||||
AudioSongSimultaneously = 4,
|
||||
AudioCheckPositionTimeout = 100, // 100ms per check audio pos
|
||||
AudioCheckPositionDelta = 4800, // update position called each 4800 samples
|
||||
AudioCheckPositionDelta = 2400, // update position called each 2400 samples
|
||||
AudioFadeTimeout = 7, // 7ms
|
||||
AudioFadeDuration = 500,
|
||||
AudioVoiceMsgSkip = 400, // 200ms
|
||||
|
|
|
@ -1929,9 +1929,16 @@ void DialogsWidget::resizeEvent(QResizeEvent *e) {
|
|||
_addContact.move(w - _addContact.width() - st::dlgPaddingHor, _filter.y());
|
||||
_cancelSearch.move(w - _cancelSearch.width() - st::dlgPaddingHor, _filter.y());
|
||||
scroll.move(0, _filter.height() + 2 * st::dlgFilterPadding);
|
||||
|
||||
int32 addToY = App::main() ? App::main()->contentScrollAddToY() : 0;
|
||||
int32 newScrollY = scroll.scrollTop() + addToY;
|
||||
scroll.resize(w, height() - _filter.y() - _filter.height() - st::dlgFilterPadding - st::dlgPaddingVer);
|
||||
list.resize(w, list.height());
|
||||
if (addToY) {
|
||||
scroll.scrollToY(newScrollY);
|
||||
} else {
|
||||
onListScroll();
|
||||
}
|
||||
}
|
||||
|
||||
void DialogsWidget::keyPressEvent(QKeyEvent *e) {
|
||||
|
|
|
@ -2611,6 +2611,15 @@ bool MentionsInner::moveSel(int direction) {
|
|||
}
|
||||
|
||||
bool MentionsInner::select() {
|
||||
QString sel = getSelected();
|
||||
if (!sel.isEmpty()) {
|
||||
emit chosen(sel);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QString MentionsInner::getSelected() const {
|
||||
int32 maxSel = (_rows->isEmpty() ? (_hrows->isEmpty() ? _crows->size() : _hrows->size()) : _rows->size());
|
||||
if (_sel >= 0 && _sel < maxSel) {
|
||||
QString result;
|
||||
|
@ -2628,10 +2637,9 @@ bool MentionsInner::select() {
|
|||
result = '/' + command.command;
|
||||
}
|
||||
}
|
||||
emit chosen(result);
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
return QString();
|
||||
}
|
||||
|
||||
void MentionsInner::mousePressEvent(QMouseEvent *e) {
|
||||
|
@ -2991,6 +2999,10 @@ int32 MentionsDropdown::innerBottom() {
|
|||
return _scroll.scrollTop() + _scroll.height();
|
||||
}
|
||||
|
||||
QString MentionsDropdown::getSelected() const {
|
||||
return _inner.getSelected();
|
||||
}
|
||||
|
||||
bool MentionsDropdown::eventFilter(QObject *obj, QEvent *e) {
|
||||
if (isHidden()) return QWidget::eventFilter(obj, e);
|
||||
if (e->type() == QEvent::KeyPress) {
|
||||
|
|
|
@ -503,6 +503,8 @@ public:
|
|||
bool moveSel(int direction);
|
||||
bool select();
|
||||
|
||||
QString getSelected() const;
|
||||
|
||||
signals:
|
||||
|
||||
void chosen(QString mentionOrHashtag);
|
||||
|
@ -552,6 +554,7 @@ public:
|
|||
int32 innerBottom();
|
||||
|
||||
bool eventFilter(QObject *obj, QEvent *e);
|
||||
QString getSelected() const;
|
||||
|
||||
~MentionsDropdown();
|
||||
|
||||
|
|
|
@ -26,8 +26,17 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
|||
#include <QtGui/QCursor>
|
||||
#include <QtGui/QFont>
|
||||
|
||||
inline QPoint rtlpoint(int x, int y, int outerw) {
|
||||
return QPoint(rtl() ? (outerw - x) : x, y);
|
||||
}
|
||||
inline QPoint rtlpoint(const QPoint &p, int outerw) {
|
||||
return rtl() ? QPoint(outerw - p.x(), p.y()) : p;
|
||||
}
|
||||
inline QRect rtlrect(int x, int y, int w, int h, int outerw) {
|
||||
return rtl() ? QRect(outerw - x - w, y, w, h) : QRect(x, y, w, h);
|
||||
return QRect(rtl() ? (outerw - x - w) : x, y, w, h);
|
||||
}
|
||||
inline QRect rtlrect(const QRect &r, int outerw) {
|
||||
return rtl() ? QRect(outerw - r.x() - r.width(), r.y(), r.width(), r.height()) : r;
|
||||
}
|
||||
inline QRect centerrect(const QRect &inRect, const QRect &rect) {
|
||||
return QRect(inRect.x() + (inRect.width() - rect.width()) / 2, inRect.y() + (inRect.height() - rect.height()) / 2, rect.width(), rect.height());
|
||||
|
|
|
@ -24,7 +24,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
|||
|
||||
namespace {
|
||||
|
||||
const QRegularExpression _reDomain(QString::fromUtf8("(?<![\\w\\$\\-\\_%=\\.])(?:([a-zA-Z]+)://)?((?:[A-Za-zА-яА-ЯёЁ0-9\\-\\_]+\\.){1,5}([A-Za-zрф\\-\\d]{2,22})(\\:\\d+)?)"), QRegularExpression::UseUnicodePropertiesOption);
|
||||
const QRegularExpression _reDomain(QString::fromUtf8("(?<![\\w\\$\\-\\_%=\\.])(?:([a-zA-Z]+)://)?((?:[A-Za-zА-яА-ЯёЁ0-9\\-\\_]+\\.){1,10}([A-Za-zрф\\-\\d]{2,22})(\\:\\d+)?)"), QRegularExpression::UseUnicodePropertiesOption);
|
||||
const QRegularExpression _reExplicitDomain(QString::fromUtf8("(?<![\\w\\$\\-\\_%=\\.])(?:([a-zA-Z]+)://)((?:[A-Za-zА-яА-ЯёЁ0-9\\-\\_]+\\.){0,5}([A-Za-zрф\\-\\d]{2,22})(\\:\\d+)?)"), QRegularExpression::UseUnicodePropertiesOption);
|
||||
const QRegularExpression _reMailName(qsl("[a-zA-Z\\-_\\.0-9]{1,256}$"));
|
||||
const QRegularExpression _reMailStart(qsl("^[a-zA-Z\\-_\\.0-9]{1,256}\\@"));
|
||||
|
@ -1617,21 +1617,23 @@ public:
|
|||
void eSetFont(ITextBlock *block) {
|
||||
style::font newFont = _t->_font;
|
||||
int flags = block->flags();
|
||||
if (!flags && block->lnkIndex()) {
|
||||
if (block->lnkIndex()) {
|
||||
const TextLinkPtr &l(_t->_links.at(block->lnkIndex() - 1));
|
||||
if (l == _overLnk) {
|
||||
if (l == _downLnk || !_downLnk) {
|
||||
flags = _textStyle->lnkOverFlags->flags();
|
||||
newFont = _textStyle->lnkOverFlags;
|
||||
} else {
|
||||
flags = _textStyle->lnkFlags->flags();
|
||||
newFont = _textStyle->lnkFlags;
|
||||
}
|
||||
} else {
|
||||
flags = _textStyle->lnkFlags->flags();
|
||||
}
|
||||
newFont = _textStyle->lnkFlags;
|
||||
}
|
||||
} else {
|
||||
flags = block->flags();
|
||||
if (flags & TextBlockBold) newFont = newFont->bold();
|
||||
if (flags & TextBlockItalic) newFont = newFont->italic();
|
||||
if (flags & TextBlockUnderline) newFont = newFont->underline();
|
||||
}
|
||||
if (newFont != _f) {
|
||||
_f = newFont;
|
||||
_e->fnt = _f->f;
|
||||
|
|
|
@ -17,20 +17,6 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
class Widget : public QWidget {
|
||||
public:
|
||||
|
||||
Widget(QWidget *parent = 0) : QWidget(parent) {
|
||||
}
|
||||
void moveToLeft(int x, int y, int outerw) {
|
||||
move(rtl() ? (outerw - x - width()) : x, y);
|
||||
}
|
||||
void moveToRight(int x, int y, int outerw) {
|
||||
move(rtl() ? x : (outerw - x - width()), y);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
namespace App {
|
||||
const QPixmap &sprite();
|
||||
}
|
||||
|
@ -119,14 +105,20 @@ public:
|
|||
void drawSpriteCenter(const QRect &in, const style::sprite &sprite) {
|
||||
return drawPixmap(QPoint(in.x() + (in.width() - sprite.pxWidth()) / 2, in.y() + (in.height() - sprite.pxHeight()) / 2), App::sprite(), sprite);
|
||||
}
|
||||
void drawSpriteCenterLeft(const QRect &in, int outerw, const style::sprite &sprite) {
|
||||
return drawPixmapLeft(QPoint(in.x() + (in.width() - sprite.pxWidth()) / 2, in.y() + (in.height() - sprite.pxHeight()) / 2), outerw, App::sprite(), sprite);
|
||||
}
|
||||
void drawSpriteCenterRight(const QRect &in, int outerw, const style::sprite &sprite) {
|
||||
return drawPixmapRight(QPoint(in.x() + (in.width() - sprite.pxWidth()) / 2, in.y() + (in.height() - sprite.pxHeight()) / 2), outerw, App::sprite(), sprite);
|
||||
}
|
||||
};
|
||||
|
||||
class TWidget : public Widget {
|
||||
class TWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
TWidget(QWidget *parent = 0) : Widget(parent) {
|
||||
TWidget(QWidget *parent = 0) : QWidget(parent) {
|
||||
}
|
||||
TWidget *tparent() {
|
||||
return qobject_cast<TWidget*>(parentWidget());
|
||||
|
@ -140,6 +132,27 @@ public:
|
|||
virtual void enterFromChildEvent(QEvent *e) { // e -- from leaveEvent() of child TWidget
|
||||
}
|
||||
|
||||
void moveToLeft(int x, int y, int outerw) {
|
||||
move(rtl() ? (outerw - x - width()) : x, y);
|
||||
}
|
||||
void moveToRight(int x, int y, int outerw) {
|
||||
move(rtl() ? x : (outerw - x - width()), y);
|
||||
}
|
||||
QPoint myrtlpoint(int x, int y) const {
|
||||
return rtlpoint(x, y, width());
|
||||
}
|
||||
QPoint myrtlpoint(const QPoint p) const {
|
||||
return rtlpoint(p, width());
|
||||
}
|
||||
QRect myrtlrect(int x, int y, int w, int h) const {
|
||||
return rtlrect(x, y, w, h, width());
|
||||
}
|
||||
QRect myrtlrect(const QRect &r) {
|
||||
return rtlrect(r, width());
|
||||
}
|
||||
void rtlupdate(const QRect &r) {
|
||||
update(myrtlrect(r));
|
||||
}
|
||||
bool event(QEvent *e) {
|
||||
return QWidget::event(e);
|
||||
}
|
||||
|
@ -149,12 +162,12 @@ protected:
|
|||
void enterEvent(QEvent *e) {
|
||||
TWidget *p(tparent());
|
||||
if (p) p->leaveToChildEvent(e);
|
||||
return Widget::enterEvent(e);
|
||||
return QWidget::enterEvent(e);
|
||||
}
|
||||
void leaveEvent(QEvent *e) {
|
||||
TWidget *p(tparent());
|
||||
if (p) p->enterFromChildEvent(e);
|
||||
return Widget::leaveEvent(e);
|
||||
return QWidget::leaveEvent(e);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -372,6 +372,28 @@ bool History::updateTyping(uint64 ms, uint32 dots, bool force) {
|
|||
return changed;
|
||||
}
|
||||
|
||||
void History::eraseFromOverview(MediaOverviewType type, MsgId msgId) {
|
||||
if (_overviewIds[type].isEmpty()) return;
|
||||
|
||||
History::MediaOverviewIds::iterator i = _overviewIds[type].find(msgId);
|
||||
if (i == _overviewIds[type].cend()) return;
|
||||
|
||||
_overviewIds[type].erase(i);
|
||||
for (History::MediaOverview::iterator i = _overview[type].begin(), e = _overview[type].end(); i != e; ++i) {
|
||||
if ((*i) == msgId) {
|
||||
_overview[type].erase(i);
|
||||
if (_overviewCount[type] > 0) {
|
||||
--_overviewCount[type];
|
||||
if (!_overviewCount[type]) {
|
||||
_overviewCount[type] = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (App::wnd()) App::wnd()->mediaOverviewUpdated(peer, type);
|
||||
}
|
||||
|
||||
bool DialogsList::del(const PeerId &peerId, DialogRow *replacedBy) {
|
||||
RowByPeer::iterator i = rowByPeer.find(peerId);
|
||||
if (i == rowByPeer.cend()) return false;
|
||||
|
@ -803,13 +825,23 @@ HistoryItem *History::doAddToBack(HistoryBlock *to, bool newBlock, HistoryItem *
|
|||
}
|
||||
HistoryMedia *media = adding->getMedia(true);
|
||||
if (media) {
|
||||
MediaOverviewType t = mediaToOverviewType(media->type());
|
||||
HistoryMediaType mt = media->type();
|
||||
MediaOverviewType t = mediaToOverviewType(mt);
|
||||
if (t != OverviewCount) {
|
||||
if (_overviewIds[t].constFind(adding->id) == _overviewIds[t].cend()) {
|
||||
_overview[t].push_back(adding->id);
|
||||
_overviewIds[t].insert(adding->id, NullType());
|
||||
if (_overviewCount[t] > 0) ++_overviewCount[t];
|
||||
if (App::wnd()) App::wnd()->mediaOverviewUpdated(peer);
|
||||
if (App::wnd()) App::wnd()->mediaOverviewUpdated(peer, t);
|
||||
}
|
||||
if (mt == MediaTypeDocument && static_cast<HistoryDocument*>(media)->document()->song()) {
|
||||
t = OverviewAudioDocuments;
|
||||
if (_overviewIds[t].constFind(adding->id) == _overviewIds[t].cend()) {
|
||||
_overview[t].push_back(adding->id);
|
||||
_overviewIds[t].insert(adding->id, NullType());
|
||||
if (_overviewCount[t] > 0) ++_overviewCount[t];
|
||||
if (App::wnd()) App::wnd()->mediaOverviewUpdated(peer, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -933,16 +965,27 @@ void History::addToFront(const QVector<MTPMessage> &slice) {
|
|||
++skip;
|
||||
|
||||
if (loadedAtBottom()) { // add photos to overview and authors to lastAuthors
|
||||
int32 mask = 0;
|
||||
QList<UserData*> *lastAuthors = peer->chat ? &(peer->asChat()->lastAuthors) : 0;
|
||||
for (int32 i = block->size(); i > 0; --i) {
|
||||
HistoryItem *item = (*block)[i - 1];
|
||||
HistoryMedia *media = item->getMedia(true);
|
||||
if (media) {
|
||||
MediaOverviewType t = mediaToOverviewType(media->type());
|
||||
HistoryMediaType mt = media->type();
|
||||
MediaOverviewType t = mediaToOverviewType(mt);
|
||||
if (t != OverviewCount) {
|
||||
if (_overviewIds[t].constFind(item->id) == _overviewIds[t].cend()) {
|
||||
_overview[t].push_front(item->id);
|
||||
_overviewIds[t].insert(item->id, NullType());
|
||||
mask |= (1 << t);
|
||||
}
|
||||
if (mt == MediaTypeDocument && static_cast<HistoryDocument*>(media)->document()->song()) {
|
||||
t = OverviewAudioDocuments;
|
||||
if (_overviewIds[t].constFind(item->id) == _overviewIds[t].cend()) {
|
||||
_overview[t].push_front(item->id);
|
||||
_overviewIds[t].insert(item->id, NullType());
|
||||
mask |= (1 << t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -987,7 +1030,9 @@ void History::addToFront(const QVector<MTPMessage> &slice) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (App::wnd()) App::wnd()->mediaOverviewUpdated(peer);
|
||||
for (int32 t = 0; t < OverviewCount; ++t) {
|
||||
if ((mask & (1 << t)) && App::wnd()) App::wnd()->mediaOverviewUpdated(peer, MediaOverviewType(t));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
delete block;
|
||||
|
@ -1062,10 +1107,14 @@ void History::addToBack(const QVector<MTPMessage> &slice) {
|
|||
delete block;
|
||||
}
|
||||
if (!wasLoadedAtBottom && loadedAtBottom()) { // add all loaded photos to overview
|
||||
int32 mask = 0;
|
||||
for (int32 i = 0; i < OverviewCount; ++i) {
|
||||
if (_overviewCount[i] == 0) continue; // all loaded
|
||||
if (!_overview[i].isEmpty() || !_overviewIds[i].isEmpty()) {
|
||||
_overview[i].clear();
|
||||
_overviewIds[i].clear();
|
||||
mask |= (1 << i);
|
||||
}
|
||||
}
|
||||
for (int32 i = 0; i < size(); ++i) {
|
||||
HistoryBlock *b = (*this)[i];
|
||||
|
@ -1073,15 +1122,29 @@ void History::addToBack(const QVector<MTPMessage> &slice) {
|
|||
HistoryItem *item = (*b)[j];
|
||||
HistoryMedia *media = item->getMedia(true);
|
||||
if (media) {
|
||||
MediaOverviewType t = mediaToOverviewType(media->type());
|
||||
if (t != OverviewCount && _overviewCount[t] != 0) {
|
||||
HistoryMediaType mt = media->type();
|
||||
MediaOverviewType t = mediaToOverviewType(mt);
|
||||
if (t != OverviewCount) {
|
||||
if (_overviewCount[t] != 0) {
|
||||
_overview[t].push_back(item->id);
|
||||
_overviewIds[t].insert(item->id, NullType());
|
||||
mask |= (1 << t);
|
||||
}
|
||||
if (mt == MediaTypeDocument && static_cast<HistoryDocument*>(media)->document()->song()) {
|
||||
t = OverviewAudioDocuments;
|
||||
if (_overviewCount[t] != 0) {
|
||||
_overview[t].push_back(item->id);
|
||||
_overviewIds[t].insert(item->id, NullType());
|
||||
mask |= (1 << t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (App::wnd()) App::wnd()->mediaOverviewUpdated(peer);
|
||||
}
|
||||
}
|
||||
for (int32 t = 0; t < OverviewCount; ++t) {
|
||||
if ((mask & (1 << t)) && App::wnd()) App::wnd()->mediaOverviewUpdated(peer, MediaOverviewType(t));
|
||||
}
|
||||
}
|
||||
if (wasEmpty && !isEmpty()) {
|
||||
HistoryBlock *dateBlock = new HistoryBlock(this);
|
||||
|
@ -1328,11 +1391,13 @@ void History::clear(bool leaveItems) {
|
|||
showFrom = 0;
|
||||
}
|
||||
for (int32 i = 0; i < OverviewCount; ++i) {
|
||||
if (!_overview[i].isEmpty() || !_overviewIds[i].isEmpty()) {
|
||||
if (_overviewCount[i] == 0) _overviewCount[i] = _overview[i].size();
|
||||
_overview[i].clear();
|
||||
_overviewIds[i].clear();
|
||||
if (App::wnd() && !App::quiting()) App::wnd()->mediaOverviewUpdated(peer, MediaOverviewType(i));
|
||||
}
|
||||
}
|
||||
if (App::wnd() && !App::quiting()) App::wnd()->mediaOverviewUpdated(peer);
|
||||
for (Parent::const_iterator i = cbegin(), e = cend(); i != e; ++i) {
|
||||
if (leaveItems) {
|
||||
(*i)->clear(true);
|
||||
|
@ -1580,23 +1645,10 @@ void HistoryItem::destroy() {
|
|||
}
|
||||
HistoryMedia *m = getMedia(true);
|
||||
MediaOverviewType t = m ? mediaToOverviewType(m->type()) : OverviewCount;
|
||||
if (t != OverviewCount && !history()->_overviewIds[t].isEmpty()) {
|
||||
History::MediaOverviewIds::iterator i = history()->_overviewIds[t].find(id);
|
||||
if (i != history()->_overviewIds[t].cend()) {
|
||||
history()->_overviewIds[t].erase(i);
|
||||
for (History::MediaOverview::iterator i = history()->_overview[t].begin(), e = history()->_overview[t].end(); i != e; ++i) {
|
||||
if ((*i) == id) {
|
||||
history()->_overview[t].erase(i);
|
||||
if (history()->_overviewCount[t] > 0) {
|
||||
--history()->_overviewCount[t];
|
||||
if (!history()->_overviewCount[t]) {
|
||||
history()->_overviewCount[t] = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (App::wnd()) App::wnd()->mediaOverviewUpdated(history()->peer);
|
||||
if (t != OverviewCount) {
|
||||
history()->eraseFromOverview(t, id);
|
||||
if (m->type() == MediaTypeDocument && static_cast<HistoryDocument*>(m)->document()->song()) {
|
||||
history()->eraseFromOverview(OverviewAudioDocuments, id);
|
||||
}
|
||||
}
|
||||
delete this;
|
||||
|
@ -2339,8 +2391,9 @@ void HistoryVideo::draw(QPainter &p, const HistoryItem *parent, bool selected, i
|
|||
p.setPen(status->p);
|
||||
|
||||
if (data->loader) {
|
||||
if (_dldTextCache.isEmpty() || _dldDone != data->loader->currentOffset()) {
|
||||
_dldDone = data->loader->currentOffset();
|
||||
int32 offset = data->loader->currentOffset();
|
||||
if (_dldTextCache.isEmpty() || _dldDone != offset) {
|
||||
_dldDone = offset;
|
||||
_dldTextCache = formatDownloadText(_dldDone, data->size);
|
||||
}
|
||||
statusText = _dldTextCache;
|
||||
|
@ -2563,7 +2616,7 @@ void HistoryAudio::draw(QPainter &p, const HistoryItem *parent, bool selected, i
|
|||
img = out ? st::mediaAudioOutImg : st::mediaAudioInImg;
|
||||
} else if (already || hasdata) {
|
||||
bool showPause = false;
|
||||
if (playing.msgId == parent->id && playingState != AudioPlayerStopped && playingState != AudioPlayerStoppedAtStart) {
|
||||
if (playing.msgId == parent->id && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
|
||||
statusText = formatDurationText(playingPosition / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency)) + qsl(" / ") + formatDurationText(playingDuration / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency));
|
||||
showPause = (playingState == AudioPlayerPlaying || playingState == AudioPlayerResuming || playingState == AudioPlayerStarting);
|
||||
} else {
|
||||
|
@ -2572,8 +2625,9 @@ void HistoryAudio::draw(QPainter &p, const HistoryItem *parent, bool selected, i
|
|||
img = out ? (showPause ? st::mediaPauseOutImg : st::mediaPlayOutImg) : (showPause ? st::mediaPauseInImg : st::mediaPlayInImg);
|
||||
} else {
|
||||
if (data->loader) {
|
||||
if (_dldTextCache.isEmpty() || _dldDone != data->loader->currentOffset()) {
|
||||
_dldDone = data->loader->currentOffset();
|
||||
int32 offset = data->loader->currentOffset();
|
||||
if (_dldTextCache.isEmpty() || _dldDone != offset) {
|
||||
_dldDone = offset;
|
||||
_dldTextCache = formatDownloadText(_dldDone, data->size);
|
||||
}
|
||||
statusText = _dldTextCache;
|
||||
|
@ -2733,7 +2787,7 @@ namespace {
|
|||
SongData *song = document->song();
|
||||
if (!song || (song->title.isEmpty() && song->performer.isEmpty())) return document->name;
|
||||
if (song->performer.isEmpty()) return song->title;
|
||||
return song->performer + QString::fromUtf8(" \xe2\x80\x94 ") + (song->title.isEmpty() ? qsl("Unknown Track") : song->title);
|
||||
return song->performer + QString::fromUtf8(" \xe2\x80\x93 ") + (song->title.isEmpty() ? qsl("Unknown Track") : song->title);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2905,17 +2959,19 @@ void HistoryDocument::draw(QPainter &p, const HistoryItem *parent, bool selected
|
|||
img = out ? st::mediaAudioOutImg : st::mediaAudioInImg;
|
||||
} else if (already || hasdata) {
|
||||
bool showPause = false;
|
||||
if (playing.msgId == parent->id && playingState != AudioPlayerStopped && playingState != AudioPlayerStoppedAtStart) {
|
||||
if (playing.msgId == parent->id && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
|
||||
statusText = formatDurationText(playingPosition / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency)) + qsl(" / ") + formatDurationText(playingDuration / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency));
|
||||
showPause = (playingState == AudioPlayerPlaying || playingState == AudioPlayerResuming || playingState == AudioPlayerStarting);
|
||||
} else {
|
||||
statusText = formatDurationText(data->song()->duration);
|
||||
}
|
||||
if (!showPause && playing.msgId == parent->id && App::main() && App::main()->player()->seekingSong(playing)) showPause = true;
|
||||
img = out ? (showPause ? st::mediaPauseOutImg : st::mediaPlayOutImg) : (showPause ? st::mediaPauseInImg : st::mediaPlayInImg);
|
||||
} else {
|
||||
if (data->loader) {
|
||||
if (_dldTextCache.isEmpty() || _dldDone != data->loader->currentOffset()) {
|
||||
_dldDone = data->loader->currentOffset();
|
||||
int32 offset = data->loader->currentOffset();
|
||||
if (_dldTextCache.isEmpty() || _dldDone != offset) {
|
||||
_dldDone = offset;
|
||||
_dldTextCache = formatDownloadText(_dldDone, data->size);
|
||||
}
|
||||
statusText = _dldTextCache;
|
||||
|
@ -2936,8 +2992,9 @@ void HistoryDocument::draw(QPainter &p, const HistoryItem *parent, bool selected
|
|||
}
|
||||
statusText = _uplTextCache;
|
||||
} else if (data->loader) {
|
||||
if (_dldTextCache.isEmpty() || _dldDone != data->loader->currentOffset()) {
|
||||
_dldDone = data->loader->currentOffset();
|
||||
int32 offset = data->loader->currentOffset();
|
||||
if (_dldTextCache.isEmpty() || _dldDone != offset) {
|
||||
_dldDone = offset;
|
||||
_dldTextCache = formatDownloadText(_dldDone, data->size);
|
||||
}
|
||||
statusText = _dldTextCache;
|
||||
|
@ -3147,8 +3204,8 @@ HistorySticker::HistorySticker(DocumentData *document) : HistoryMedia()
|
|||
, pixw(1), pixh(1), data(document), lastw(0)
|
||||
{
|
||||
data->thumb->load();
|
||||
if (!data->sticker->alt.isEmpty()) {
|
||||
_emoji = data->sticker->alt;
|
||||
if (!data->sticker()->alt.isEmpty()) {
|
||||
_emoji = data->sticker()->alt;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -106,6 +106,7 @@ enum MediaOverviewType {
|
|||
OverviewVideos,
|
||||
OverviewDocuments,
|
||||
OverviewAudios,
|
||||
OverviewAudioDocuments,
|
||||
|
||||
OverviewCount
|
||||
};
|
||||
|
@ -127,6 +128,7 @@ inline MTPMessagesFilter typeToMediaFilter(MediaOverviewType &type) {
|
|||
case OverviewVideos: return MTP_inputMessagesFilterVideo();
|
||||
case OverviewDocuments: return MTP_inputMessagesFilterDocument();
|
||||
case OverviewAudios: return MTP_inputMessagesFilterAudio();
|
||||
case OverviewAudioDocuments: return MTP_inputMessagesFilterAudioDocuments();
|
||||
default: type = OverviewCount; break;
|
||||
}
|
||||
return MTPMessagesFilter();
|
||||
|
@ -286,6 +288,8 @@ struct History : public QList<HistoryBlock*> {
|
|||
MediaOverviewIds _overviewIds[OverviewCount];
|
||||
int32 _overviewCount[OverviewCount]; // -1 - not loaded, 0 - all loaded, > 0 - count, but not all loaded
|
||||
|
||||
void eraseFromOverview(MediaOverviewType type, MsgId msgId);
|
||||
|
||||
static const int32 ScrollMax = INT_MAX;
|
||||
};
|
||||
|
||||
|
|
|
@ -2225,6 +2225,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
|
|||
connect(&_attachPhoto, SIGNAL(clicked()), this, SLOT(onPhotoSelect()));
|
||||
connect(&_field, SIGNAL(submitted(bool)), this, SLOT(onSend(bool)));
|
||||
connect(&_field, SIGNAL(cancelled()), this, SLOT(onCancel()));
|
||||
connect(&_field, SIGNAL(tabbed()), this, SLOT(onFieldTabbed()));
|
||||
connect(&_field, SIGNAL(resized()), this, SLOT(onFieldResize()));
|
||||
connect(&_field, SIGNAL(focused()), this, SLOT(onFieldFocused()));
|
||||
connect(&imageLoader, SIGNAL(imageReady()), this, SLOT(onPhotoReady()));
|
||||
|
@ -3501,6 +3502,19 @@ bool HistoryWidget::showStep(float64 ms) {
|
|||
_bgAnimCache = _animCache = _animTopBarCache = _bgAnimTopBarCache = QPixmap();
|
||||
App::main()->topBar()->stopAnim();
|
||||
App::main()->topBar()->enableShadow();
|
||||
doneShow();
|
||||
} else {
|
||||
a_bgCoord.update(dt1, st::introHideFunc);
|
||||
a_bgAlpha.update(dt1, st::introAlphaHideFunc);
|
||||
a_coord.update(dt2, st::introShowFunc);
|
||||
a_alpha.update(dt2, st::introAlphaShowFunc);
|
||||
}
|
||||
update();
|
||||
App::main()->topBar()->update();
|
||||
return res;
|
||||
}
|
||||
|
||||
void HistoryWidget::doneShow() {
|
||||
if (hist && hist->readyForWork()) {
|
||||
_scroll.show();
|
||||
if (hist->lastScrollTop == History::ScrollMax) {
|
||||
|
@ -3515,15 +3529,6 @@ bool HistoryWidget::showStep(float64 ms) {
|
|||
}
|
||||
updateControlsVisibility();
|
||||
App::wnd()->setInnerFocus();
|
||||
} else {
|
||||
a_bgCoord.update(dt1, st::introHideFunc);
|
||||
a_bgAlpha.update(dt1, st::introAlphaHideFunc);
|
||||
a_coord.update(dt2, st::introShowFunc);
|
||||
a_alpha.update(dt2, st::introAlphaShowFunc);
|
||||
}
|
||||
update();
|
||||
App::main()->topBar()->update();
|
||||
return res;
|
||||
}
|
||||
|
||||
void HistoryWidget::animStop() {
|
||||
|
@ -4502,7 +4507,7 @@ void HistoryWidget::resizeEvent(QResizeEvent *e) {
|
|||
_attachPhoto.move(_attachDocument.x(), _attachDocument.y());
|
||||
|
||||
_replyForwardPreviewCancel.move(width() - _replyForwardPreviewCancel.width(), _field.y() - st::sendPadding - _replyForwardPreviewCancel.height());
|
||||
updateListSize();
|
||||
updateListSize(App::main() ? App::main()->contentScrollAddToY() : 0);
|
||||
|
||||
bool kbShowShown = hist && !_kbShown && _keyboard.hasMarkup();
|
||||
_field.resize(width() - _send.width() - _attachDocument.width() - _attachEmoji.width() - (kbShowShown ? _kbShow.width() : 0) - (_cmdStartShown ? _cmdStart.width() : 0), _field.height());
|
||||
|
@ -4841,6 +4846,13 @@ void HistoryWidget::keyPressEvent(QKeyEvent *e) {
|
|||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::onFieldTabbed() {
|
||||
QString sel = _attachMention.isHidden() ? QString() : _attachMention.getSelected();
|
||||
if (!sel.isEmpty()) {
|
||||
_field.onMentionHashtagOrBotCommandInsert(sel);
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::onStickerSend(DocumentData *sticker) {
|
||||
if (!hist || !sticker) return;
|
||||
|
||||
|
@ -5403,9 +5415,9 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
|
|||
return;
|
||||
}
|
||||
|
||||
bool hasTopBar = !App::main()->topBar()->isHidden();
|
||||
bool hasTopBar = !App::main()->topBar()->isHidden(), hasPlayer = !App::main()->player()->isHidden();
|
||||
QRect fill(0, 0, width(), App::main()->height());
|
||||
int fromy = hasTopBar ? (-st::topBarHeight) : 0, x = 0, y = 0;
|
||||
int fromy = (hasTopBar ? (-st::topBarHeight) : 0) + (hasPlayer ? (-st::playerHeight) : 0), x = 0, y = 0;
|
||||
QPixmap cached = App::main()->cachedBackground(fill, x, y);
|
||||
if (cached.isNull()) {
|
||||
const QPixmap &pix(*cChatBackground());
|
||||
|
|
|
@ -416,6 +416,7 @@ public:
|
|||
void animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTopBarCache, bool back = false);
|
||||
bool showStep(float64 ms);
|
||||
void animStop();
|
||||
void doneShow();
|
||||
|
||||
QPoint clampMousePosition(QPoint point);
|
||||
|
||||
|
@ -528,6 +529,7 @@ public slots:
|
|||
void onMentionHashtagOrBotCommandInsert(QString str);
|
||||
void onTextChange();
|
||||
|
||||
void onFieldTabbed();
|
||||
void onStickerSend(DocumentData *sticker);
|
||||
|
||||
void onVisibleChanged();
|
||||
|
|
|
@ -1036,6 +1036,14 @@ namespace {
|
|||
cSetDialogLastPath(path);
|
||||
} break;
|
||||
|
||||
case dbiSongVolume: {
|
||||
qint32 v;
|
||||
stream >> v;
|
||||
if (!_checkStreamStatus(stream)) return false;
|
||||
|
||||
cSetSongVolume(snap(v / 1e6, 0., 1.));
|
||||
} break;
|
||||
|
||||
default:
|
||||
LOG(("App Error: unknown blockId in _readSetting: %1").arg(blockId));
|
||||
return false;
|
||||
|
@ -1257,7 +1265,7 @@ namespace {
|
|||
_writeMap(WriteMapFast);
|
||||
}
|
||||
|
||||
uint32 size = 11 * (sizeof(quint32) + sizeof(qint32));
|
||||
uint32 size = 12 * (sizeof(quint32) + sizeof(qint32));
|
||||
size += sizeof(quint32) + _stringSize(cAskDownloadPath() ? QString() : cDownloadPath());
|
||||
size += sizeof(quint32) + sizeof(qint32) + (cRecentEmojisPreload().isEmpty() ? cGetRecentEmojis().size() : cRecentEmojisPreload().size()) * (sizeof(uint64) + sizeof(ushort));
|
||||
size += sizeof(quint32) + sizeof(qint32) + cEmojiVariants().size() * (sizeof(uint32) + sizeof(uint64));
|
||||
|
@ -1278,6 +1286,7 @@ namespace {
|
|||
data.stream << quint32(dbiCompressPastedImage) << qint32(cCompressPastedImage());
|
||||
data.stream << quint32(dbiEmojiTab) << qint32(cEmojiTab());
|
||||
data.stream << quint32(dbiDialogLastPath) << cDialogLastPath();
|
||||
data.stream << quint32(dbiSongVolume) << qint32(qRound(cSongVolume() * 1e6));
|
||||
|
||||
{
|
||||
RecentEmojisPreload v(cRecentEmojisPreload());
|
||||
|
|
|
@ -277,7 +277,7 @@ void TopBarWidget::showAll() {
|
|||
resizeEvent(0);
|
||||
return;
|
||||
}
|
||||
PeerData *p = App::main() ? App::main()->profilePeer() : 0;
|
||||
PeerData *p = App::main() ? App::main()->profilePeer() : 0, *o = App::main() ? App::main()->overviewPeer() : 0;
|
||||
if (p && (p->chat || p->asUser()->contact >= 0)) {
|
||||
if (p->chat) {
|
||||
if (p->asChat()->forbidden) {
|
||||
|
@ -324,7 +324,7 @@ void TopBarWidget::showAll() {
|
|||
_mediaType.hide();
|
||||
}
|
||||
}
|
||||
if (App::main() && App::main()->historyPeer() && !p && _clearSelection.isHidden() && !cWideMode()) {
|
||||
if (App::main() && App::main()->historyPeer() && !o && !p && _clearSelection.isHidden() && !cWideMode()) {
|
||||
_info.show();
|
||||
} else {
|
||||
_info.hide();
|
||||
|
@ -350,9 +350,12 @@ MainWidget *TopBarWidget::main() {
|
|||
return static_cast<MainWidget*>(parentWidget());
|
||||
}
|
||||
|
||||
MainWidget::MainWidget(Window *window) : QWidget(window), _started(0), failedObjId(0), _toForwardNameVersion(0), _dialogsWidth(st::dlgMinWidth),
|
||||
dialogs(this), history(this), profile(0), overview(0), _topBar(this), _forwardConfirm(0), hider(0), _mediaType(this), _mediaTypeMask(0),
|
||||
updGoodPts(0), updLastPts(0), updPtsCount(0), updDate(0), updQts(-1), updSeq(0), updInited(false), updSkipPtsUpdateLevel(0), _onlineRequest(0), _lastWasOnline(false), _lastSetOnline(0), _isIdle(false),
|
||||
MainWidget::MainWidget(Window *window) : QWidget(window),
|
||||
_started(0), failedObjId(0), _toForwardNameVersion(0), _dialogsWidth(st::dlgMinWidth),
|
||||
dialogs(this), history(this), profile(0), overview(0), _player(this), _topBar(this),
|
||||
_forwardConfirm(0), hider(0), _contentScrollAddToY(0), _playerHeight(0), _mediaType(this), _mediaTypeMask(0),
|
||||
updGoodPts(0), updLastPts(0), updPtsCount(0), updDate(0), updQts(-1), updSeq(0), updInited(false), updSkipPtsUpdateLevel(0),
|
||||
_onlineRequest(0), _lastWasOnline(false), _lastSetOnline(0), _isIdle(false),
|
||||
_failDifferenceTimeout(1), _lastUpdateTime(0), _cachedX(0), _cachedY(0), _background(0), _api(new ApiWrap(this)) {
|
||||
setGeometry(QRect(0, st::titleHeight, App::wnd()->width(), App::wnd()->height() - st::titleHeight));
|
||||
|
||||
|
@ -397,7 +400,10 @@ _failDifferenceTimeout(1), _lastUpdateTime(0), _cachedX(0), _cachedY(0), _backgr
|
|||
App::wnd()->getTitle()->updateBackButton();
|
||||
_topBar.hide();
|
||||
|
||||
_player.hide();
|
||||
|
||||
_topBar.raise();
|
||||
_player.raise();
|
||||
dialogs.raise();
|
||||
_mediaType.raise();
|
||||
|
||||
|
@ -613,7 +619,7 @@ void MainWidget::noHider(HistoryHider *destroyed) {
|
|||
onPeerShown(history.peer());
|
||||
if (profile || overview || (history.peer() && history.peer()->id)) {
|
||||
dialogs.enableShadow(false);
|
||||
QPixmap animCache = myGrab(this, QRect(0, st::topBarHeight, _dialogsWidth, height() - st::topBarHeight)),
|
||||
QPixmap animCache = myGrab(this, QRect(0, _playerHeight + st::topBarHeight, _dialogsWidth, height() - _playerHeight - st::topBarHeight)),
|
||||
animTopBarCache = myGrab(this, QRect(_topBar.x(), _topBar.y(), _topBar.width(), st::topBarHeight));
|
||||
dialogs.enableShadow();
|
||||
_topBar.enableShadow();
|
||||
|
@ -651,7 +657,7 @@ void MainWidget::hiderLayer(HistoryHider *h) {
|
|||
|
||||
hider->hide();
|
||||
dialogs.enableShadow(false);
|
||||
QPixmap animCache = myGrab(this, QRect(0, 0, _dialogsWidth, height()));
|
||||
QPixmap animCache = myGrab(this, QRect(0, _playerHeight, _dialogsWidth, height() - _playerHeight));
|
||||
dialogs.enableShadow();
|
||||
_topBar.enableShadow();
|
||||
|
||||
|
@ -1138,13 +1144,14 @@ void MainWidget::overviewPreloaded(PeerData *peer, const MTPmessages_Messages &r
|
|||
}
|
||||
}
|
||||
|
||||
mediaOverviewUpdated(peer);
|
||||
mediaOverviewUpdated(peer, type);
|
||||
}
|
||||
|
||||
void MainWidget::mediaOverviewUpdated(PeerData *peer) {
|
||||
if (profile) profile->mediaOverviewUpdated(peer);
|
||||
void MainWidget::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
|
||||
if (profile) profile->mediaOverviewUpdated(peer, type);
|
||||
if (!_player.isHidden()) _player.mediaOverviewUpdated(peer, type);
|
||||
if (overview && overview->peer() == peer) {
|
||||
overview->mediaOverviewUpdated(peer);
|
||||
overview->mediaOverviewUpdated(peer, type);
|
||||
|
||||
int32 mask = 0;
|
||||
History *h = peer ? App::historyLoaded(peer->id) : 0;
|
||||
|
@ -1336,7 +1343,7 @@ void MainWidget::photosLoaded(History *h, const MTPmessages_Messages &msgs, mtpR
|
|||
h->_overview[type].push_front(item->id);
|
||||
}
|
||||
}
|
||||
if (App::wnd()) App::wnd()->mediaOverviewUpdated(h->peer);
|
||||
if (App::wnd()) App::wnd()->mediaOverviewUpdated(h->peer, type);
|
||||
}
|
||||
|
||||
void MainWidget::partWasRead(PeerData *peer, const MTPmessages_AffectedHistory &result) {
|
||||
|
@ -1417,7 +1424,7 @@ void MainWidget::audioLoadProgress(mtpFileLoader *loader) {
|
|||
AudioMsgId playing;
|
||||
AudioPlayerState state = AudioPlayerStopped;
|
||||
audioPlayer()->currentState(&playing, &state);
|
||||
if (playing.msgId == audio->openOnSaveMsgId && state != AudioPlayerStopped) {
|
||||
if (playing.msgId == audio->openOnSaveMsgId && !(state & AudioPlayerStoppedMask) && state != AudioPlayerFinishing) {
|
||||
audioPlayer()->pauseresume(OverviewAudios);
|
||||
} else {
|
||||
audioPlayer()->play(AudioMsgId(audio, audio->openOnSaveMsgId));
|
||||
|
@ -1480,9 +1487,12 @@ void MainWidget::audioPlayProgress(const AudioMsgId &audioId) {
|
|||
|
||||
void MainWidget::documentPlayProgress(const SongMsgId &songId) {
|
||||
SongMsgId playing;
|
||||
AudioPlayerState state = AudioPlayerStopped;
|
||||
audioPlayer()->currentState(&playing, &state);
|
||||
if (playing == songId && state == AudioPlayerStoppedAtStart) {
|
||||
AudioPlayerState playingState = AudioPlayerStopped;
|
||||
int64 playingPosition = 0, playingDuration = 0;
|
||||
int32 playingFrequency = 0;
|
||||
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency);
|
||||
if (playing == songId && playingState == AudioPlayerStoppedAtStart) {
|
||||
playingState = AudioPlayerStopped;
|
||||
audioPlayer()->clearStoppedAtStart(songId);
|
||||
|
||||
DocumentData *document = songId.song;
|
||||
|
@ -1518,11 +1528,33 @@ void MainWidget::documentPlayProgress(const SongMsgId &songId) {
|
|||
}
|
||||
}
|
||||
|
||||
if (playing == songId) {
|
||||
_player.updateState(playing, playingState, playingPosition, playingDuration, playingFrequency);
|
||||
|
||||
if (!(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
|
||||
if (_player.isHidden()) {
|
||||
_player.clearSelection();
|
||||
_player.show();
|
||||
_playerHeight = _contentScrollAddToY = _player.height();
|
||||
resizeEvent(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (HistoryItem *item = App::histItemById(songId.msgId)) {
|
||||
msgUpdated(item->history()->peer->id, item);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWidget::hidePlayer() {
|
||||
if (!_player.isHidden()) {
|
||||
_player.hide();
|
||||
_contentScrollAddToY = -_player.height();
|
||||
_playerHeight = 0;
|
||||
resizeEvent(0);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWidget::audioLoadFailed(mtpFileLoader *loader, bool started) {
|
||||
loadFailed(loader, started, SLOT(audioLoadRetry()));
|
||||
AudioData *audio = App::audio(loader->objId());
|
||||
|
@ -1552,10 +1584,12 @@ void MainWidget::documentLoadProgress(mtpFileLoader *loader) {
|
|||
SongMsgId playing;
|
||||
AudioPlayerState playingState = AudioPlayerStopped;
|
||||
audioPlayer()->currentState(&playing, &playingState);
|
||||
if (playing.msgId == item->id && playingState != AudioPlayerStopped) {
|
||||
if (playing.msgId == item->id && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
|
||||
audioPlayer()->pauseresume(OverviewDocuments);
|
||||
} else {
|
||||
audioPlayer()->play(SongMsgId(document, item->id));
|
||||
SongMsgId song(document, item->id);
|
||||
audioPlayer()->play(song);
|
||||
if (App::main()) App::main()->documentPlayProgress(song);
|
||||
}
|
||||
} else if(document->openOnSave > 0 && document->size < MediaViewImageSizeLimit) {
|
||||
QImageReader reader(already);
|
||||
|
@ -1589,6 +1623,21 @@ void MainWidget::documentLoadProgress(mtpFileLoader *loader) {
|
|||
}
|
||||
}
|
||||
App::wnd()->documentUpdated(document);
|
||||
|
||||
if (audioPlayer()) {
|
||||
SongMsgId playing;
|
||||
AudioPlayerState playingState = AudioPlayerStopped;
|
||||
int64 playingPosition = 0, playingDuration = 0;
|
||||
int32 playingFrequency = 0;
|
||||
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency);
|
||||
if (playing.song == document && !_player.isHidden()) {
|
||||
if (document->loader) {
|
||||
_player.updateState(playing, playingState, playingPosition, playingDuration, playingFrequency);
|
||||
} else {
|
||||
audioPlayer()->play(playing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWidget::documentLoadFailed(mtpFileLoader *loader, bool started) {
|
||||
|
@ -1848,19 +1897,19 @@ void MainWidget::showPeer(quint64 peerId, qint32 msgId, bool back, bool force) {
|
|||
hider = 0;
|
||||
}
|
||||
if (force || !selectingPeer()) {
|
||||
if (!animating() && ((history.isHidden() && (profile || overview)) || (!cWideMode() && (history.isHidden() || !peerId)))) {
|
||||
if (!animating() && ((history.isHidden() && history.activePeer() && (profile || overview)) || (!cWideMode() && (history.isHidden() || !peerId)))) {
|
||||
dialogs.enableShadow(false);
|
||||
if (peerId) {
|
||||
_topBar.enableShadow(false);
|
||||
if (cWideMode()) {
|
||||
animCache = myGrab(this, QRect(_dialogsWidth, st::topBarHeight, width() - _dialogsWidth, height() - st::topBarHeight));
|
||||
animCache = myGrab(this, QRect(_dialogsWidth, _playerHeight + st::topBarHeight, width() - _dialogsWidth, height() - _playerHeight - st::topBarHeight));
|
||||
} else {
|
||||
animCache = myGrab(this, QRect(0, st::topBarHeight, _dialogsWidth, height() - st::topBarHeight));
|
||||
animCache = myGrab(this, QRect(0, _playerHeight + st::topBarHeight, _dialogsWidth, height() - _playerHeight - st::topBarHeight));
|
||||
}
|
||||
} else if (cWideMode()) {
|
||||
animCache = myGrab(this, QRect(_dialogsWidth, 0, width() - _dialogsWidth, height()));
|
||||
animCache = myGrab(this, QRect(_dialogsWidth, _playerHeight, width() - _dialogsWidth, height() - _playerHeight));
|
||||
} else {
|
||||
animCache = myGrab(this, QRect(0, 0, _dialogsWidth, height()));
|
||||
animCache = myGrab(this, QRect(0, _playerHeight, _dialogsWidth, height() - _playerHeight));
|
||||
}
|
||||
if (peerId || cWideMode()) {
|
||||
animTopBarCache = myGrab(this, QRect(_topBar.x(), _topBar.y(), _topBar.width(), st::topBarHeight));
|
||||
|
@ -1909,6 +1958,8 @@ void MainWidget::showPeer(quint64 peerId, qint32 msgId, bool back, bool force) {
|
|||
history.show();
|
||||
if (!animCache.isNull()) {
|
||||
history.animShow(animCache, animTopBarCache, back);
|
||||
} else {
|
||||
QTimer::singleShot(0, this, SLOT(setInnerFocus()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1958,8 +2009,12 @@ PeerData *MainWidget::profilePeer() {
|
|||
return profile ? profile->peer() : 0;
|
||||
}
|
||||
|
||||
PeerData *MainWidget::overviewPeer() {
|
||||
return overview ? overview->peer() : 0;
|
||||
}
|
||||
|
||||
bool MainWidget::mediaTypeSwitch() {
|
||||
if (!overview) return false;
|
||||
if (!overview || (overview->type() == OverviewAudioDocuments)) return false;
|
||||
|
||||
for (int32 i = 0; i < OverviewCount; ++i) {
|
||||
if (!(_mediaTypeMask & ~(1 << i))) {
|
||||
|
@ -1974,13 +2029,21 @@ 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
|
||||
showBackFromStack();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
dialogs.enableShadow(false);
|
||||
_topBar.enableShadow(false);
|
||||
QPixmap animCache = myGrab(this, history.geometry()), animTopBarCache = myGrab(this, QRect(_topBar.x(), _topBar.y(), _topBar.width(), st::topBarHeight));
|
||||
QRect topBarRect = QRect(_topBar.x(), _topBar.y(), _topBar.width(), st::topBarHeight);
|
||||
QRect historyRect = QRect(history.x(), topBarRect.y() + topBarRect.height(), history.width(), history.y() + history.height() - topBarRect.y() - topBarRect.height());
|
||||
QPixmap animCache, animTopBarCache;
|
||||
if (!animating() && (!cWideMode() || profile || overview || history.peer())) {
|
||||
animCache = myGrab(this, historyRect);
|
||||
animTopBarCache = myGrab(this, topBarRect);
|
||||
}
|
||||
dialogs.enableShadow();
|
||||
_topBar.enableShadow();
|
||||
if (!back) {
|
||||
|
@ -1988,7 +2051,7 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool
|
|||
_stack.push_back(new StackItemOverview(overview->peer(), overview->type(), overview->lastWidth(), overview->lastScrollTop()));
|
||||
} else if (profile) {
|
||||
_stack.push_back(new StackItemProfile(profile->peer(), profile->lastScrollTop(), profile->allMediaShown()));
|
||||
} else {
|
||||
} else if (history.peer()) {
|
||||
_stack.push_back(new StackItemHistory(history.peer(), history.lastWidth(), history.lastScrollTop(), history.replyReturns(), history.kbWasHidden()));
|
||||
}
|
||||
}
|
||||
|
@ -2009,12 +2072,19 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool
|
|||
_mediaTypeMask = 0;
|
||||
_topBar.show();
|
||||
resizeEvent(0);
|
||||
mediaOverviewUpdated(peer);
|
||||
mediaOverviewUpdated(peer, type);
|
||||
if (!animCache.isNull()) {
|
||||
overview->animShow(animCache, animTopBarCache, back, lastScrollTop);
|
||||
} else {
|
||||
overview->show();
|
||||
overview->activate();
|
||||
}
|
||||
history.animStop();
|
||||
history.showPeer(0, 0, false, true);
|
||||
history.hide();
|
||||
if (!cWideMode()) dialogs.hide();
|
||||
_topBar.raise();
|
||||
_player.raise();
|
||||
dialogs.raise();
|
||||
_mediaType.raise();
|
||||
if (hider) hider->raise();
|
||||
|
@ -2060,6 +2130,7 @@ void MainWidget::showPeerProfile(PeerData *peer, bool back, int32 lastScrollTop,
|
|||
history.showPeer(0, 0, false, true);
|
||||
history.hide();
|
||||
_topBar.raise();
|
||||
_player.raise();
|
||||
dialogs.raise();
|
||||
_mediaType.raise();
|
||||
if (hider) hider->raise();
|
||||
|
@ -2067,7 +2138,16 @@ void MainWidget::showPeerProfile(PeerData *peer, bool back, int32 lastScrollTop,
|
|||
}
|
||||
|
||||
void MainWidget::showBackFromStack() {
|
||||
if (_stack.isEmpty() || selectingPeer()) return;
|
||||
if (selectingPeer()) return;
|
||||
if (_stack.isEmpty()) {
|
||||
if (cWideMode()) {
|
||||
showPeer(0, 0, false, true);
|
||||
QTimer::singleShot(0, this, SLOT(setInnerFocus()));
|
||||
} else {
|
||||
onShowDialogs();
|
||||
}
|
||||
return;
|
||||
}
|
||||
StackItem *item = _stack.back();
|
||||
_stack.pop_back();
|
||||
if (item->type() == HistoryStackItem) {
|
||||
|
@ -2313,19 +2393,26 @@ void MainWidget::resizeEvent(QResizeEvent *e) {
|
|||
if (cWideMode()) {
|
||||
_dialogsWidth = snap<int>((width() * 5) / 14, st::dlgMinWidth, st::dlgMaxWidth);
|
||||
dialogs.setGeometry(0, 0, _dialogsWidth + st::dlgShadow, height());
|
||||
_topBar.setGeometry(_dialogsWidth, 0, width() - _dialogsWidth, st::topBarHeight + st::titleShadow);
|
||||
history.setGeometry(_dialogsWidth, tbh, width() - _dialogsWidth, height() - tbh);
|
||||
_player.setGeometry(_dialogsWidth, 0, width() - _dialogsWidth, _player.height());
|
||||
_topBar.setGeometry(_dialogsWidth, _playerHeight, width() - _dialogsWidth, st::topBarHeight + st::titleShadow);
|
||||
history.setGeometry(_dialogsWidth, _playerHeight + tbh, width() - _dialogsWidth, height() - _playerHeight - tbh);
|
||||
if (hider) hider->setGeometry(QRect(_dialogsWidth, 0, width() - _dialogsWidth, height()));
|
||||
} else {
|
||||
_dialogsWidth = width();
|
||||
dialogs.setGeometry(0, 0, _dialogsWidth + st::dlgShadow, height());
|
||||
_topBar.setGeometry(0, 0, _dialogsWidth, st::topBarHeight + st::titleShadow);
|
||||
history.setGeometry(0, tbh, _dialogsWidth, height() - tbh);
|
||||
_player.setGeometry(0, 0, _dialogsWidth, _player.height());
|
||||
dialogs.setGeometry(0, _playerHeight, _dialogsWidth + st::dlgShadow, height() - _playerHeight);
|
||||
_topBar.setGeometry(0, _playerHeight, _dialogsWidth, st::topBarHeight + st::titleShadow);
|
||||
history.setGeometry(0, _playerHeight + tbh, _dialogsWidth, height() - _playerHeight - tbh);
|
||||
if (hider) hider->setGeometry(QRect(0, 0, _dialogsWidth, height()));
|
||||
}
|
||||
_mediaType.move(width() - _mediaType.width(), st::topBarHeight);
|
||||
_mediaType.move(width() - _mediaType.width(), _playerHeight + st::topBarHeight);
|
||||
if (profile) profile->setGeometry(history.geometry());
|
||||
if (overview) overview->setGeometry(history.geometry());
|
||||
_contentScrollAddToY = 0;
|
||||
}
|
||||
|
||||
int32 MainWidget::contentScrollAddToY() const {
|
||||
return _contentScrollAddToY;
|
||||
}
|
||||
|
||||
void MainWidget::keyPressEvent(QKeyEvent *e) {
|
||||
|
@ -2355,9 +2442,15 @@ void MainWidget::paintTopBar(QPainter &p, float64 over, int32 decreaseWidth) {
|
|||
}
|
||||
|
||||
void MainWidget::topBarShadowParams(int32 &x, float64 &o) {
|
||||
if (!profile && !overview && dialogs.isHidden()) {
|
||||
if (!cWideMode() && dialogs.isHidden()) {
|
||||
if (profile) {
|
||||
if (!history.activePeer()) profile->topBarShadowParams(x, o);
|
||||
} else if (overview) {
|
||||
if (!history.activePeer()) overview->topBarShadowParams(x, o);
|
||||
} else {
|
||||
history.topBarShadowParams(x, o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWidget::onPhotosSelect() {
|
||||
|
@ -2384,6 +2477,10 @@ TopBarWidget *MainWidget::topBar() {
|
|||
return &_topBar;
|
||||
}
|
||||
|
||||
PlayerWidget *MainWidget::player() {
|
||||
return &_player;
|
||||
}
|
||||
|
||||
void MainWidget::onTopBarClick() {
|
||||
if (profile) {
|
||||
profile->topBarClick();
|
||||
|
@ -3451,7 +3548,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
|
|||
}
|
||||
}
|
||||
App::markPeerUpdated(user);
|
||||
if (App::wnd()) App::wnd()->mediaOverviewUpdated(user);
|
||||
if (App::wnd()) App::wnd()->mediaOverviewUpdated(user, OverviewCount);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
|||
#include "historywidget.h"
|
||||
#include "profilewidget.h"
|
||||
#include "overviewwidget.h"
|
||||
#include "playerwidget.h"
|
||||
#include "apiwrap.h"
|
||||
|
||||
class Window;
|
||||
|
@ -189,6 +190,9 @@ public:
|
|||
void topBarShadowParams(int32 &x, float64 &o);
|
||||
TopBarWidget *topBar();
|
||||
|
||||
PlayerWidget *player();
|
||||
int32 contentScrollAddToY() const;
|
||||
|
||||
void animShow(const QPixmap &bgAnimCache, bool back = false);
|
||||
bool animStep(float64 ms);
|
||||
|
||||
|
@ -233,6 +237,7 @@ public:
|
|||
PeerData *activePeer();
|
||||
MsgId activeMsgId();
|
||||
PeerData *profilePeer();
|
||||
PeerData *overviewPeer();
|
||||
bool mediaTypeSwitch();
|
||||
void showPeerProfile(PeerData *peer, bool back = false, int32 lastScrollTop = -1, bool allMediaShown = false);
|
||||
void showMediaOverview(PeerData *peer, MediaOverviewType type, bool back = false, int32 lastScrollTop = -1);
|
||||
|
@ -313,7 +318,7 @@ public:
|
|||
|
||||
void searchMessages(const QString &query);
|
||||
void preloadOverviews(PeerData *peer);
|
||||
void mediaOverviewUpdated(PeerData *peer);
|
||||
void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type);
|
||||
void changingMsgId(HistoryItem *row, MsgId newId);
|
||||
void itemRemoved(HistoryItem *item);
|
||||
void itemReplaced(HistoryItem *oldItem, HistoryItem *newItem);
|
||||
|
@ -391,6 +396,7 @@ public slots:
|
|||
void documentLoadFailed(mtpFileLoader *loader, bool started);
|
||||
void documentLoadRetry();
|
||||
void documentPlayProgress(const SongMsgId &songId);
|
||||
void hidePlayer();
|
||||
|
||||
void setInnerFocus();
|
||||
void dialogsCancelled();
|
||||
|
@ -490,12 +496,16 @@ private:
|
|||
HistoryWidget history;
|
||||
ProfileWidget *profile;
|
||||
OverviewWidget *overview;
|
||||
PlayerWidget _player;
|
||||
TopBarWidget _topBar;
|
||||
ConfirmBox *_forwardConfirm; // for narrow mode
|
||||
HistoryHider *hider;
|
||||
StackItems _stack;
|
||||
QPixmap profileAnimCache;
|
||||
|
||||
int32 _playerHeight;
|
||||
int32 _contentScrollAddToY;
|
||||
|
||||
Dropdown _mediaType;
|
||||
int32 _mediaTypeMask;
|
||||
|
||||
|
|
|
@ -136,19 +136,19 @@ void MediaView::moveToScreen() {
|
|||
}
|
||||
|
||||
int32 navSkip = 2 * st::mvControlMargin + st::mvControlSize;
|
||||
_closeNav = rtlrect(width() - st::mvControlMargin - st::mvControlSize, st::mvControlMargin, st::mvControlSize, st::mvControlSize, width());
|
||||
_closeNav = myrtlrect(width() - st::mvControlMargin - st::mvControlSize, st::mvControlMargin, st::mvControlSize, st::mvControlSize);
|
||||
_closeNavIcon = centersprite(_closeNav, st::mvClose);
|
||||
_leftNav = rtlrect(st::mvControlMargin, navSkip, st::mvControlSize, height() - 2 * navSkip, width());
|
||||
_leftNav = myrtlrect(st::mvControlMargin, navSkip, st::mvControlSize, height() - 2 * navSkip);
|
||||
_leftNavIcon = centersprite(_leftNav, st::mvLeft);
|
||||
_rightNav = rtlrect(width() - st::mvControlMargin - st::mvControlSize, navSkip, st::mvControlSize, height() - 2 * navSkip, width());
|
||||
_rightNav = myrtlrect(width() - st::mvControlMargin - st::mvControlSize, navSkip, st::mvControlSize, height() - 2 * navSkip);
|
||||
_rightNavIcon = centersprite(_rightNav, st::mvRight);
|
||||
|
||||
_saveMsg.moveTo((width() - _saveMsg.width()) / 2, (height() - _saveMsg.height()) / 2);
|
||||
}
|
||||
|
||||
void MediaView::mediaOverviewUpdated(PeerData *peer) {
|
||||
void MediaView::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
|
||||
if (!_photo && !_doc) return;
|
||||
if (_history && _history->peer == peer) {
|
||||
if (_history && _history->peer == peer && type == _overview) {
|
||||
_index = -1;
|
||||
for (int i = 0, l = _history->_overview[_overview].size(); i < l; ++i) {
|
||||
if (_history->_overview[_overview].at(i) == _msgid) {
|
||||
|
@ -158,7 +158,7 @@ void MediaView::mediaOverviewUpdated(PeerData *peer) {
|
|||
}
|
||||
updateControls();
|
||||
preloadData(0);
|
||||
} else if (_user == peer) {
|
||||
} else if (_user == peer && type == OverviewCount) {
|
||||
if (!_photo) return;
|
||||
|
||||
_index = -1;
|
||||
|
@ -192,7 +192,7 @@ void MediaView::changingMsgId(HistoryItem *row, MsgId newId) {
|
|||
if (row->id == _msgid) {
|
||||
_msgid = newId;
|
||||
}
|
||||
mediaOverviewUpdated(row->history()->peer);
|
||||
mediaOverviewUpdated(row->history()->peer, _overview);
|
||||
}
|
||||
|
||||
void MediaView::updateDocSize() {
|
||||
|
@ -258,9 +258,9 @@ void MediaView::updateControls() {
|
|||
}
|
||||
|
||||
_saveVisible = ((_photo && _photo->full->loaded()) || (_doc && (!_doc->already(true).isEmpty() || (_current.isNull() && _currentGif.isNull()))));
|
||||
_saveNav = rtlrect(width() - st::mvIconSize.width() * 2, height() - st::mvIconSize.height(), st::mvIconSize.width(), st::mvIconSize.height(), width());
|
||||
_saveNav = myrtlrect(width() - st::mvIconSize.width() * 2, height() - st::mvIconSize.height(), st::mvIconSize.width(), st::mvIconSize.height());
|
||||
_saveNavIcon = centersprite(_saveNav, st::mvSave);
|
||||
_moreNav = rtlrect(width() - st::mvIconSize.width(), height() - st::mvIconSize.height(), st::mvIconSize.width(), st::mvIconSize.height(), width());
|
||||
_moreNav = myrtlrect(width() - st::mvIconSize.width(), height() - st::mvIconSize.height(), st::mvIconSize.width(), st::mvIconSize.height());
|
||||
_moreNavIcon = centersprite(_moreNav, st::mvMore);
|
||||
|
||||
QDateTime d(date(_photo ? _photo->date : _doc->date)), dNow(date(unixtime()));
|
||||
|
@ -273,11 +273,11 @@ void MediaView::updateControls() {
|
|||
}
|
||||
if (_from) {
|
||||
_fromName.setText(st::mvFont, _from->name);
|
||||
_nameNav = rtlrect(st::mvTextLeft, height() - st::mvTextTop, qMin(_fromName.maxWidth(), width() / 3), st::mvFont->height, width());
|
||||
_dateNav = rtlrect(st::mvTextLeft + _nameNav.width() + st::mvTextSkip, height() - st::mvTextTop, st::mvFont->m.width(_dateText), st::mvFont->height, width());
|
||||
_nameNav = myrtlrect(st::mvTextLeft, height() - st::mvTextTop, qMin(_fromName.maxWidth(), width() / 3), st::mvFont->height);
|
||||
_dateNav = myrtlrect(st::mvTextLeft + _nameNav.width() + st::mvTextSkip, height() - st::mvTextTop, st::mvFont->m.width(_dateText), st::mvFont->height);
|
||||
} else {
|
||||
_nameNav = QRect();
|
||||
_dateNav = rtlrect(st::mvTextLeft, height() - st::mvTextTop, st::mvFont->m.width(_dateText), st::mvFont->height, width());
|
||||
_dateNav = myrtlrect(st::mvTextLeft, height() - st::mvTextTop, st::mvFont->m.width(_dateText), st::mvFont->height);
|
||||
}
|
||||
updateHeader();
|
||||
if (_photo) {
|
||||
|
@ -349,7 +349,6 @@ bool MediaView::animStep(float64 msp) {
|
|||
a_cOpacity.finish();
|
||||
_controlsState = (_controlsState == ControlsShowing ? ControlsShown : ControlsHidden);
|
||||
setCursor(_controlsState == ControlsHidden ? Qt::BlankCursor : (_over == OverNone ? style::cur_default : style::cur_pointer));
|
||||
LOG(("Finished with controls!"));
|
||||
} else {
|
||||
a_cOpacity.update(dt, anim::linear);
|
||||
}
|
||||
|
@ -410,7 +409,6 @@ void MediaView::close() {
|
|||
void MediaView::activateControls() {
|
||||
_controlsHideTimer.start(int(st::mvWaitHide));
|
||||
if (_controlsState == ControlsHiding || _controlsState == ControlsHidden) {
|
||||
LOG(("Showing controls.."));
|
||||
_controlsState = ControlsShowing;
|
||||
_controlsAnimStarted = getms();
|
||||
a_cOpacity.start(1);
|
||||
|
@ -421,7 +419,6 @@ void MediaView::activateControls() {
|
|||
void MediaView::onHideControls(bool force) {
|
||||
if (!force && !_dropdown.isHidden()) return;
|
||||
if (_controlsState == ControlsHiding || _controlsState == ControlsHidden) return;
|
||||
LOG(("Hiding controls.."));
|
||||
_controlsState = ControlsHiding;
|
||||
_controlsAnimStarted = getms();
|
||||
a_cOpacity.start(0);
|
||||
|
@ -906,7 +903,7 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) {
|
|||
// _docSize is updated in updateControls()
|
||||
|
||||
_docRect = QRect((width() - st::mvDocSize.width()) / 2, (height() - st::mvDocSize.height()) / 2, st::mvDocSize.width(), st::mvDocSize.height());
|
||||
_docIconRect = rtlrect(_docRect.x() + st::mvDocPadding, _docRect.y() + st::mvDocPadding, st::mvDocBlue.pxWidth(), st::mvDocBlue.pxHeight(), width());
|
||||
_docIconRect = myrtlrect(_docRect.x() + st::mvDocPadding, _docRect.y() + st::mvDocPadding, st::mvDocBlue.pxWidth(), st::mvDocBlue.pxHeight());
|
||||
} else if (!_current.isNull()) {
|
||||
_current.setDevicePixelRatio(cRetinaFactor());
|
||||
_w = _current.width() / cIntRetinaFactor();
|
||||
|
@ -1264,11 +1261,6 @@ void MediaView::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static uint64 t = getms();
|
||||
// uint64 t2 = getms();
|
||||
// LOG(("paint: %1, wait: %2, name: %3, icon: %4").arg(t2 - ms).arg(t2 - t).arg(logBool(name)).arg(logBool(icon)));
|
||||
// t = t2;
|
||||
}
|
||||
|
||||
void MediaView::keyPressEvent(QKeyEvent *e) {
|
||||
|
@ -1828,7 +1820,7 @@ void MediaView::findCurrent() {
|
|||
}
|
||||
}
|
||||
|
||||
if (_history->_overviewCount[_overview] < 0) {
|
||||
if (_history->_overviewCount[_overview] < 0 || (!_index && _history->_overviewCount[_overview] > 0)) {
|
||||
loadBack();
|
||||
}
|
||||
}
|
||||
|
@ -1877,7 +1869,7 @@ void MediaView::userPhotosLoaded(UserData *u, const MTPphotos_Photos &photos, mt
|
|||
photo->thumb->load();
|
||||
u->photos.push_back(photo);
|
||||
}
|
||||
if (App::wnd()) App::wnd()->mediaOverviewUpdated(u);
|
||||
if (App::wnd()) App::wnd()->mediaOverviewUpdated(u, OverviewCount);
|
||||
}
|
||||
|
||||
void MediaView::updateHeader() {
|
||||
|
@ -1913,7 +1905,7 @@ void MediaView::updateHeader() {
|
|||
hwidth = width() / 3;
|
||||
_headerText = st::mvThickFont->m.elidedText(_headerText, Qt::ElideMiddle, hwidth);
|
||||
}
|
||||
_headerNav = rtlrect(st::mvTextLeft, height() - st::mvHeaderTop, hwidth, st::mvThickFont->height, width());
|
||||
_headerNav = myrtlrect(st::mvTextLeft, height() - st::mvHeaderTop, hwidth, st::mvThickFont->height);
|
||||
}
|
||||
//
|
||||
//void MediaView::updatePolaroid() {
|
||||
|
|
|
@ -55,7 +55,7 @@ public:
|
|||
updateOver(mapFromGlobal(QCursor::pos()));
|
||||
}
|
||||
|
||||
void mediaOverviewUpdated(PeerData *peer);
|
||||
void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type);
|
||||
void documentUpdated(DocumentData *doc);
|
||||
void changingMsgId(HistoryItem *row, MsgId newId);
|
||||
void updateDocSize();
|
||||
|
|
|
@ -1681,8 +1681,12 @@ void OverviewWidget::onScroll() {
|
|||
}
|
||||
|
||||
void OverviewWidget::resizeEvent(QResizeEvent *e) {
|
||||
int32 st = _scroll.scrollTop();
|
||||
_scroll.resize(size());
|
||||
int32 newScrollTop = _inner.resizeToWidth(width(), _scroll.scrollTop(), height());
|
||||
int32 newScrollTop = _inner.resizeToWidth(width(), st, height());
|
||||
if (int32 addToY = App::main() ? App::main()->contentScrollAddToY() : 0) {
|
||||
newScrollTop += addToY;
|
||||
}
|
||||
if (newScrollTop != _scroll.scrollTop()) {
|
||||
_noDropResizeIndex = true;
|
||||
_scroll.scrollToY(newScrollTop);
|
||||
|
@ -1700,33 +1704,36 @@ void OverviewWidget::paintEvent(QPaintEvent *e) {
|
|||
return;
|
||||
}
|
||||
|
||||
bool hasTopBar = !App::main()->topBar()->isHidden();
|
||||
QRect r(e->rect());
|
||||
if (type() == OverviewPhotos) {
|
||||
p.fillRect(r, st::white->b);
|
||||
} else if (cTileBackground()) {
|
||||
int left = r.left(), top = r.top(), right = r.left() + r.width(), bottom = r.top() + r.height();
|
||||
if (right > 0 && bottom > 0) {
|
||||
QRect fill(left, top + (hasTopBar ? st::topBarHeight : 0), right, bottom + (hasTopBar ? st::topBarHeight : 0));
|
||||
|
||||
if (hasTopBar) p.translate(0, -st::topBarHeight);
|
||||
p.fillRect(fill, QBrush(*cChatBackground()));
|
||||
if (hasTopBar) p.translate(0, st::topBarHeight);
|
||||
}
|
||||
} else {
|
||||
bool hasTopBar = !App::main()->topBar()->isHidden(), hasPlayer = !App::main()->player()->isHidden();
|
||||
QRect fill(0, 0, width(), App::main()->height());
|
||||
int fromy = hasTopBar ? (-st::topBarHeight) : 0, x = 0, y = 0;
|
||||
int fromy = (hasTopBar ? (-st::topBarHeight) : 0) + (hasPlayer ? (-st::playerHeight) : 0), x = 0, y = 0;
|
||||
QPixmap cached = App::main()->cachedBackground(fill, x, y);
|
||||
if (cached.isNull()) {
|
||||
const QPixmap &pix(*cChatBackground());
|
||||
if (cTileBackground()) {
|
||||
int left = r.left(), top = r.top(), right = r.left() + r.width(), bottom = r.top() + r.height();
|
||||
float64 w = pix.width() / cRetinaFactor(), h = pix.height() / cRetinaFactor();
|
||||
int sx = qFloor(left / w), sy = qFloor((top - fromy) / h), cx = qCeil(right / w), cy = qCeil((bottom - fromy) / h);
|
||||
for (int i = sx; i < cx; ++i) {
|
||||
for (int j = sy; j < cy; ++j) {
|
||||
p.drawPixmap(QPointF(i * w, fromy + j * h), pix);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bool smooth = p.renderHints().testFlag(QPainter::SmoothPixmapTransform);
|
||||
p.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
|
||||
QRect to, from;
|
||||
App::main()->backgroundParams(fill, to, from);
|
||||
to.moveTop(to.top() + fromy);
|
||||
p.drawPixmap(to, *cChatBackground(), from);
|
||||
p.drawPixmap(to, pix, from);
|
||||
|
||||
if (!smooth) p.setRenderHint(QPainter::SmoothPixmapTransform, false);
|
||||
}
|
||||
} else {
|
||||
p.drawPixmap(x, fromy + y, cached);
|
||||
}
|
||||
|
@ -1760,6 +1767,13 @@ void OverviewWidget::paintTopBar(QPainter &p, float64 over, int32 decreaseWidth)
|
|||
}
|
||||
}
|
||||
|
||||
void OverviewWidget::topBarShadowParams(int32 &x, float64 &o) {
|
||||
if (animating() && a_coord.current() >= 0) {
|
||||
x = a_coord.current();
|
||||
o = a_alpha.current();
|
||||
}
|
||||
}
|
||||
|
||||
void OverviewWidget::topBarClick() {
|
||||
App::main()->showBackFromStack();
|
||||
}
|
||||
|
@ -1781,6 +1795,7 @@ void OverviewWidget::switchType(MediaOverviewType type) {
|
|||
case OverviewVideos: _header = lang(lng_profile_videos_header); break;
|
||||
case OverviewDocuments: _header = lang(lng_profile_files_header); break;
|
||||
case OverviewAudios: _header = lang(lng_profile_audios_header); break;
|
||||
case OverviewAudioDocuments: _header = lang(lng_profile_audio_files_header); break;
|
||||
}
|
||||
noSelectingScroll();
|
||||
App::main()->topBar()->showSelected(0);
|
||||
|
@ -1847,10 +1862,7 @@ bool OverviewWidget::animStep(float64 ms) {
|
|||
a_alpha.finish();
|
||||
_bgAnimCache = _animCache = _animTopBarCache = _bgAnimTopBarCache = QPixmap();
|
||||
App::main()->topBar()->stopAnim();
|
||||
_scroll.show();
|
||||
_scroll.scrollToY(_scrollSetAfterShow);
|
||||
activate();
|
||||
onScroll();
|
||||
doneShow();
|
||||
} else {
|
||||
a_bgCoord.update(dt1, st::introHideFunc);
|
||||
a_bgAlpha.update(dt1, st::introAlphaHideFunc);
|
||||
|
@ -1862,8 +1874,15 @@ bool OverviewWidget::animStep(float64 ms) {
|
|||
return res;
|
||||
}
|
||||
|
||||
void OverviewWidget::mediaOverviewUpdated(PeerData *p) {
|
||||
if (peer() == p) {
|
||||
void OverviewWidget::doneShow() {
|
||||
_scroll.show();
|
||||
_scroll.scrollToY(_scrollSetAfterShow);
|
||||
activate();
|
||||
onScroll();
|
||||
}
|
||||
|
||||
void OverviewWidget::mediaOverviewUpdated(PeerData *p, MediaOverviewType t) {
|
||||
if (peer() == p && t == type()) {
|
||||
_inner.mediaOverviewUpdated();
|
||||
onScroll();
|
||||
updateTopBarSelection();
|
||||
|
|
|
@ -142,6 +142,7 @@ private:
|
|||
} CachedItem;
|
||||
typedef QVector<CachedItem> CachedItems;
|
||||
CachedItems _items;
|
||||
|
||||
int32 _width, _height, _minHeight, _addToY;
|
||||
|
||||
// selection support, like in HistoryWidget
|
||||
|
@ -199,6 +200,7 @@ public:
|
|||
void scrollBy(int32 add);
|
||||
|
||||
void paintTopBar(QPainter &p, float64 over, int32 decreaseWidth);
|
||||
void topBarShadowParams(int32 &x, float64 &o);
|
||||
void topBarClick();
|
||||
|
||||
PeerData *peer() const;
|
||||
|
@ -212,7 +214,9 @@ public:
|
|||
void animShow(const QPixmap &oldAnimCache, const QPixmap &bgAnimTopBarCache, bool back = false, int32 lastScrollTop = -1);
|
||||
bool animStep(float64 ms);
|
||||
|
||||
void mediaOverviewUpdated(PeerData *peer);
|
||||
void doneShow();
|
||||
|
||||
void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type);
|
||||
void changingMsgId(HistoryItem *row, MsgId newId);
|
||||
void msgUpdated(PeerId peer, const HistoryItem *msg);
|
||||
void itemRemoved(HistoryItem *item);
|
||||
|
|
|
@ -0,0 +1,548 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "style.h"
|
||||
#include "lang.h"
|
||||
|
||||
#include "boxes/addcontactbox.h"
|
||||
#include "application.h"
|
||||
#include "window.h"
|
||||
#include "playerwidget.h"
|
||||
#include "mainwidget.h"
|
||||
|
||||
#include "localstorage.h"
|
||||
|
||||
#include "audio.h"
|
||||
|
||||
PlayerWidget::PlayerWidget(QWidget *parent) : TWidget(parent),
|
||||
_prevAvailable(false), _nextAvailable(false), _fullAvailable(false),
|
||||
_over(OverNone), _down(OverNone), _downCoord(0), _downProgress(0.), _downFrequency(AudioVoiceMsgFrequency),
|
||||
_stateAnim(animFunc(this, &PlayerWidget::stateStep)),
|
||||
_index(-1), _history(0), _showPause(false), _position(0), _duration(0), _loaded(0),
|
||||
a_progress(0., 0.), a_loadProgress(0., 0.), _progressAnim(animFunc(this, &PlayerWidget::progressStep)) {
|
||||
resize(st::wndMinWidth, st::playerHeight);
|
||||
setMouseTracking(true);
|
||||
memset(_stateHovers, 0, sizeof(_stateHovers));
|
||||
}
|
||||
|
||||
void PlayerWidget::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
QRect r(e->rect()), checkr(myrtlrect(r));
|
||||
p.fillRect(r, st::playerBg->b);
|
||||
|
||||
if (!_playbackRect.contains(checkr)) {
|
||||
if (_fullAvailable && checkr.intersects(_prevRect)) {
|
||||
if (_prevAvailable) {
|
||||
float64 o = _stateHovers[OverPrev];
|
||||
p.setOpacity(o * 1. + (1. - o) * st::playerInactiveOpacity);
|
||||
} else {
|
||||
p.setOpacity(st::playerUnavailableOpacity);
|
||||
}
|
||||
p.drawSpriteCenterLeft(_prevRect, width(), st::playerPrev);
|
||||
}
|
||||
if (checkr.intersects(_playRect)) {
|
||||
float64 o = _stateHovers[OverPlay];
|
||||
p.setOpacity(o * 1. + (1. - o) * st::playerInactiveOpacity);
|
||||
p.drawSpriteCenterLeft(_playRect, width(), (_showPause || _down == OverPlayback) ? st::playerPause : st::playerPlay);
|
||||
}
|
||||
if (_fullAvailable && checkr.intersects(_nextRect)) {
|
||||
if (_nextAvailable) {
|
||||
float64 o = _stateHovers[OverNext];
|
||||
p.setOpacity(o * 1. + (1. - o) * st::playerInactiveOpacity);
|
||||
} else {
|
||||
p.setOpacity(st::playerUnavailableOpacity);
|
||||
}
|
||||
p.drawSpriteCenterLeft(_nextRect, width(), st::playerNext);
|
||||
}
|
||||
if (checkr.intersects(_closeRect)) {
|
||||
float64 o = _stateHovers[OverClose];
|
||||
p.setOpacity(o * 1. + (1. - o) * st::playerInactiveOpacity);
|
||||
p.drawSpriteCenterLeft(_closeRect, width(), st::playerClose);
|
||||
}
|
||||
if (checkr.intersects(_volumeRect)) {
|
||||
float64 o = _stateHovers[OverVolume];
|
||||
p.setOpacity(o * 1. + (1. - o) * st::playerInactiveOpacity);
|
||||
int32 top = _volumeRect.y() + (_volumeRect.height() - st::playerVolume.pxHeight()) / 2;
|
||||
int32 left = _volumeRect.x() + (_volumeRect.width() - st::playerVolume.pxWidth()) / 2;
|
||||
int32 mid = left + qRound(st::playerVolume.pxWidth() * cSongVolume());
|
||||
int32 right = left + st::playerVolume.pxWidth();
|
||||
if (rtl()) {
|
||||
left = width() - left;
|
||||
mid = width() - mid;
|
||||
right = width() - right;
|
||||
if (mid < left) {
|
||||
p.drawPixmap(QRect(mid, top, left - mid, st::playerVolume.pxHeight()), App::sprite(), QRect(st::playerVolume.x() + (mid - right) * cIntRetinaFactor(), st::playerVolume.y(), (left - mid) * cIntRetinaFactor(), st::playerVolume.pxHeight() * cIntRetinaFactor()));
|
||||
}
|
||||
if (right < mid) {
|
||||
p.setOpacity(st::playerUnavailableOpacity);
|
||||
p.drawPixmap(QRect(right, top, mid - right, st::playerVolume.pxHeight()), App::sprite(), QRect(st::playerVolume.x(), st::playerVolume.y(), (mid - right) * cIntRetinaFactor(), st::playerVolume.pxHeight() * cIntRetinaFactor()));
|
||||
}
|
||||
} else {
|
||||
if (mid > left) {
|
||||
p.drawPixmap(QRect(left, top, mid - left, st::playerVolume.pxHeight()), App::sprite(), QRect(st::playerVolume.x(), st::playerVolume.y(), (mid - left) * cIntRetinaFactor(), st::playerVolume.pxHeight() * cIntRetinaFactor()));
|
||||
}
|
||||
if (right > mid) {
|
||||
p.setOpacity(st::playerUnavailableOpacity);
|
||||
p.drawPixmap(QRect(mid, top, right - mid, st::playerVolume.pxHeight()), App::sprite(), QRect(st::playerVolume.x() + (mid - left) * cIntRetinaFactor(), st::playerVolume.y(), (right - mid) * cIntRetinaFactor(), st::playerVolume.pxHeight() * cIntRetinaFactor()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_fullAvailable && checkr.intersects(_fullRect)) {
|
||||
float64 o = _stateHovers[OverFull];
|
||||
p.setOpacity(o * 1. + (1. - o) * st::playerInactiveOpacity);
|
||||
p.drawSpriteCenterLeft(_fullRect, width(), st::playerFull);
|
||||
}
|
||||
p.setOpacity(1.);
|
||||
|
||||
p.setPen(st::playerTimeFg->p);
|
||||
p.setFont(st::linkFont->f);
|
||||
p.drawTextLeft(_infoRect.x() + _infoRect.width() - _timeWidth, _infoRect.y() + (_infoRect.height() - st::linkFont->height) / 2, width(), _time, _timeWidth);
|
||||
|
||||
textstyleSet(&st::playerNameStyle);
|
||||
p.setPen(st::playerFg->p);
|
||||
_name.drawElided(p, _infoRect.x() + (rtl() ? (_timeWidth + st::playerSkip) : 0), _infoRect.y() + (_infoRect.height() - st::linkFont->height) / 2, _infoRect.width() - _timeWidth - st::playerSkip);
|
||||
textstyleRestore();
|
||||
}
|
||||
|
||||
if (_duration) {
|
||||
float64 prg = (_down == OverPlayback) ? _downProgress : a_progress.current();
|
||||
int32 from = _playbackRect.x(), mid = qRound(_playbackRect.x() + prg * _playbackRect.width()), end = _playbackRect.x() + _playbackRect.width();
|
||||
if (mid > from) {
|
||||
p.fillRect(rtl() ? (width() - mid) : from, height() - st::playerLineHeight, mid - from, _playbackRect.height(), st::playerLineActive->b);
|
||||
}
|
||||
if (end > mid) {
|
||||
p.fillRect(rtl() ? (width() - end) : mid, height() - st::playerLineHeight, end - mid, st::playerLineHeight, st::playerLineInactive->b);
|
||||
}
|
||||
if (_stateHovers[OverPlayback] > 0) {
|
||||
p.setOpacity(_stateHovers[OverPlayback]);
|
||||
|
||||
int32 x = mid - (st::playerMoverSize.width() / 2);
|
||||
p.fillRect(rtl() ? (width() - x - st::playerMoverSize.width()) : x, height() - st::playerMoverSize.height(), st::playerMoverSize.width(), st::playerMoverSize.height(), st::playerLineActive->b);
|
||||
}
|
||||
} else if (a_loadProgress.current() > 0) {
|
||||
int32 from = _playbackRect.x(), mid = qRound(_playbackRect.x() + a_loadProgress.current() * _playbackRect.width());
|
||||
if (mid > from) {
|
||||
p.fillRect(rtl() ? (width() - mid) : from, height() - st::playerLineHeight, mid - from, _playbackRect.height(), st::playerLineInactive->b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerWidget::mousePressEvent(QMouseEvent *e) {
|
||||
QPoint pos(myrtlpoint(e->pos()));
|
||||
|
||||
if (e->button() == Qt::LeftButton) {
|
||||
_down = OverNone;
|
||||
if (_song && _over == OverPlay) {
|
||||
SongMsgId playing;
|
||||
AudioPlayerState playingState = AudioPlayerStopped;
|
||||
audioPlayer()->currentState(&playing, &playingState);
|
||||
if (playing == _song && !(playingState & AudioPlayerStoppedMask)) {
|
||||
audioPlayer()->pauseresume(OverviewDocuments);
|
||||
} else {
|
||||
audioPlayer()->play(_song);
|
||||
if (App::main()) App::main()->documentPlayProgress(_song);
|
||||
}
|
||||
return;
|
||||
} else if (_over == OverPrev) {
|
||||
const History::MediaOverview *o = _history ? &_history->_overview[OverviewAudioDocuments] : 0;
|
||||
if (audioPlayer() && o && _index > 0 && _index <= o->size() && !o->isEmpty()) {
|
||||
startPlay(o->at(_index - 1));
|
||||
}
|
||||
} else if (_over == OverNext) {
|
||||
const History::MediaOverview *o = _history ? &_history->_overview[OverviewAudioDocuments] : 0;
|
||||
if (audioPlayer() && o && _index >= 0 && _index < o->size() - 1) {
|
||||
startPlay(o->at(_index + 1));
|
||||
}
|
||||
} else if (_over == OverClose) {
|
||||
_down = OverClose;
|
||||
} else if (_over == OverVolume) {
|
||||
_down = OverVolume;
|
||||
_downCoord = pos.x() - _volumeRect.x();
|
||||
cSetSongVolume(snap((_downCoord - ((_volumeRect.width() - st::playerVolume.pxWidth()) / 2)) / float64(st::playerVolume.pxWidth()), 0., 1.));
|
||||
emit audioPlayer()->songVolumeChanged();
|
||||
rtlupdate(_volumeRect);
|
||||
} else if (_over == OverPlayback) {
|
||||
SongMsgId playing;
|
||||
AudioPlayerState playingState = AudioPlayerStopped;
|
||||
int64 playingPosition = 0, playingDuration = 0;
|
||||
int32 playingFrequency = 0;
|
||||
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency);
|
||||
if (playing == _song && playingDuration) {
|
||||
if (playingState == AudioPlayerPlaying || playingState == AudioPlayerStarting || playingState == AudioPlayerResuming) {
|
||||
audioPlayer()->pauseresume(OverviewDocuments);
|
||||
}
|
||||
_down = OverPlayback;
|
||||
_downProgress = snap((pos.x() - _playbackRect.x()) / float64(_playbackRect.width()), 0., 1.);
|
||||
_downDuration = playingDuration;
|
||||
_downFrequency = (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency);
|
||||
|
||||
rtlupdate(_playbackRect);
|
||||
updateDownTime();
|
||||
}
|
||||
} else if (_over == OverFull && _song) {
|
||||
if (HistoryItem *item = App::histItemById(_song.msgId)) {
|
||||
App::main()->showMediaOverview(item->history()->peer, OverviewAudioDocuments);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerWidget::updateDownTime() {
|
||||
QString time = formatDurationText(qRound(_downDuration * _downProgress) / _downFrequency);
|
||||
if (time != _time) {
|
||||
_time = time;
|
||||
_timeWidth = st::linkFont->m.width(_time);
|
||||
rtlupdate(_infoRect);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerWidget::updateOverState(OverState newState) {
|
||||
bool result = true;
|
||||
if (_over != newState) {
|
||||
updateOverRect(_over);
|
||||
updateOverRect(newState);
|
||||
if (_over != OverNone) {
|
||||
_stateAnimations.remove(_over);
|
||||
_stateAnimations[-_over] = getms() - ((1. - _stateHovers[_over]) * st::playerDuration);
|
||||
if (!_stateAnim.animating()) _stateAnim.start();
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
_over = newState;
|
||||
if (newState != OverNone) {
|
||||
_stateAnimations.remove(-_over);
|
||||
_stateAnimations[_over] = getms() - (_stateHovers[_over] * st::playerDuration);
|
||||
if (!_stateAnim.animating()) _stateAnim.start();
|
||||
setCursor(style::cur_pointer);
|
||||
} else {
|
||||
setCursor(style::cur_default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerWidget::updateOverRect(OverState state) {
|
||||
switch (state) {
|
||||
case OverPrev: rtlupdate(_prevRect); break;
|
||||
case OverPlay: rtlupdate(_playRect); break;
|
||||
case OverNext: rtlupdate(_nextRect); break;
|
||||
case OverClose: rtlupdate(_closeRect); break;
|
||||
case OverVolume: rtlupdate(_volumeRect); break;
|
||||
case OverFull: rtlupdate(_fullRect); break;
|
||||
case OverPlayback: rtlupdate(_playbackRect); break;
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerWidget::updateControls() {
|
||||
_fullAvailable = (_index >= 0);
|
||||
_prevAvailable = _fullAvailable && (_index > 0);
|
||||
_nextAvailable = _fullAvailable && (_index < _history->_overview[OverviewAudioDocuments].size() - 1);
|
||||
resizeEvent(0);
|
||||
update();
|
||||
|
||||
if (_index >= 0 && _index < MediaOverviewStartPerPage) {
|
||||
if (_history->_overviewCount[OverviewAudioDocuments] < 0 || _history->_overviewCount[OverviewAudioDocuments] > 0) {
|
||||
if (App::main()) App::main()->loadMediaBack(_history->peer, OverviewAudioDocuments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerWidget::findCurrent() {
|
||||
_index = -1;
|
||||
if (!_history) return;
|
||||
|
||||
const History::MediaOverview *o = &_history->_overview[OverviewAudioDocuments];
|
||||
for (int i = 0, l = o->size(); i < l; ++i) {
|
||||
if (o->at(i) == _song.msgId) {
|
||||
_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_index < 0) return;
|
||||
|
||||
if (_index < o->size() - 1) {
|
||||
if (HistoryItem *next = App::histItemById(o->at(_index + 1))) {
|
||||
if (HistoryDocument *document = static_cast<HistoryDocument*>(next->getMedia())) {
|
||||
if (document->document()->already(true).isEmpty() && document->document()->data.isEmpty()) {
|
||||
if (!document->document()->loader) {
|
||||
DocumentOpenLink::doOpen(document->document());
|
||||
document->document()->openOnSave = document->document()->openOnSaveMsgId = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerWidget::startPlay(MsgId msgId) {
|
||||
if (HistoryItem *item = App::histItemById(msgId)) {
|
||||
if (HistoryDocument *doc = static_cast<HistoryDocument*>(item->getMedia())) {
|
||||
audioPlayer()->play(SongMsgId(doc->document(), item->id));
|
||||
updateState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerWidget::clearSelection() {
|
||||
for (StateAnimations::const_iterator i = _stateAnimations.cbegin(); i != _stateAnimations.cend(); ++i) {
|
||||
_stateHovers[qAbs(i.key())] = 0;
|
||||
}
|
||||
_stateAnimations.clear();
|
||||
}
|
||||
|
||||
void PlayerWidget::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
|
||||
if (_history && _history->peer == peer && type == OverviewAudioDocuments) {
|
||||
_index = -1;
|
||||
for (int i = 0, l = _history->_overview[OverviewAudioDocuments].size(); i < l; ++i) {
|
||||
if (_history->_overview[OverviewAudioDocuments].at(i) == _song.msgId) {
|
||||
_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
updateControls();
|
||||
}
|
||||
}
|
||||
|
||||
bool PlayerWidget::seekingSong(const SongMsgId &song) const {
|
||||
return (_down == OverPlayback) && (song == _song);
|
||||
}
|
||||
|
||||
bool PlayerWidget::stateStep(float64 msñ) {
|
||||
bool result = false;
|
||||
uint64 ms = getms();
|
||||
for (StateAnimations::iterator i = _stateAnimations.begin(); i != _stateAnimations.cend();) {
|
||||
int32 over = qAbs(i.key());
|
||||
updateOverRect(OverState(over));
|
||||
|
||||
float64 dt = float64(ms - i.value()) / st::playerDuration;
|
||||
if (dt >= 1) {
|
||||
_stateHovers[over] = (i.key() > 0) ? 1 : 0;
|
||||
i = _stateAnimations.erase(i);
|
||||
} else {
|
||||
_stateHovers[over] = (i.key() > 0) ? dt : (1 - dt);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return !_stateAnimations.isEmpty();
|
||||
}
|
||||
|
||||
void PlayerWidget::mouseMoveEvent(QMouseEvent *e) {
|
||||
_lastMousePos = e->globalPos();
|
||||
updateSelected();
|
||||
}
|
||||
|
||||
void PlayerWidget::leaveEvent(QEvent *e) {
|
||||
_lastMousePos = QCursor::pos();
|
||||
updateSelected();
|
||||
}
|
||||
|
||||
void PlayerWidget::updateSelected() {
|
||||
QPoint pos(myrtlpoint(mapFromGlobal(_lastMousePos)));
|
||||
|
||||
if (_down == OverVolume) {
|
||||
int32 delta = (pos.x() - _volumeRect.x()) - _downCoord;
|
||||
float64 startFrom = snap((_downCoord - ((_volumeRect.width() - st::playerVolume.pxWidth()) / 2)) / float64(st::playerVolume.pxWidth()), 0., 1.);
|
||||
float64 add = delta / float64(4 * st::playerVolume.pxWidth()), result = snap(startFrom + add, 0., 1.);
|
||||
if (result != cSongVolume()) {
|
||||
cSetSongVolume(result);
|
||||
emit audioPlayer()->songVolumeChanged();
|
||||
rtlupdate(_volumeRect);
|
||||
}
|
||||
} else if (_down == OverPlayback) {
|
||||
_downProgress = snap((pos.x() - _playbackRect.x()) / float64(_playbackRect.width()), 0., 1.);
|
||||
rtlupdate(_playbackRect);
|
||||
updateDownTime();
|
||||
} else if (_down == OverNone) {
|
||||
bool inInfo = ((pos.x() >= _infoRect.x()) && (pos.x() < _fullRect.x() + _fullRect.width()) && (pos.y() >= _playRect.y()) && (pos.y() <= _playRect.y() + _playRect.height()));
|
||||
if (_prevAvailable && _prevRect.contains(pos)) {
|
||||
updateOverState(OverPrev);
|
||||
} else if (_nextAvailable && _nextRect.contains(pos)) {
|
||||
updateOverState(OverNext);
|
||||
} else if (_playRect.contains(pos)) {
|
||||
updateOverState(OverPlay);
|
||||
} else if (_closeRect.contains(pos)) {
|
||||
updateOverState(OverClose);
|
||||
} else if (_volumeRect.contains(pos)) {
|
||||
updateOverState(OverVolume);
|
||||
} else if (_duration && _playbackRect.contains(pos)) {
|
||||
updateOverState(OverPlayback);
|
||||
} else if (_fullAvailable && inInfo) {
|
||||
updateOverState(OverFull);
|
||||
} else if (_over != OverNone) {
|
||||
updateOverState(OverNone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||
if (_down == OverVolume) {
|
||||
mouseMoveEvent(e);
|
||||
Local::writeUserSettings();
|
||||
} else if (_down == OverPlayback) {
|
||||
mouseMoveEvent(e);
|
||||
SongMsgId playing;
|
||||
AudioPlayerState playingState = AudioPlayerStopped;
|
||||
int64 playingPosition = 0, playingDuration = 0;
|
||||
int32 playingFrequency = 0;
|
||||
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency);
|
||||
if (playing == _song && playingDuration) {
|
||||
_downDuration = playingDuration;
|
||||
audioPlayer()->seek(qRound(_downProgress * _downDuration));
|
||||
|
||||
_showPause = true;
|
||||
|
||||
a_progress = anim::fvalue(_downProgress, _downProgress);
|
||||
_progressAnim.stop();
|
||||
}
|
||||
update();
|
||||
} else if (_down == OverClose && _over == OverClose) {
|
||||
if (_song) {
|
||||
audioPlayer()->stop(OverviewDocuments);
|
||||
if (App::main()) App::main()->hidePlayer();
|
||||
}
|
||||
}
|
||||
_down = OverNone;
|
||||
}
|
||||
|
||||
void PlayerWidget::resizeEvent(QResizeEvent *e) {
|
||||
int32 availh = (height() - st::playerLineHeight);
|
||||
int32 ch = st::playerPlay.pxHeight() + st::playerSkip, ct = (availh - ch) / 2;
|
||||
_playbackRect = QRect(cWideMode() ? st::dlgShadow : 0, height() - st::playerMoverSize.height(), width() - (cWideMode() ? st::dlgShadow : 0), st::playerMoverSize.height());
|
||||
_prevRect = _fullAvailable ? QRect(st::playerSkip / 2, ct, st::playerPrev.pxWidth() + st::playerSkip, ch) : QRect();
|
||||
_playRect = QRect(_fullAvailable ? (_prevRect.x() + _prevRect.width()) : (st::playerSkip / 2), ct, st::playerPlay.pxWidth() + st::playerSkip, ch);
|
||||
_nextRect = _fullAvailable ? QRect(_playRect.x() + _playRect.width(), ct, st::playerNext.pxWidth() + st::playerSkip, ch) : QRect();
|
||||
|
||||
_closeRect = QRect(width() - st::playerSkip / 2 - st::playerClose.pxWidth() - st::playerSkip, ct, st::playerClose.pxWidth() + st::playerSkip, ch);
|
||||
_volumeRect = QRect(_closeRect.x() - st::playerVolume.pxWidth() - st::playerSkip, ct, st::playerVolume.pxWidth() + st::playerSkip, ch);
|
||||
_fullRect = _fullAvailable ? QRect(_volumeRect.x() - st::playerFull.pxWidth() - st::playerSkip, ct, st::playerFull.pxWidth() + st::playerSkip, ch) : QRect();
|
||||
|
||||
int32 infoLeft = (_fullAvailable ? (_nextRect.x() + _nextRect.width()) : (_playRect.x() + _playRect.width()));
|
||||
_infoRect = QRect(infoLeft + st::playerSkip / 2, 0, (_fullAvailable ? _fullRect.x() : _volumeRect.x()) - infoLeft - st::playerSkip, availh);
|
||||
update();
|
||||
}
|
||||
|
||||
bool PlayerWidget::progressStep(float64 ms) {
|
||||
float64 dt = ms / (2 * AudioVoiceMsgUpdateView);
|
||||
bool res = true;
|
||||
if (_duration && dt >= 1) {
|
||||
a_progress.finish();
|
||||
a_loadProgress.finish();
|
||||
res = false;
|
||||
} else {
|
||||
a_progress.update(qMin(dt, 1.), anim::linear);
|
||||
a_loadProgress.update(1. - (st::radialDuration / (st::radialDuration + ms)), anim::linear);
|
||||
}
|
||||
rtlupdate(_playbackRect);
|
||||
return res;
|
||||
}
|
||||
|
||||
void PlayerWidget::updateState() {
|
||||
updateState(SongMsgId(), AudioPlayerStopped, 0, 0, 0);
|
||||
}
|
||||
|
||||
void PlayerWidget::updateState(SongMsgId playing, AudioPlayerState playingState, int64 playingPosition, int64 playingDuration, int32 playingFrequency) {
|
||||
if (!playing) {
|
||||
audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency);
|
||||
}
|
||||
|
||||
bool songChanged = false;
|
||||
if (playing && _song != playing) {
|
||||
songChanged = true;
|
||||
_song = playing;
|
||||
if (HistoryItem *item = App::histItemById(_song.msgId)) {
|
||||
_history = item->history();
|
||||
findCurrent();
|
||||
} else {
|
||||
_history = 0;
|
||||
_index = -1;
|
||||
}
|
||||
SongData *song = _song.song->song();
|
||||
if (song->performer.isEmpty()) {
|
||||
_name.setText(st::linkFont, song->title.isEmpty() ? (_song.song->name.isEmpty() ? qsl("Unknown Track") : _song.song->name) : song->title, _textNameOptions);
|
||||
} else {
|
||||
TextCustomTagsMap custom;
|
||||
custom.insert(QChar('c'), qMakePair(textcmdStartLink(1), textcmdStopLink()));
|
||||
_name.setRichText(st::linkFont, QString::fromUtf8("[c]%1[/c] \xe2\x80\x93 %2").arg(textRichPrepare(song->performer)).arg(song->title.isEmpty() ? qsl("Unknown Track") : textRichPrepare(song->title)), _textNameOptions, custom);
|
||||
}
|
||||
updateControls();
|
||||
}
|
||||
|
||||
qint64 position = 0, duration = 0, display = 0;
|
||||
if (playing == _song) {
|
||||
if (!(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
|
||||
display = position = playingPosition;
|
||||
duration = playingDuration;
|
||||
} else {
|
||||
display = playingDuration;
|
||||
}
|
||||
display = display / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency);
|
||||
} else if (_song) {
|
||||
display = _song.song->song()->duration;
|
||||
}
|
||||
QString time = (_down == OverPlayback) ? _time : formatDurationText(display);
|
||||
bool showPause = false, stopped = ((playingState & AudioPlayerStoppedMask) || playingState == AudioPlayerFinishing);
|
||||
bool wasPlaying = !!_duration;
|
||||
if (!stopped) {
|
||||
showPause = (playingState == AudioPlayerPlaying || playingState == AudioPlayerResuming || playingState == AudioPlayerStarting);
|
||||
}
|
||||
float64 progress = duration ? snap(float64(position) / duration, 0., 1.) : 0.;
|
||||
int32 loaded = duration ? _song.song->size : (_song.song->loader ? _song.song->loader->currentOffset() : 0);
|
||||
float64 loadProgress = (duration || !_song.song->loader) ? 1. : snap(float64(loaded) / qMax(_song.song->size, 1), 0., 1.);
|
||||
if (time != _time || showPause != _showPause) {
|
||||
if (_time != time) {
|
||||
_time = time;
|
||||
_timeWidth = st::linkFont->m.width(_time);
|
||||
}
|
||||
_showPause = showPause;
|
||||
if (duration != _duration || position != _position || loaded != _loaded) {
|
||||
if (!songChanged && ((!stopped && duration && _duration) || (!duration && _loaded != loaded))) {
|
||||
a_progress.start(progress);
|
||||
a_loadProgress.start(loadProgress);
|
||||
_progressAnim.start();
|
||||
} else {
|
||||
a_progress = anim::fvalue(progress, progress);
|
||||
a_loadProgress = anim::fvalue(loadProgress, loadProgress);
|
||||
_progressAnim.stop();
|
||||
}
|
||||
_position = position;
|
||||
_duration = duration;
|
||||
_loaded = loaded;
|
||||
}
|
||||
update();
|
||||
} else if (duration != _duration || position != _position || loaded != _loaded) {
|
||||
if (!songChanged && ((!stopped && duration && _duration) || (!duration && _loaded != loaded))) {
|
||||
a_progress.start(progress);
|
||||
a_loadProgress.start(loadProgress);
|
||||
_progressAnim.start();
|
||||
} else {
|
||||
a_progress = anim::fvalue(progress, progress);
|
||||
a_loadProgress = anim::fvalue(loadProgress, loadProgress);
|
||||
_progressAnim.stop();
|
||||
}
|
||||
_position = position;
|
||||
_duration = duration;
|
||||
_loaded = loaded;
|
||||
}
|
||||
|
||||
if (wasPlaying && playingState == AudioPlayerStoppedAtEnd) {
|
||||
const History::MediaOverview *o = _history ? &_history->_overview[OverviewAudioDocuments] : 0;
|
||||
if (audioPlayer() && o && _index >= 0 && _index < o->size() - 1) {
|
||||
startPlay(o->at(_index + 1));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "audio.h"
|
||||
|
||||
class PlayerWidget : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
PlayerWidget(QWidget *parent);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
void mouseMoveEvent(QMouseEvent *e);
|
||||
void leaveEvent(QEvent *e);
|
||||
void mouseReleaseEvent(QMouseEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
|
||||
bool progressStep(float64 ms);
|
||||
bool stateStep(float64 ms);
|
||||
|
||||
void updateState(SongMsgId playing, AudioPlayerState playingState, int64 playingPosition, int64 playingDuration, int32 playingFrequency);
|
||||
void updateState();
|
||||
void clearSelection();
|
||||
|
||||
void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type);
|
||||
|
||||
bool seekingSong(const SongMsgId &song) const;
|
||||
|
||||
private:
|
||||
|
||||
enum OverState {
|
||||
OverNone = 0,
|
||||
OverPrev,
|
||||
OverPlay,
|
||||
OverNext,
|
||||
OverClose,
|
||||
OverVolume,
|
||||
OverFull,
|
||||
OverPlayback,
|
||||
|
||||
OverStateCount
|
||||
};
|
||||
void updateDownTime();
|
||||
void updateOverState(OverState newState);
|
||||
void updateOverRect(OverState state);
|
||||
|
||||
void updateControls();
|
||||
void findCurrent();
|
||||
|
||||
void startPlay(MsgId msgId);
|
||||
|
||||
QPoint _lastMousePos;
|
||||
void updateSelected();
|
||||
|
||||
bool _prevAvailable, _nextAvailable, _fullAvailable;
|
||||
OverState _over, _down;
|
||||
int32 _downCoord;
|
||||
int64 _downDuration;
|
||||
int32 _downFrequency;
|
||||
float64 _downProgress;
|
||||
|
||||
float64 _stateHovers[OverStateCount];
|
||||
typedef QMap<int32, uint64> StateAnimations;
|
||||
StateAnimations _stateAnimations;
|
||||
Animation _stateAnim;
|
||||
|
||||
SongMsgId _song;
|
||||
int32 _index;
|
||||
History *_history;
|
||||
QRect _playRect, _prevRect, _nextRect, _playbackRect;
|
||||
QRect _closeRect, _volumeRect, _fullRect, _infoRect;
|
||||
int32 _timeWidth;
|
||||
QString _time;
|
||||
Text _name;
|
||||
bool _showPause;
|
||||
int64 _position, _duration;
|
||||
int32 _loaded;
|
||||
|
||||
anim::fvalue a_progress, a_loadProgress;
|
||||
Animation _progressAnim;
|
||||
|
||||
};
|
|
@ -579,6 +579,8 @@ void ProfileInner::paintEvent(QPaintEvent *e) {
|
|||
p.setPen(st::black->p);
|
||||
int oneState = 0; // < 0 - loading, 0 - no media, > 0 - link shown
|
||||
for (int i = 0; i < OverviewCount; ++i) {
|
||||
if (i == OverviewAudioDocuments) continue;
|
||||
|
||||
int32 count = (_hist->_overviewCount[i] > 0) ? _hist->_overviewCount[i] : (_hist->_overviewCount[i] == 0 ? _hist->_overview[i].size() : -1);
|
||||
if (count < 0) {
|
||||
if (!oneState) oneState = count;
|
||||
|
@ -859,6 +861,8 @@ void ProfileInner::resizeEvent(QResizeEvent *e) {
|
|||
_mediaShowAll.move(_left + _width - _mediaShowAll.width(), top);
|
||||
int wasCount = 0; // < 0 - loading, 0 - no media, > 0 - link shown
|
||||
for (int i = 0; i < OverviewCount; ++i) {
|
||||
if (i == OverviewAudioDocuments) continue;
|
||||
|
||||
if (_allMediaTypes) {
|
||||
int32 count = (_hist->_overviewCount[i] > 0) ? _hist->_overviewCount[i] : (_hist->_overviewCount[i] == 0 ? _hist->_overview[i].size() : -1);
|
||||
if (count > 0) {
|
||||
|
@ -957,7 +961,7 @@ void ProfileInner::updateNotifySettings() {
|
|||
_enableNotifications.setChecked(_peer->notify == EmptyNotifySettings || _peer->notify == UnknownNotifySettings || _peer->notify->mute < unixtime());
|
||||
}
|
||||
|
||||
void ProfileInner::mediaOverviewUpdated(PeerData *peer) {
|
||||
void ProfileInner::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
|
||||
if (peer == _peer) {
|
||||
resizeEvent(0);
|
||||
showAll();
|
||||
|
@ -1029,6 +1033,8 @@ void ProfileInner::showAll() {
|
|||
// shared media
|
||||
bool first = false, wasCount = false, manyCounts = false;
|
||||
for (int i = 0; i < OverviewCount; ++i) {
|
||||
if (i == OverviewAudioDocuments) continue;
|
||||
|
||||
int32 count = (_hist->_overviewCount[i] > 0) ? _hist->_overviewCount[i] : (_hist->_overviewCount[i] == 0 ? _hist->_overview[i].size() : -1);
|
||||
if (count > 0) {
|
||||
if (wasCount) {
|
||||
|
@ -1136,8 +1142,13 @@ void ProfileWidget::onScroll() {
|
|||
}
|
||||
|
||||
void ProfileWidget::resizeEvent(QResizeEvent *e) {
|
||||
int32 addToY = App::main() ? App::main()->contentScrollAddToY() : 0;
|
||||
int32 newScrollY = _scroll.scrollTop() + addToY;
|
||||
_scroll.resize(size());
|
||||
_inner.resize(width(), _inner.height());
|
||||
if (addToY) {
|
||||
_scroll.scrollToY(newScrollY);
|
||||
}
|
||||
}
|
||||
|
||||
void ProfileWidget::mousePressEvent(QMouseEvent *e) {
|
||||
|
@ -1176,6 +1187,13 @@ void ProfileWidget::paintTopBar(QPainter &p, float64 over, int32 decreaseWidth)
|
|||
}
|
||||
}
|
||||
|
||||
void ProfileWidget::topBarShadowParams(int32 &x, float64 &o) {
|
||||
if (animating() && a_coord.current() >= 0) {
|
||||
x = a_coord.current();
|
||||
o = a_alpha.current();
|
||||
}
|
||||
}
|
||||
|
||||
void ProfileWidget::topBarClick() {
|
||||
App::main()->showBackFromStack();
|
||||
}
|
||||
|
@ -1253,8 +1271,8 @@ void ProfileWidget::updateNotifySettings() {
|
|||
_inner.updateNotifySettings();
|
||||
}
|
||||
|
||||
void ProfileWidget::mediaOverviewUpdated(PeerData *peer) {
|
||||
_inner.mediaOverviewUpdated(peer);
|
||||
void ProfileWidget::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
|
||||
_inner.mediaOverviewUpdated(peer, type);
|
||||
}
|
||||
|
||||
void ProfileWidget::clear() {
|
||||
|
|
|
@ -53,7 +53,7 @@ public:
|
|||
void loadProfilePhotos(int32 yFrom);
|
||||
|
||||
void updateNotifySettings();
|
||||
void mediaOverviewUpdated(PeerData *peer);
|
||||
void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type);
|
||||
|
||||
~ProfileInner();
|
||||
|
||||
|
@ -187,6 +187,7 @@ public:
|
|||
void dropEvent(QDropEvent *e);
|
||||
|
||||
void paintTopBar(QPainter &p, float64 over, int32 decreaseWidth);
|
||||
void topBarShadowParams(int32 &x, float64 &o);
|
||||
void topBarClick();
|
||||
|
||||
PeerData *peer() const;
|
||||
|
@ -200,7 +201,7 @@ public:
|
|||
void updateOnlineDisplayTimer();
|
||||
|
||||
void updateNotifySettings();
|
||||
void mediaOverviewUpdated(PeerData *peer);
|
||||
void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type);
|
||||
|
||||
void clear();
|
||||
~ProfileWidget();
|
||||
|
|
|
@ -156,6 +156,8 @@ int gNotifyDefaultDelay = 1500;
|
|||
|
||||
int gOtherOnline = 0;
|
||||
|
||||
float64 gSongVolume = 0.9;
|
||||
|
||||
void settingsParseArgs(int argc, char *argv[]) {
|
||||
#ifdef Q_OS_MAC
|
||||
gCustomNotifies = (QSysInfo::macVersion() < QSysInfo::MV_10_8);
|
||||
|
|
|
@ -304,4 +304,6 @@ DeclareSetting(int, NotifyDefaultDelay);
|
|||
|
||||
DeclareSetting(int, OtherOnline);
|
||||
|
||||
DeclareSetting(float64, SongVolume);
|
||||
|
||||
void settingsParseArgs(int argc, char *argv[]);
|
||||
|
|
|
@ -448,7 +448,7 @@ void AudioOpenLink::onClick(Qt::MouseButton button) const {
|
|||
AudioMsgId playing;
|
||||
AudioPlayerState playingState = AudioPlayerStopped;
|
||||
audioPlayer()->currentState(&playing, &playingState);
|
||||
if (playing.msgId == App::hoveredLinkItem()->id && playingState != AudioPlayerStopped) {
|
||||
if (playing.msgId == App::hoveredLinkItem()->id && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
|
||||
audioPlayer()->pauseresume(OverviewAudios);
|
||||
} else {
|
||||
audioPlayer()->play(AudioMsgId(data, App::hoveredLinkItem()->id));
|
||||
|
@ -545,9 +545,8 @@ QString AudioData::already(bool check) {
|
|||
return location.name;
|
||||
}
|
||||
|
||||
void DocumentOpenLink::onClick(Qt::MouseButton button) const {
|
||||
DocumentData *data = document();
|
||||
if (!data->date || button != Qt::LeftButton) return;
|
||||
void DocumentOpenLink::doOpen(DocumentData *data) {
|
||||
if (!data->date) return;
|
||||
|
||||
bool play = data->song() && App::hoveredLinkItem() && audioPlayer();
|
||||
QString already = data->already(true);
|
||||
|
@ -556,10 +555,12 @@ void DocumentOpenLink::onClick(Qt::MouseButton button) const {
|
|||
SongMsgId playing;
|
||||
AudioPlayerState playingState = AudioPlayerStopped;
|
||||
audioPlayer()->currentState(&playing, &playingState);
|
||||
if (playing.msgId == App::hoveredLinkItem()->id && playingState != AudioPlayerStopped) {
|
||||
if (playing.msgId == App::hoveredLinkItem()->id && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) {
|
||||
audioPlayer()->pauseresume(OverviewDocuments);
|
||||
} else {
|
||||
audioPlayer()->play(SongMsgId(data, App::hoveredLinkItem()->id));
|
||||
SongMsgId song(data, App::hoveredLinkItem()->id);
|
||||
audioPlayer()->play(song);
|
||||
if (App::main()) App::main()->documentPlayProgress(song);
|
||||
}
|
||||
} else if (data->size < MediaViewImageSizeLimit) {
|
||||
QImageReader reader(already);
|
||||
|
@ -604,6 +605,11 @@ void DocumentOpenLink::onClick(Qt::MouseButton button) const {
|
|||
}
|
||||
}
|
||||
|
||||
void DocumentOpenLink::onClick(Qt::MouseButton button) const {
|
||||
if (button != Qt::LeftButton) return;
|
||||
doOpen(document());
|
||||
}
|
||||
|
||||
void DocumentSaveLink::doSave(DocumentData *data, bool forceSavingAs) {
|
||||
if (!data->date) return;
|
||||
|
||||
|
|
|
@ -627,6 +627,7 @@ class DocumentOpenLink : public DocumentLink {
|
|||
public:
|
||||
DocumentOpenLink(DocumentData *document) : DocumentLink(document) {
|
||||
}
|
||||
static void doOpen(DocumentData *document);
|
||||
void onClick(Qt::MouseButton button) const;
|
||||
};
|
||||
|
||||
|
|
|
@ -273,6 +273,7 @@ enum DataBlockId {
|
|||
dbiRecentStickers = 0x26,
|
||||
dbiDcOption = 0x27,
|
||||
dbiTryIPv6 = 0x28,
|
||||
dbiSongVolume = 0x29,
|
||||
|
||||
dbiEncryptedWithSalt = 333,
|
||||
dbiEncrypted = 444,
|
||||
|
|
|
@ -1712,10 +1712,10 @@ void Window::sendPaths() {
|
|||
}
|
||||
}
|
||||
|
||||
void Window::mediaOverviewUpdated(PeerData *peer) {
|
||||
if (main) main->mediaOverviewUpdated(peer);
|
||||
void Window::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
|
||||
if (main) main->mediaOverviewUpdated(peer, type);
|
||||
if (!_mediaView || _mediaView->isHidden()) return;
|
||||
_mediaView->mediaOverviewUpdated(peer);
|
||||
_mediaView->mediaOverviewUpdated(peer, type);
|
||||
}
|
||||
|
||||
void Window::documentUpdated(DocumentData *doc) {
|
||||
|
|
|
@ -226,7 +226,7 @@ public:
|
|||
|
||||
void sendPaths();
|
||||
|
||||
void mediaOverviewUpdated(PeerData *peer);
|
||||
void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type);
|
||||
void documentUpdated(DocumentData *doc);
|
||||
void changingMsgId(HistoryItem *row, MsgId newId);
|
||||
|
||||
|
|
|
@ -352,6 +352,10 @@
|
|||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Debug\moc_playerwidget.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Debug\moc_profilewidget.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
|
@ -618,6 +622,10 @@
|
|||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Deploy\moc_playerwidget.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Deploy\moc_profilewidget.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
|
@ -909,6 +917,10 @@
|
|||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Release\moc_playerwidget.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Release\moc_profilewidget.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
|
@ -1044,6 +1056,7 @@
|
|||
<ClCompile Include="SourceFiles\mtproto\mtpSession.cpp" />
|
||||
<ClCompile Include="SourceFiles\overviewwidget.cpp" />
|
||||
<ClCompile Include="SourceFiles\passcodewidget.cpp" />
|
||||
<ClCompile Include="SourceFiles\playerwidget.cpp" />
|
||||
<ClCompile Include="SourceFiles\profilewidget.cpp" />
|
||||
<ClCompile Include="SourceFiles\pspecific_linux.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
|
@ -1993,6 +2006,20 @@
|
|||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DAL_LIBTYPE_STATIC -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\..\..\Libraries\libogg-1.3.2\include" "-I.\..\..\Libraries\opus\include" "-I.\..\..\Libraries\opusfile\include" "-I.\..\..\Libraries\mpg123-1.22.1\ports\MSVC++" "-I.\..\..\Libraries\mpg123-1.22.1\src\libmpg123" "-I.\..\..\Libraries\faad2-2.7\include" "-I.\..\..\Libraries\faad2-2.7\common\mp4ff" "-I.\..\..\Libraries\ffmpeg-2.6.3" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.4.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.4.0\QtGui" "-fstdafx.h" "-f../../SourceFiles/passcodewidget.h"</Command>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="SourceFiles\playerwidget.h">
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">Moc%27ing playerwidget.h...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/playerwidget.h" -DAL_LIBTYPE_STATIC -DCUSTOM_API_ID -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\..\..\Libraries\ffmpeg-2.6.3" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.4.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.4.0\QtGui"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing playerwidget.h...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/playerwidget.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\..\..\Libraries\ffmpeg-2.6.3" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.4.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.4.0\QtGui"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing playerwidget.h...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/playerwidget.h" -DAL_LIBTYPE_STATIC -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\..\..\Libraries\libogg-1.3.2\include" "-I.\..\..\Libraries\opus\include" "-I.\..\..\Libraries\opusfile\include" "-I.\..\..\Libraries\mpg123-1.22.1\ports\MSVC++" "-I.\..\..\Libraries\mpg123-1.22.1\src\libmpg123" "-I.\..\..\Libraries\faad2-2.7\include" "-I.\..\..\Libraries\faad2-2.7\common\mp4ff" "-I.\..\..\Libraries\ffmpeg-2.6.3" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.4.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.4.0\QtGui"</Command>
|
||||
</CustomBuild>
|
||||
<ClInclude Include="SourceFiles\pspecific.h" />
|
||||
<CustomBuild Include="SourceFiles\pspecific_linux.h">
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
|
|
|
@ -903,6 +903,18 @@
|
|||
<ClCompile Include="GeneratedFiles\Release\moc_autoupdater.cpp">
|
||||
<Filter>Generated Files\Release</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SourceFiles\playerwidget.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Deploy\moc_playerwidget.cpp">
|
||||
<Filter>Generated Files\Deploy</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Debug\moc_playerwidget.cpp">
|
||||
<Filter>Generated Files\Debug</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Release\moc_playerwidget.cpp">
|
||||
<Filter>Generated Files\Release</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="SourceFiles\stdafx.h">
|
||||
|
@ -1198,6 +1210,9 @@
|
|||
<CustomBuild Include="SourceFiles\autoupdater.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="SourceFiles\playerwidget.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="SourceFiles\art\icon256.ico" />
|
||||
|
|
Loading…
Reference in New Issue