mirror of
https://github.com/vale981/tdesktop
synced 2025-03-09 04:26:42 -04:00

That way audio files and voice/video messages will play in context (one after another with ability to go to next or previous in player) almost always, no matter at what part of message history we are.
217 lines
5.6 KiB
C++
217 lines
5.6 KiB
C++
/*
|
|
This file is part of Telegram Desktop,
|
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
|
|
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
It is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
In addition, as a special exception, the copyright holders give permission
|
|
to link the code of portions of this program with the OpenSSL library.
|
|
|
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
|
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|
*/
|
|
#pragma once
|
|
|
|
#include "data/data_shared_media.h"
|
|
|
|
class AudioMsgId;
|
|
|
|
namespace Media {
|
|
namespace Player {
|
|
|
|
void start();
|
|
void finish();
|
|
|
|
class Instance;
|
|
Instance *instance();
|
|
|
|
struct TrackState;
|
|
|
|
class Instance : private base::Subscriber {
|
|
public:
|
|
void play(AudioMsgId::Type type);
|
|
void pause(AudioMsgId::Type type);
|
|
void stop(AudioMsgId::Type type);
|
|
void playPause(AudioMsgId::Type type);
|
|
bool next(AudioMsgId::Type type);
|
|
bool previous(AudioMsgId::Type type);
|
|
|
|
AudioMsgId::Type getActiveType() const;
|
|
|
|
void play() {
|
|
play(getActiveType());
|
|
}
|
|
void pause() {
|
|
pause(getActiveType());
|
|
}
|
|
void stop() {
|
|
stop(getActiveType());
|
|
}
|
|
void playPause() {
|
|
playPause(getActiveType());
|
|
}
|
|
bool next() {
|
|
return next(getActiveType());
|
|
}
|
|
bool previous() {
|
|
return previous(getActiveType());
|
|
}
|
|
|
|
void playPauseCancelClicked(AudioMsgId::Type type);
|
|
|
|
void play(const AudioMsgId &audioId);
|
|
AudioMsgId current(AudioMsgId::Type type) const {
|
|
if (auto data = getData(type)) {
|
|
return data->current;
|
|
}
|
|
return AudioMsgId();
|
|
}
|
|
|
|
bool repeatEnabled(AudioMsgId::Type type) const {
|
|
if (auto data = getData(type)) {
|
|
return data->repeatEnabled;
|
|
}
|
|
return false;
|
|
}
|
|
void toggleRepeat(AudioMsgId::Type type) {
|
|
if (auto data = getData(type)) {
|
|
data->repeatEnabled = !data->repeatEnabled;
|
|
_repeatChangedNotifier.notify(type);
|
|
}
|
|
}
|
|
|
|
bool isSeeking(AudioMsgId::Type type) const {
|
|
if (auto data = getData(type)) {
|
|
return (data->seeking == data->current);
|
|
}
|
|
return false;
|
|
}
|
|
void startSeeking(AudioMsgId::Type type);
|
|
void stopSeeking(AudioMsgId::Type type);
|
|
|
|
bool nextAvailable(AudioMsgId::Type type) const;
|
|
bool previousAvailable(AudioMsgId::Type type) const;
|
|
|
|
struct Switch {
|
|
AudioMsgId from;
|
|
FullMsgId to;
|
|
};
|
|
|
|
base::Observable<Switch> &switchToNextNotifier() {
|
|
return _switchToNextNotifier;
|
|
}
|
|
base::Observable<bool> &usePanelPlayer() {
|
|
return _usePanelPlayer;
|
|
}
|
|
base::Observable<bool> &titleButtonOver() {
|
|
return _titleButtonOver;
|
|
}
|
|
base::Observable<bool> &playerWidgetOver() {
|
|
return _playerWidgetOver;
|
|
}
|
|
base::Observable<TrackState> &updatedNotifier() {
|
|
return _updatedNotifier;
|
|
}
|
|
base::Observable<AudioMsgId::Type> &tracksFinishedNotifier() {
|
|
return _tracksFinishedNotifier;
|
|
}
|
|
base::Observable<AudioMsgId::Type> &trackChangedNotifier() {
|
|
return _trackChangedNotifier;
|
|
}
|
|
base::Observable<AudioMsgId::Type> &repeatChangedNotifier() {
|
|
return _repeatChangedNotifier;
|
|
}
|
|
|
|
rpl::producer<> playlistChanges(AudioMsgId::Type type) const;
|
|
|
|
void documentLoadProgress(DocumentData *document);
|
|
|
|
void clear();
|
|
|
|
private:
|
|
Instance();
|
|
friend void start();
|
|
|
|
using SharedMediaType = Storage::SharedMediaType;
|
|
using SliceKey = SparseIdsMergedSlice::Key;
|
|
struct Data {
|
|
Data(AudioMsgId::Type type, SharedMediaType overview)
|
|
: type(type)
|
|
, overview(overview) {
|
|
}
|
|
|
|
AudioMsgId::Type type;
|
|
Storage::SharedMediaType overview;
|
|
AudioMsgId current;
|
|
AudioMsgId seeking;
|
|
base::optional<SparseIdsMergedSlice> playlistSlice;
|
|
base::optional<SliceKey> playlistSliceKey;
|
|
base::optional<SliceKey> playlistRequestedKey;
|
|
base::optional<int> playlistIndex;
|
|
rpl::lifetime playlistLifetime;
|
|
rpl::event_stream<> playlistChanges;
|
|
History *history = nullptr;
|
|
History *migrated = nullptr;
|
|
bool repeatEnabled = false;
|
|
bool isPlaying = false;
|
|
};
|
|
|
|
// Observed notifications.
|
|
void handleSongUpdate(const AudioMsgId &audioId);
|
|
|
|
void setCurrent(const AudioMsgId &audioId);
|
|
void refreshPlaylist(not_null<Data*> data);
|
|
base::optional<SliceKey> playlistKey(not_null<Data*> data) const;
|
|
bool validPlaylist(not_null<Data*> data);
|
|
void validatePlaylist(not_null<Data*> data);
|
|
void playlistUpdated(not_null<Data*> data);
|
|
bool moveInPlaylist(not_null<Data*> data, int delta, bool autonext);
|
|
void preloadNext(not_null<Data*> data);
|
|
HistoryItem *itemByIndex(not_null<Data*> data, int index);
|
|
void handleLogout();
|
|
|
|
template <typename CheckCallback>
|
|
void emitUpdate(AudioMsgId::Type type, CheckCallback check);
|
|
|
|
Data *getData(AudioMsgId::Type type) {
|
|
if (type == AudioMsgId::Type::Song) {
|
|
return &_songData;
|
|
} else if (type == AudioMsgId::Type::Voice) {
|
|
return &_voiceData;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const Data *getData(AudioMsgId::Type type) const {
|
|
if (type == AudioMsgId::Type::Song) {
|
|
return &_songData;
|
|
} else if (type == AudioMsgId::Type::Voice) {
|
|
return &_voiceData;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Data _songData;
|
|
Data _voiceData;
|
|
|
|
base::Observable<Switch> _switchToNextNotifier;
|
|
base::Observable<bool> _usePanelPlayer;
|
|
base::Observable<bool> _titleButtonOver;
|
|
base::Observable<bool> _playerWidgetOver;
|
|
base::Observable<TrackState> _updatedNotifier;
|
|
base::Observable<AudioMsgId::Type> _tracksFinishedNotifier;
|
|
base::Observable<AudioMsgId::Type> _trackChangedNotifier;
|
|
base::Observable<AudioMsgId::Type> _repeatChangedNotifier;
|
|
|
|
};
|
|
|
|
} // namespace Clip
|
|
} // namespace Media
|