mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Play ringtones on click in select box.
This commit is contained in:
parent
f5164fe3e4
commit
d35b8f82a3
7 changed files with 107 additions and 23 deletions
|
@ -11,7 +11,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "base/random.h"
|
#include "base/random.h"
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
|
#include "data/data_document_media.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
|
#include "data/notify/data_notify_settings.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "storage/file_upload.h"
|
#include "storage/file_upload.h"
|
||||||
#include "storage/localimageloader.h"
|
#include "storage/localimageloader.h"
|
||||||
|
@ -83,7 +85,7 @@ void Ringtones::upload(
|
||||||
filemime,
|
filemime,
|
||||||
content);
|
content);
|
||||||
|
|
||||||
const auto uploadedData = UploadedData{ filename, filemime };
|
const auto uploadedData = UploadedData{ filename, filemime, content };
|
||||||
const auto fakeId = FullMsgId(
|
const auto fakeId = FullMsgId(
|
||||||
_session->userPeerId(),
|
_session->userPeerId(),
|
||||||
_session->data().nextLocalMessageId());
|
_session->data().nextLocalMessageId());
|
||||||
|
@ -111,9 +113,12 @@ void Ringtones::ready(const FullMsgId &msgId, const MTPInputFile &file) {
|
||||||
file,
|
file,
|
||||||
MTP_string(uploadedData.filename),
|
MTP_string(uploadedData.filename),
|
||||||
MTP_string(uploadedData.filemime)
|
MTP_string(uploadedData.filemime)
|
||||||
)).done([=](const MTPDocument &result) {
|
)).done([=, content = uploadedData.content](const MTPDocument &result) {
|
||||||
const auto document = _session->data().processDocument(result);
|
const auto document = _session->data().processDocument(result);
|
||||||
_list.documents.insert(_list.documents.begin(), document->id);
|
_list.documents.insert(_list.documents.begin(), document->id);
|
||||||
|
const auto media = document->createMediaView();
|
||||||
|
media->setBytes(content);
|
||||||
|
document->owner().notifySettings().cacheSound(document);
|
||||||
_uploadDones.fire_copy(document->id);
|
_uploadDones.fire_copy(document->id);
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
_uploadFails.fire_copy(error.type());
|
_uploadFails.fire_copy(error.type());
|
||||||
|
@ -134,6 +139,7 @@ void Ringtones::requestList() {
|
||||||
_list.documents.reserve(data.vringtones().v.size());
|
_list.documents.reserve(data.vringtones().v.size());
|
||||||
for (const auto &d : data.vringtones().v) {
|
for (const auto &d : data.vringtones().v) {
|
||||||
const auto document = _session->data().processDocument(d);
|
const auto document = _session->data().processDocument(d);
|
||||||
|
document->forceToCache(true);
|
||||||
_list.documents.emplace_back(document->id);
|
_list.documents.emplace_back(document->id);
|
||||||
}
|
}
|
||||||
requestList();
|
requestList();
|
||||||
|
|
|
@ -42,6 +42,7 @@ private:
|
||||||
struct UploadedData {
|
struct UploadedData {
|
||||||
QString filename;
|
QString filename;
|
||||||
QString filemime;
|
QString filemime;
|
||||||
|
QByteArray content;
|
||||||
};
|
};
|
||||||
void ready(const FullMsgId &msgId, const MTPInputFile &file);
|
void ready(const FullMsgId &msgId, const MTPInputFile &file);
|
||||||
|
|
||||||
|
|
|
@ -13,15 +13,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "base/call_delayed.h"
|
#include "base/call_delayed.h"
|
||||||
#include "base/event_filter.h"
|
#include "base/event_filter.h"
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
|
#include "base/timer_rpl.h"
|
||||||
#include "core/file_utilities.h"
|
#include "core/file_utilities.h"
|
||||||
#include "core/mime_type.h"
|
#include "core/mime_type.h"
|
||||||
|
#include "core/application.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
|
#include "data/data_document_media.h"
|
||||||
#include "data/data_document_resolver.h"
|
#include "data/data_document_resolver.h"
|
||||||
#include "data/data_peer.h"
|
#include "data/data_peer.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/notify/data_notify_settings.h"
|
#include "data/notify/data_notify_settings.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
|
#include "media/audio/media_audio.h"
|
||||||
#include "settings/settings_common.h"
|
#include "settings/settings_common.h"
|
||||||
#include "ui/boxes/confirm_box.h"
|
#include "ui/boxes/confirm_box.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
|
@ -40,6 +44,50 @@ namespace {
|
||||||
|
|
||||||
constexpr auto kDefaultValue = -1;
|
constexpr auto kDefaultValue = -1;
|
||||||
constexpr auto kNoSoundValue = -2;
|
constexpr auto kNoSoundValue = -2;
|
||||||
|
constexpr auto kNoDetachTimeout = crl::time(250);
|
||||||
|
|
||||||
|
class AudioCreator final {
|
||||||
|
public:
|
||||||
|
AudioCreator();
|
||||||
|
AudioCreator(AudioCreator &&other);
|
||||||
|
AudioCreator &operator=(AudioCreator &&other);
|
||||||
|
~AudioCreator();
|
||||||
|
|
||||||
|
private:
|
||||||
|
rpl::lifetime _lifetime;
|
||||||
|
bool _attached = false;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
AudioCreator::AudioCreator()
|
||||||
|
: _attached(true) {
|
||||||
|
crl::async([] {
|
||||||
|
QMutexLocker lock(Media::Player::internal::audioPlayerMutex());
|
||||||
|
Media::Audio::AttachToDevice();
|
||||||
|
});
|
||||||
|
base::timer_each(
|
||||||
|
kNoDetachTimeout
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
Media::Audio::StopDetachIfNotUsedSafe();
|
||||||
|
}, _lifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioCreator::AudioCreator(AudioCreator &&other)
|
||||||
|
: _lifetime(base::take(other._lifetime))
|
||||||
|
, _attached(base::take(other._attached)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioCreator &AudioCreator::operator=(AudioCreator &&other) {
|
||||||
|
_lifetime = base::take(other._lifetime);
|
||||||
|
_attached = base::take(other._attached);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioCreator::~AudioCreator() {
|
||||||
|
if (_attached) {
|
||||||
|
Media::Audio::ScheduleDetachIfNotUsedSafe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -79,8 +127,9 @@ void RingtonesBox(
|
||||||
padding.setTop(padding.bottom());
|
padding.setTop(padding.bottom());
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
|
AudioCreator creator;
|
||||||
std::shared_ptr<Ui::RadiobuttonGroup> group;
|
std::shared_ptr<Ui::RadiobuttonGroup> group;
|
||||||
std::vector<DocumentId> documentIds;
|
std::vector<std::shared_ptr<Data::DocumentMedia>> medias;
|
||||||
Data::NotifySound chosen;
|
Data::NotifySound chosen;
|
||||||
base::unique_qptr<Ui::PopupMenu> menu;
|
base::unique_qptr<Ui::PopupMenu> menu;
|
||||||
QPointer<Ui::Radiobutton> defaultButton;
|
QPointer<Ui::Radiobutton> defaultButton;
|
||||||
|
@ -113,6 +162,9 @@ void RingtonesBox(
|
||||||
}
|
}
|
||||||
if (value == kDefaultValue) {
|
if (value == kDefaultValue) {
|
||||||
state->defaultButton = button;
|
state->defaultButton = button;
|
||||||
|
button->setClickedCallback([=] {
|
||||||
|
Core::App().notifications().playSound(session, 0);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (value < 0) {
|
if (value < 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -120,6 +172,14 @@ void RingtonesBox(
|
||||||
while (state->buttons.size() <= value) {
|
while (state->buttons.size() <= value) {
|
||||||
state->buttons.push_back(nullptr);
|
state->buttons.push_back(nullptr);
|
||||||
}
|
}
|
||||||
|
button->setClickedCallback([=] {
|
||||||
|
const auto media = state->medias[value].get();
|
||||||
|
if (media->loaded()) {
|
||||||
|
Core::App().notifications().playSound(
|
||||||
|
session,
|
||||||
|
media->owner()->id);
|
||||||
|
}
|
||||||
|
});
|
||||||
base::install_event_filter(button, [=](not_null<QEvent*> e) {
|
base::install_event_filter(button, [=](not_null<QEvent*> e) {
|
||||||
if (e->type() != QEvent::ContextMenu || state->menu) {
|
if (e->type() != QEvent::ContextMenu || state->menu) {
|
||||||
return base::EventFilterResult::Continue;
|
return base::EventFilterResult::Continue;
|
||||||
|
@ -128,7 +188,7 @@ void RingtonesBox(
|
||||||
button,
|
button,
|
||||||
st::popupMenuWithIcons);
|
st::popupMenuWithIcons);
|
||||||
auto callback = [=] {
|
auto callback = [=] {
|
||||||
const auto id = state->documentIds[value];
|
const auto id = state->medias[value]->owner()->id;
|
||||||
session->api().ringtones().remove(id);
|
session->api().ringtones().remove(id);
|
||||||
};
|
};
|
||||||
state->menu->addAction(
|
state->menu->addAction(
|
||||||
|
@ -172,7 +232,7 @@ void RingtonesBox(
|
||||||
object_ptr<Ui::VerticalLayout>(container));
|
object_ptr<Ui::VerticalLayout>(container));
|
||||||
|
|
||||||
const auto rebuild = [=] {
|
const auto rebuild = [=] {
|
||||||
state->documentIds.clear();
|
const auto old = base::take(state->medias);
|
||||||
auto value = 0;
|
auto value = 0;
|
||||||
while (custom->count()) {
|
while (custom->count()) {
|
||||||
delete custom->widgetAt(0);
|
delete custom->widgetAt(0);
|
||||||
|
@ -183,7 +243,8 @@ void RingtonesBox(
|
||||||
const auto document = session->data().document(id);
|
const auto document = session->data().document(id);
|
||||||
const auto text = ExtractRingtoneName(document);
|
const auto text = ExtractRingtoneName(document);
|
||||||
addToGroup(custom, value++, text, chosen);
|
addToGroup(custom, value++, text, chosen);
|
||||||
state->documentIds.push_back(id);
|
state->medias.push_back(document->createMediaView());
|
||||||
|
document->owner().notifySettings().cacheSound(document);
|
||||||
}
|
}
|
||||||
|
|
||||||
custom->resizeToWidth(container->width());
|
custom->resizeToWidth(container->width());
|
||||||
|
@ -260,7 +321,7 @@ void RingtonesBox(
|
||||||
? Data::NotifySound()
|
? Data::NotifySound()
|
||||||
: (value == kNoSoundValue)
|
: (value == kNoSoundValue)
|
||||||
? Data::NotifySound{ .none = true }
|
? Data::NotifySound{ .none = true }
|
||||||
: Data::NotifySound{ .id = state->documentIds[value] };
|
: Data::NotifySound{ .id = state->medias[value]->owner()->id };
|
||||||
save(sound);
|
save(sound);
|
||||||
box->closeBox();
|
box->closeBox();
|
||||||
});
|
});
|
||||||
|
|
|
@ -163,24 +163,16 @@ void NotifySettings::updateLocal(not_null<PeerData*> peer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const auto sound = peer->notifySound(); sound && sound->id) {
|
if (const auto sound = peer->notifySound(); sound && sound->id) {
|
||||||
const auto cache = [=](DocumentId id) {
|
|
||||||
if (const auto document = _owner->document(id)) {
|
|
||||||
const auto view = document->createMediaView();
|
|
||||||
_ringtones.views.emplace(id, view);
|
|
||||||
document->forceToCache(true);
|
|
||||||
document->save(Data::FileOriginRingtones(), QString());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (const auto doc = _owner->document(sound->id); !doc->isNull()) {
|
if (const auto doc = _owner->document(sound->id); !doc->isNull()) {
|
||||||
cache(sound->id);
|
cacheSound(doc);
|
||||||
} else {
|
} else {
|
||||||
_ringtones.pendingIds.push_back(sound->id);
|
_ringtones.pendingIds.push_back(sound->id);
|
||||||
if (!_ringtones.pendingLifetime) {
|
if (!_ringtones.pendingLifetime) {
|
||||||
// Not requested yet.
|
// Not requested yet.
|
||||||
_owner->session().api().ringtones().listUpdates(
|
_owner->session().api().ringtones().listUpdates(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
for (const auto &id : base::take(_ringtones.pendingIds)) {
|
for (const auto id : base::take(_ringtones.pendingIds)) {
|
||||||
cache(id);
|
cacheSound(id);
|
||||||
}
|
}
|
||||||
_ringtones.pendingLifetime.destroy();
|
_ringtones.pendingLifetime.destroy();
|
||||||
}, _ringtones.pendingLifetime);
|
}, _ringtones.pendingLifetime);
|
||||||
|
@ -190,6 +182,20 @@ void NotifySettings::updateLocal(not_null<PeerData*> peer) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NotifySettings::cacheSound(DocumentId id) {
|
||||||
|
cacheSound(_owner->document(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotifySettings::cacheSound(not_null<DocumentData*> document) {
|
||||||
|
if (document->isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto view = document->createMediaView();
|
||||||
|
_ringtones.views.emplace(document->id, view);
|
||||||
|
document->forceToCache(true);
|
||||||
|
document->save(Data::FileOriginRingtones(), QString());
|
||||||
|
}
|
||||||
|
|
||||||
void NotifySettings::updateLocal(DefaultNotify type) {
|
void NotifySettings::updateLocal(DefaultNotify type) {
|
||||||
defaultValue(type).updates.fire({});
|
defaultValue(type).updates.fire({});
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,10 @@ public:
|
||||||
std::optional<NotifySound> sound = std::nullopt);
|
std::optional<NotifySound> sound = std::nullopt);
|
||||||
void resetToDefault(not_null<PeerData*> peer);
|
void resetToDefault(not_null<PeerData*> peer);
|
||||||
|
|
||||||
std::shared_ptr<DocumentMedia> lookupRingtone(DocumentId id) const;
|
void cacheSound(DocumentId id);
|
||||||
|
void cacheSound(not_null<DocumentData*> document);
|
||||||
|
[[nodiscard]] std::shared_ptr<DocumentMedia> lookupRingtone(
|
||||||
|
DocumentId id) const;
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<> defaultUpdates(DefaultNotify type) const;
|
[[nodiscard]] rpl::producer<> defaultUpdates(DefaultNotify type) const;
|
||||||
[[nodiscard]] rpl::producer<> defaultUpdates(
|
[[nodiscard]] rpl::producer<> defaultUpdates(
|
||||||
|
|
|
@ -510,7 +510,7 @@ void System::showNext() {
|
||||||
}
|
}
|
||||||
if (settings.soundNotify() && !_manager->skipAudio()) {
|
if (settings.soundNotify() && !_manager->skipAudio()) {
|
||||||
const auto track = lookupSound(
|
const auto track = lookupSound(
|
||||||
alertPeer,
|
&alertPeer->owner(),
|
||||||
alertPeer->owner().notifySettings().sound(alertPeer).id);
|
alertPeer->owner().notifySettings().sound(alertPeer).id);
|
||||||
track->playOnce();
|
track->playOnce();
|
||||||
Media::Player::mixer()->suppressAll(track->getLengthMs());
|
Media::Player::mixer()->suppressAll(track->getLengthMs());
|
||||||
|
@ -699,7 +699,7 @@ void System::showNext() {
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<Media::Audio::Track*> System::lookupSound(
|
not_null<Media::Audio::Track*> System::lookupSound(
|
||||||
not_null<PeerData*> peer,
|
not_null<Data::Session*> owner,
|
||||||
DocumentId id) {
|
DocumentId id) {
|
||||||
if (!id) {
|
if (!id) {
|
||||||
ensureSoundCreated();
|
ensureSoundCreated();
|
||||||
|
@ -709,7 +709,7 @@ not_null<Media::Audio::Track*> System::lookupSound(
|
||||||
if (i != end(_customSoundTracks)) {
|
if (i != end(_customSoundTracks)) {
|
||||||
return i->second.get();
|
return i->second.get();
|
||||||
}
|
}
|
||||||
const auto ¬ifySettings = peer->owner().notifySettings();
|
const auto ¬ifySettings = owner->notifySettings();
|
||||||
const auto custom = notifySettings.lookupRingtone(id);
|
const auto custom = notifySettings.lookupRingtone(id);
|
||||||
if (custom && !custom->bytes().isEmpty()) {
|
if (custom && !custom->bytes().isEmpty()) {
|
||||||
const auto j = _customSoundTracks.emplace(
|
const auto j = _customSoundTracks.emplace(
|
||||||
|
@ -747,6 +747,10 @@ void System::notifySettingsChanged(ChangeType type) {
|
||||||
return _settingsChanged.fire(std::move(type));
|
return _settingsChanged.fire(std::move(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void System::playSound(not_null<Main::Session*> session, DocumentId id) {
|
||||||
|
lookupSound(&session->data(), id)->playOnce();
|
||||||
|
}
|
||||||
|
|
||||||
Manager::DisplayOptions Manager::getNotificationOptions(
|
Manager::DisplayOptions Manager::getNotificationOptions(
|
||||||
HistoryItem *item,
|
HistoryItem *item,
|
||||||
ItemNotificationType type) const {
|
ItemNotificationType type) const {
|
||||||
|
|
|
@ -15,6 +15,7 @@ struct ItemNotification;
|
||||||
enum class ItemNotificationType;
|
enum class ItemNotificationType;
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
class Session;
|
||||||
class CloudImageView;
|
class CloudImageView;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
|
@ -99,6 +100,8 @@ public:
|
||||||
[[nodiscard]] rpl::producer<ChangeType> settingsChanged() const;
|
[[nodiscard]] rpl::producer<ChangeType> settingsChanged() const;
|
||||||
void notifySettingsChanged(ChangeType type);
|
void notifySettingsChanged(ChangeType type);
|
||||||
|
|
||||||
|
void playSound(not_null<Main::Session*> session, DocumentId id);
|
||||||
|
|
||||||
[[nodiscard]] rpl::lifetime &lifetime() {
|
[[nodiscard]] rpl::lifetime &lifetime() {
|
||||||
return _lifetime;
|
return _lifetime;
|
||||||
}
|
}
|
||||||
|
@ -159,7 +162,7 @@ private:
|
||||||
void showGrouped();
|
void showGrouped();
|
||||||
void ensureSoundCreated();
|
void ensureSoundCreated();
|
||||||
[[nodiscard]] not_null<Media::Audio::Track*> lookupSound(
|
[[nodiscard]] not_null<Media::Audio::Track*> lookupSound(
|
||||||
not_null<PeerData*> peer,
|
not_null<Data::Session*> owner,
|
||||||
DocumentId id);
|
DocumentId id);
|
||||||
|
|
||||||
base::flat_map<
|
base::flat_map<
|
||||||
|
|
Loading…
Add table
Reference in a new issue