mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
feat: support send without sound in ghost mode
This commit is contained in:
@@ -109,7 +109,20 @@ void GhostModeAccountSettings::setUseScheduledMessages(bool val) {
|
|||||||
AyuSettings::save();
|
AyuSettings::save();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GhostModeAccountSettings::setSendWithoutSound(bool val) {
|
bool GhostModeAccountSettings::shouldSendWithoutSound() const {
|
||||||
|
switch (_sendWithoutSound.current()) {
|
||||||
|
case SendWithoutSoundOption::Never:
|
||||||
|
return false;
|
||||||
|
case SendWithoutSoundOption::InGhostMode:
|
||||||
|
return isGhostModeActive();
|
||||||
|
case SendWithoutSoundOption::Always:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Unexpected("Value in GhostModeAccountSettings::shouldSendWithoutSound.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void GhostModeAccountSettings::setSendWithoutSound(
|
||||||
|
SendWithoutSoundOption val) {
|
||||||
if (_sendWithoutSound.current() == val) return;
|
if (_sendWithoutSound.current() == val) return;
|
||||||
_sendWithoutSound = val;
|
_sendWithoutSound = val;
|
||||||
AyuSettings::save();
|
AyuSettings::save();
|
||||||
@@ -195,7 +208,14 @@ void from_json(const nlohmann::json &j, GhostModeAccountSettings &s) {
|
|||||||
s._sendOfflinePacketAfterOnline = j.value("sendOfflinePacketAfterOnline", false);
|
s._sendOfflinePacketAfterOnline = j.value("sendOfflinePacketAfterOnline", false);
|
||||||
s._markReadAfterAction = j.value("markReadAfterAction", true);
|
s._markReadAfterAction = j.value("markReadAfterAction", true);
|
||||||
s._useScheduledMessages = j.value("useScheduledMessages", false);
|
s._useScheduledMessages = j.value("useScheduledMessages", false);
|
||||||
s._sendWithoutSound = j.value("sendWithoutSound", false);
|
const auto sendWithoutSound = j.find("sendWithoutSound");
|
||||||
|
s._sendWithoutSound = (sendWithoutSound == j.end())
|
||||||
|
? SendWithoutSoundOption::Never
|
||||||
|
: sendWithoutSound->is_boolean()
|
||||||
|
? (sendWithoutSound->get<bool>()
|
||||||
|
? SendWithoutSoundOption::Always
|
||||||
|
: SendWithoutSoundOption::Never)
|
||||||
|
: sendWithoutSound->get<SendWithoutSoundOption>();
|
||||||
s._suggestGhostModeBeforeViewingStory = j.value("suggestGhostModeBeforeViewingStory", true);
|
s._suggestGhostModeBeforeViewingStory = j.value("suggestGhostModeBeforeViewingStory", true);
|
||||||
s._sendReadMessagesLocked = j.value("sendReadMessagesLocked", false);
|
s._sendReadMessagesLocked = j.value("sendReadMessagesLocked", false);
|
||||||
s._sendReadStoriesLocked = j.value("sendReadStoriesLocked", false);
|
s._sendReadStoriesLocked = j.value("sendReadStoriesLocked", false);
|
||||||
|
|||||||
@@ -45,6 +45,12 @@ enum class TranslationProvider {
|
|||||||
Native = 3,
|
Native = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class SendWithoutSoundOption {
|
||||||
|
Never = 0,
|
||||||
|
InGhostMode = 1,
|
||||||
|
Always = 2,
|
||||||
|
};
|
||||||
|
|
||||||
NLOHMANN_JSON_SERIALIZE_ENUM(PeerIdDisplay, {
|
NLOHMANN_JSON_SERIALIZE_ENUM(PeerIdDisplay, {
|
||||||
{PeerIdDisplay::Hidden, 0},
|
{PeerIdDisplay::Hidden, 0},
|
||||||
{PeerIdDisplay::TelegramApi, 1},
|
{PeerIdDisplay::TelegramApi, 1},
|
||||||
@@ -70,6 +76,12 @@ NLOHMANN_JSON_SERIALIZE_ENUM(TranslationProvider, {
|
|||||||
{TranslationProvider::Native, "native"},
|
{TranslationProvider::Native, "native"},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
NLOHMANN_JSON_SERIALIZE_ENUM(SendWithoutSoundOption, {
|
||||||
|
{SendWithoutSoundOption::Never, 0},
|
||||||
|
{SendWithoutSoundOption::InGhostMode, 1},
|
||||||
|
{SendWithoutSoundOption::Always, 2},
|
||||||
|
})
|
||||||
|
|
||||||
class GhostModeAccountSettings {
|
class GhostModeAccountSettings {
|
||||||
public:
|
public:
|
||||||
GhostModeAccountSettings();
|
GhostModeAccountSettings();
|
||||||
@@ -81,7 +93,8 @@ public:
|
|||||||
[[nodiscard]] bool sendOfflinePacketAfterOnline() const { return _sendOfflinePacketAfterOnline.current(); }
|
[[nodiscard]] bool sendOfflinePacketAfterOnline() const { return _sendOfflinePacketAfterOnline.current(); }
|
||||||
[[nodiscard]] bool markReadAfterAction() const { return _markReadAfterAction.current(); }
|
[[nodiscard]] bool markReadAfterAction() const { return _markReadAfterAction.current(); }
|
||||||
[[nodiscard]] bool useScheduledMessages() const { return _useScheduledMessages.current(); }
|
[[nodiscard]] bool useScheduledMessages() const { return _useScheduledMessages.current(); }
|
||||||
[[nodiscard]] bool sendWithoutSound() const { return _sendWithoutSound.current(); }
|
[[nodiscard]] SendWithoutSoundOption sendWithoutSound() const { return _sendWithoutSound.current(); }
|
||||||
|
[[nodiscard]] bool shouldSendWithoutSound() const;
|
||||||
[[nodiscard]] bool suggestGhostModeBeforeViewingStory() const { return _suggestGhostModeBeforeViewingStory.current(); }
|
[[nodiscard]] bool suggestGhostModeBeforeViewingStory() const { return _suggestGhostModeBeforeViewingStory.current(); }
|
||||||
[[nodiscard]] bool isGhostModeActive() const { return _ghostModeActive.current(); }
|
[[nodiscard]] bool isGhostModeActive() const { return _ghostModeActive.current(); }
|
||||||
[[nodiscard]] bool isUseScheduledMessages() const { return isGhostModeActive() && useScheduledMessages(); }
|
[[nodiscard]] bool isUseScheduledMessages() const { return isGhostModeActive() && useScheduledMessages(); }
|
||||||
@@ -99,7 +112,7 @@ public:
|
|||||||
void setSendOfflinePacketAfterOnline(bool val);
|
void setSendOfflinePacketAfterOnline(bool val);
|
||||||
void setMarkReadAfterAction(bool val);
|
void setMarkReadAfterAction(bool val);
|
||||||
void setUseScheduledMessages(bool val);
|
void setUseScheduledMessages(bool val);
|
||||||
void setSendWithoutSound(bool val);
|
void setSendWithoutSound(SendWithoutSoundOption val);
|
||||||
void setSuggestGhostModeBeforeViewingStory(bool val);
|
void setSuggestGhostModeBeforeViewingStory(bool val);
|
||||||
void setGhostModeEnabled(bool val);
|
void setGhostModeEnabled(bool val);
|
||||||
|
|
||||||
@@ -123,8 +136,8 @@ public:
|
|||||||
[[nodiscard]] rpl::producer<bool> markReadAfterActionChanges() const { return _markReadAfterAction.changes(); }
|
[[nodiscard]] rpl::producer<bool> markReadAfterActionChanges() const { return _markReadAfterAction.changes(); }
|
||||||
[[nodiscard]] rpl::producer<bool> useScheduledMessagesValue() const { return _useScheduledMessages.value(); }
|
[[nodiscard]] rpl::producer<bool> useScheduledMessagesValue() const { return _useScheduledMessages.value(); }
|
||||||
[[nodiscard]] rpl::producer<bool> useScheduledMessagesChanges() const { return _useScheduledMessages.changes(); }
|
[[nodiscard]] rpl::producer<bool> useScheduledMessagesChanges() const { return _useScheduledMessages.changes(); }
|
||||||
[[nodiscard]] rpl::producer<bool> sendWithoutSoundValue() const { return _sendWithoutSound.value(); }
|
[[nodiscard]] rpl::producer<SendWithoutSoundOption> sendWithoutSoundValue() const { return _sendWithoutSound.value(); }
|
||||||
[[nodiscard]] rpl::producer<bool> sendWithoutSoundChanges() const { return _sendWithoutSound.changes(); }
|
[[nodiscard]] rpl::producer<SendWithoutSoundOption> sendWithoutSoundChanges() const { return _sendWithoutSound.changes(); }
|
||||||
[[nodiscard]] rpl::producer<bool> suggestGhostModeBeforeViewingStoryValue() const { return _suggestGhostModeBeforeViewingStory.value(); }
|
[[nodiscard]] rpl::producer<bool> suggestGhostModeBeforeViewingStoryValue() const { return _suggestGhostModeBeforeViewingStory.value(); }
|
||||||
[[nodiscard]] rpl::producer<bool> suggestGhostModeBeforeViewingStoryChanges() const { return _suggestGhostModeBeforeViewingStory.changes(); }
|
[[nodiscard]] rpl::producer<bool> suggestGhostModeBeforeViewingStoryChanges() const { return _suggestGhostModeBeforeViewingStory.changes(); }
|
||||||
[[nodiscard]] rpl::producer<bool> ghostModeActiveValue() const { return _ghostModeActive.value(); }
|
[[nodiscard]] rpl::producer<bool> ghostModeActiveValue() const { return _ghostModeActive.value(); }
|
||||||
@@ -154,7 +167,7 @@ private:
|
|||||||
rpl::variable<bool> _sendOfflinePacketAfterOnline = false;
|
rpl::variable<bool> _sendOfflinePacketAfterOnline = false;
|
||||||
rpl::variable<bool> _markReadAfterAction = true;
|
rpl::variable<bool> _markReadAfterAction = true;
|
||||||
rpl::variable<bool> _useScheduledMessages = false;
|
rpl::variable<bool> _useScheduledMessages = false;
|
||||||
rpl::variable<bool> _sendWithoutSound = false;
|
rpl::variable<SendWithoutSoundOption> _sendWithoutSound = SendWithoutSoundOption::Never;
|
||||||
rpl::variable<bool> _suggestGhostModeBeforeViewingStory = true;
|
rpl::variable<bool> _suggestGhostModeBeforeViewingStory = true;
|
||||||
rpl::variable<bool> _ghostModeActive = false;
|
rpl::variable<bool> _ghostModeActive = false;
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include "styles/style_menu_icons.h"
|
#include "styles/style_menu_icons.h"
|
||||||
#include "styles/style_settings.h"
|
#include "styles/style_settings.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
|
#include "ui/boxes/single_choice_box.h"
|
||||||
#include "ui/vertical_list.h"
|
#include "ui/vertical_list.h"
|
||||||
#include "ui/text/text.h"
|
#include "ui/text/text.h"
|
||||||
#include "ui/toast/toast.h"
|
#include "ui/toast/toast.h"
|
||||||
@@ -445,31 +446,45 @@ void BuildGhostEssentials(SectionBuilder &builder) {
|
|||||||
AddDividerText(container, tr::ayu_UseScheduledMessagesDescription());
|
AddDividerText(container, tr::ayu_UseScheduledMessagesDescription());
|
||||||
|
|
||||||
AddSkip(container);
|
AddSkip(container);
|
||||||
const auto silentButton = AddButtonWithIcon(
|
const auto silentOptions = std::vector<QString>{
|
||||||
|
tr::ayu_SendWithoutSoundByDefaultNever(tr::now),
|
||||||
|
tr::ayu_SendWithoutSoundByDefaultInGhostMode(tr::now),
|
||||||
|
tr::ayu_SendWithoutSoundByDefaultAlways(tr::now),
|
||||||
|
};
|
||||||
|
const auto silentOptionText = state->selectedUserId.value(
|
||||||
|
) | rpl::map([=](uint64 id) {
|
||||||
|
return AyuSettings::ghost(id).sendWithoutSoundValue(
|
||||||
|
) | rpl::map([=](SendWithoutSoundOption value) {
|
||||||
|
return silentOptions[static_cast<int>(value)];
|
||||||
|
});
|
||||||
|
}) | rpl::flatten_latest();
|
||||||
|
const auto silentButton = AddButtonWithLabel(
|
||||||
container,
|
container,
|
||||||
tr::ayu_SendWithoutSoundByDefault(),
|
tr::ayu_SendWithoutSoundByDefault(),
|
||||||
st::settingsButtonNoIcon
|
std::move(silentOptionText),
|
||||||
);
|
st::settingsButtonNoIcon);
|
||||||
if (wctx.highlights) {
|
if (wctx.highlights) {
|
||||||
wctx.highlights->push_back(std::make_pair(
|
wctx.highlights->push_back(std::make_pair(
|
||||||
u"ayu/sendWithoutSound"_q,
|
u"ayu/sendWithoutSound"_q,
|
||||||
HighlightEntry{ silentButton.get(), {} }));
|
HighlightEntry{ silentButton.get(), {} }));
|
||||||
}
|
}
|
||||||
silentButton->toggleOn(
|
silentButton->addClickHandler([=] {
|
||||||
state->selectedUserId.value()
|
controller->show(Box([=](not_null<Ui::GenericBox*> box) {
|
||||||
| rpl::map([](uint64 id) {
|
const auto save = [=](int index) {
|
||||||
return AyuSettings::ghost(id).sendWithoutSoundValue();
|
AyuSettings::ghost(state->selectedUserId.current()
|
||||||
}) | rpl::flatten_latest()
|
).setSendWithoutSound(
|
||||||
)->toggledValue(
|
static_cast<SendWithoutSoundOption>(index));
|
||||||
) | rpl::filter(
|
};
|
||||||
[=](bool enabled) {
|
SingleChoiceBox(box, {
|
||||||
return enabled != AyuSettings::ghost(state->selectedUserId.current()).sendWithoutSound();
|
.title = tr::ayu_SendWithoutSoundByDefault(),
|
||||||
}
|
.options = silentOptions,
|
||||||
) | on_next(
|
.initialSelection = static_cast<int>(
|
||||||
[=](bool enabled) {
|
AyuSettings::ghost(state->selectedUserId.current()
|
||||||
AyuSettings::ghost(state->selectedUserId.current()).setSendWithoutSound(enabled);
|
).sendWithoutSound()),
|
||||||
},
|
.callback = save,
|
||||||
container->lifetime());
|
});
|
||||||
|
}));
|
||||||
|
});
|
||||||
AddSkip(container);
|
AddSkip(container);
|
||||||
AddDividerText(container, tr::ayu_SendWithoutSoundByDefaultDescription());
|
AddDividerText(container, tr::ayu_SendWithoutSoundByDefaultDescription());
|
||||||
|
|
||||||
|
|||||||
@@ -614,7 +614,7 @@ bool ShouldSendSilent(
|
|||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
const Api::SendOptions &options) {
|
const Api::SendOptions &options) {
|
||||||
const auto &ghost = AyuSettings::ghost(&peer->session());
|
const auto &ghost = AyuSettings::ghost(&peer->session());
|
||||||
if (ghost.sendWithoutSound()) {
|
if (ghost.shouldSendWithoutSound()) {
|
||||||
return !options.silent;
|
return !options.silent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -749,7 +749,7 @@ FillMenuResult FillSendMenu(
|
|||||||
const auto &ghost = maybeShow
|
const auto &ghost = maybeShow
|
||||||
? AyuSettings::ghost(&maybeShow->session())
|
? AyuSettings::ghost(&maybeShow->session())
|
||||||
: AyuSettings::ghost();
|
: AyuSettings::ghost();
|
||||||
const auto sendWithoutSound = ghost.sendWithoutSound();
|
const auto sendWithoutSound = ghost.shouldSendWithoutSound();
|
||||||
menu->addAction(
|
menu->addAction(
|
||||||
sendWithoutSound ? tr::ayu_SendWithSound(tr::now) : tr::lng_send_silent_message(tr::now),
|
sendWithoutSound ? tr::ayu_SendWithSound(tr::now) : tr::lng_send_silent_message(tr::now),
|
||||||
[=] { action({ Api::SendOptions{ .silent = true } }, details); },
|
[=] { action({ Api::SendOptions{ .silent = true } }, details); },
|
||||||
|
|||||||
@@ -105,7 +105,6 @@ private:
|
|||||||
QAction *_ghostMode = nullptr;
|
QAction *_ghostMode = nullptr;
|
||||||
QAction *_readOnInteract = nullptr;
|
QAction *_readOnInteract = nullptr;
|
||||||
QAction *_scheduleMessages = nullptr;
|
QAction *_scheduleMessages = nullptr;
|
||||||
QAction *_sendWithoutSound = nullptr;
|
|
||||||
|
|
||||||
NSPasteboard *_pasteboard = nullptr;
|
NSPasteboard *_pasteboard = nullptr;
|
||||||
int _pasteboardChangeCount = -1;
|
int _pasteboardChangeCount = -1;
|
||||||
@@ -237,9 +236,6 @@ void Manager::retranslate() {
|
|||||||
if (_scheduleMessages) {
|
if (_scheduleMessages) {
|
||||||
_scheduleMessages->setText(tr::ayu_UseScheduledMessages(tr::now));
|
_scheduleMessages->setText(tr::ayu_UseScheduledMessages(tr::now));
|
||||||
}
|
}
|
||||||
if (_sendWithoutSound) {
|
|
||||||
_sendWithoutSound->setText(tr::ayu_SendWithoutSoundByDefault(tr::now));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::ensureLanguageBound() {
|
void Manager::ensureLanguageBound() {
|
||||||
@@ -336,7 +332,6 @@ void Manager::recomputeState() {
|
|||||||
ForceDisabled(_ghostMode, ghostInactive);
|
ForceDisabled(_ghostMode, ghostInactive);
|
||||||
ForceDisabled(_readOnInteract, ghostInactive);
|
ForceDisabled(_readOnInteract, ghostInactive);
|
||||||
ForceDisabled(_scheduleMessages, ghostInactive);
|
ForceDisabled(_scheduleMessages, ghostInactive);
|
||||||
ForceDisabled(_sendWithoutSound, ghostInactive);
|
|
||||||
const auto setChecked = [](QAction *action, bool checked) {
|
const auto setChecked = [](QAction *action, bool checked) {
|
||||||
const auto wasBlocked = action->blockSignals(true);
|
const auto wasBlocked = action->blockSignals(true);
|
||||||
action->setChecked(checked);
|
action->setChecked(checked);
|
||||||
@@ -348,12 +343,10 @@ void Manager::recomputeState() {
|
|||||||
: tr::ayu_EnableGhostMode(tr::now));
|
: tr::ayu_EnableGhostMode(tr::now));
|
||||||
setChecked(_readOnInteract, ghost->markReadAfterAction());
|
setChecked(_readOnInteract, ghost->markReadAfterAction());
|
||||||
setChecked(_scheduleMessages, ghost->useScheduledMessages());
|
setChecked(_scheduleMessages, ghost->useScheduledMessages());
|
||||||
setChecked(_sendWithoutSound, ghost->sendWithoutSound());
|
|
||||||
} else {
|
} else {
|
||||||
_ghostMode->setText(tr::ayu_EnableGhostMode(tr::now));
|
_ghostMode->setText(tr::ayu_EnableGhostMode(tr::now));
|
||||||
setChecked(_readOnInteract, false);
|
setChecked(_readOnInteract, false);
|
||||||
setChecked(_scheduleMessages, false);
|
setChecked(_scheduleMessages, false);
|
||||||
setChecked(_sendWithoutSound, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -592,13 +585,6 @@ void Manager::buildGhostModeMenu(QMenu *ghostMode) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
_sendWithoutSound = addToggle(
|
|
||||||
u"Send without Sound"_q,
|
|
||||||
[this](bool enabled) {
|
|
||||||
if (const auto ghost = resolveGhostSettings()) {
|
|
||||||
ghost->setSendWithoutSound(enabled);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::buildWindowMenu(QMenu *window) {
|
void Manager::buildWindowMenu(QMenu *window) {
|
||||||
@@ -720,8 +706,7 @@ void Manager::destroy() {
|
|||||||
= _strikeOut = _blockquote = _monospace = _clearFormat
|
= _strikeOut = _blockquote = _monospace = _clearFormat
|
||||||
= nullptr;
|
= nullptr;
|
||||||
_ghostModeMenu = nullptr;
|
_ghostModeMenu = nullptr;
|
||||||
_ghostMode = _readOnInteract = _scheduleMessages = _sendWithoutSound
|
_ghostMode = _readOnInteract = _scheduleMessages = nullptr;
|
||||||
= nullptr;
|
|
||||||
_pasteboard = nullptr;
|
_pasteboard = nullptr;
|
||||||
_pasteboardChangeCount = -1;
|
_pasteboardChangeCount = -1;
|
||||||
_pasteboardHasText = false;
|
_pasteboardHasText = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user