feat: add ghost mode options to macOS bar

This commit is contained in:
AlexeyZavar
2026-04-25 00:47:54 +03:00
parent 44ed070a28
commit fb9816791e
@@ -31,6 +31,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <Cocoa/Cocoa.h> #include <Cocoa/Cocoa.h>
// AyuGram includes
#include "ayu/ayu_settings.h"
namespace Platform { namespace Platform {
namespace { namespace {
@@ -47,6 +51,9 @@ private:
void buildAppleMenu(QMenu *main); void buildAppleMenu(QMenu *main);
void buildFileMenu(QMenu *file); void buildFileMenu(QMenu *file);
void buildEditMenu(QMenu *edit); void buildEditMenu(QMenu *edit);
void buildGhostModeMenu(QMenu *ghostMode);
void buildWindowMenu(QMenu *window); void buildWindowMenu(QMenu *window);
void retranslate(); void retranslate();
void ensureLanguageBound(); void ensureLanguageBound();
@@ -54,6 +61,8 @@ private:
[[nodiscard]] bool clipboardHasText(); [[nodiscard]] bool clipboardHasText();
[[nodiscard]] Window::Controller *resolveActiveWindow() const; [[nodiscard]] Window::Controller *resolveActiveWindow() const;
[[nodiscard]] GhostModeAccountSettings *resolveGhostSettings() const;
template <typename Callback> template <typename Callback>
void withActiveWindow(Callback callback) { void withActiveWindow(Callback callback) {
const auto window = resolveActiveWindow(); const auto window = resolveActiveWindow();
@@ -92,6 +101,12 @@ private:
QAction *_monospace = nullptr; QAction *_monospace = nullptr;
QAction *_clearFormat = nullptr; QAction *_clearFormat = nullptr;
QMenu *_ghostModeMenu = nullptr;
QAction *_ghostMode = nullptr;
QAction *_readOnInteract = nullptr;
QAction *_scheduleMessages = nullptr;
QAction *_sendWithoutSound = nullptr;
NSPasteboard *_pasteboard = nullptr; NSPasteboard *_pasteboard = nullptr;
int _pasteboardChangeCount = -1; int _pasteboardChangeCount = -1;
bool _pasteboardHasText = false; bool _pasteboardHasText = false;
@@ -135,6 +150,15 @@ Window::Controller *Manager::resolveActiveWindow() const {
return active ? active : Core::App().activePrimaryWindow(); return active ? active : Core::App().activePrimaryWindow();
} }
GhostModeAccountSettings *Manager::resolveGhostSettings() const {
const auto window = resolveActiveWindow();
if (!window || window->locked()) {
return nullptr;
}
const auto session = window->maybeSession();
return session ? &AyuSettings::ghost(session) : nullptr;
}
bool Manager::clipboardHasText() { bool Manager::clipboardHasText() {
const auto current = static_cast<int>([_pasteboard changeCount]); const auto current = static_cast<int>([_pasteboard changeCount]);
if (_pasteboardChangeCount != current) { if (_pasteboardChangeCount != current) {
@@ -195,6 +219,27 @@ void Manager::retranslate() {
if (_clearFormat) { if (_clearFormat) {
_clearFormat->setText(tr::lng_menu_formatting_clear(tr::now)); _clearFormat->setText(tr::lng_menu_formatting_clear(tr::now));
} }
if (_ghostModeMenu) {
_ghostModeMenu->setTitle(tr::ayu_CategoryGhostMode(tr::now));
}
if (_ghostMode) {
if (const auto ghost = resolveGhostSettings()) {
_ghostMode->setText(ghost->isGhostModeActive()
? tr::ayu_DisableGhostMode(tr::now)
: tr::ayu_EnableGhostMode(tr::now));
} else {
_ghostMode->setText(tr::ayu_EnableGhostMode(tr::now));
}
}
if (_readOnInteract) {
_readOnInteract->setText(tr::ayu_MarkReadAfterAction(tr::now));
}
if (_scheduleMessages) {
_scheduleMessages->setText(tr::ayu_UseScheduledMessages(tr::now));
}
if (_sendWithoutSound) {
_sendWithoutSound->setText(tr::ayu_SendWithoutSoundByDefault(tr::now));
}
} }
void Manager::ensureLanguageBound() { void Manager::ensureLanguageBound() {
@@ -285,6 +330,31 @@ void Manager::recomputeState() {
_monospace, _monospace,
disabled(Field::kTagPre) || disabled(Field::kTagCode)); disabled(Field::kTagPre) || disabled(Field::kTagCode));
ForceDisabled(_clearFormat, markdownState.disabled()); ForceDisabled(_clearFormat, markdownState.disabled());
const auto ghost = resolveGhostSettings();
const auto ghostInactive = (ghost == nullptr);
ForceDisabled(_ghostMode, ghostInactive);
ForceDisabled(_readOnInteract, ghostInactive);
ForceDisabled(_scheduleMessages, ghostInactive);
ForceDisabled(_sendWithoutSound, ghostInactive);
const auto setChecked = [](QAction *action, bool checked) {
const auto wasBlocked = action->blockSignals(true);
action->setChecked(checked);
action->blockSignals(wasBlocked);
};
if (ghost) {
_ghostMode->setText(ghost->isGhostModeActive()
? tr::ayu_DisableGhostMode(tr::now)
: tr::ayu_EnableGhostMode(tr::now));
setChecked(_readOnInteract, ghost->markReadAfterAction());
setChecked(_scheduleMessages, ghost->useScheduledMessages());
setChecked(_sendWithoutSound, ghost->sendWithoutSound());
} else {
_ghostMode->setText(tr::ayu_EnableGhostMode(tr::now));
setChecked(_readOnInteract, false);
setChecked(_scheduleMessages, false);
setChecked(_sendWithoutSound, false);
}
} }
void Manager::buildAppleMenu(QMenu *main) { void Manager::buildAppleMenu(QMenu *main) {
@@ -466,6 +536,71 @@ void Manager::buildEditMenu(QMenu *edit) {
} }
} }
void Manager::buildGhostModeMenu(QMenu *ghostMode) {
_ghostModeMenu = ghostMode;
QObject::connect(ghostMode, &QMenu::aboutToShow, ghostMode, [this] {
requestUpdate();
});
const auto addToggle = [&](QString text, auto callback) {
const auto action = ghostMode->addAction(std::move(text));
action->setCheckable(true);
QObject::connect(
action,
&QAction::triggered,
action,
[this, callback = std::move(callback)](bool checked) {
callback(checked);
requestUpdate();
});
return action;
};
_ghostMode = ghostMode->addAction(u"Enable Ghost"_q);
QObject::connect(
_ghostMode,
&QAction::triggered,
_ghostMode,
[this] {
if (const auto ghost = resolveGhostSettings()) {
ghost->setGhostModeEnabled(!ghost->isGhostModeActive());
}
requestUpdate();
});
ghostMode->addSeparator();
_readOnInteract = addToggle(
u"Read on Interact"_q,
[this](bool enabled) {
if (const auto ghost = resolveGhostSettings()) {
ghost->setMarkReadAfterAction(enabled);
if (enabled) {
ghost->setUseScheduledMessages(false);
}
}
});
_scheduleMessages = addToggle(
u"Schedule Messages"_q,
[this](bool enabled) {
if (const auto ghost = resolveGhostSettings()) {
ghost->setUseScheduledMessages(enabled);
if (enabled) {
ghost->setMarkReadAfterAction(false);
}
}
});
_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) {
const auto receiver = _menuBar.get(); const auto receiver = _menuBar.get();
_fullScreen = window->addAction( _fullScreen = window->addAction(
@@ -554,6 +689,9 @@ void Manager::buildMenu() {
buildAppleMenu(_menuBar->addMenu(u"AyuGram"_q)); buildAppleMenu(_menuBar->addMenu(u"AyuGram"_q));
buildFileMenu(_menuBar->addMenu(u"File"_q)); buildFileMenu(_menuBar->addMenu(u"File"_q));
buildEditMenu(_menuBar->addMenu(u"Edit"_q)); buildEditMenu(_menuBar->addMenu(u"Edit"_q));
buildGhostModeMenu(_menuBar->addMenu(u"Ghost Mode"_q));
buildWindowMenu(_menuBar->addMenu(u"Window"_q)); buildWindowMenu(_menuBar->addMenu(u"Window"_q));
} }
@@ -581,6 +719,9 @@ void Manager::destroy() {
= _bold = _italic = _underline = _bold = _italic = _underline
= _strikeOut = _blockquote = _monospace = _clearFormat = _strikeOut = _blockquote = _monospace = _clearFormat
= nullptr; = nullptr;
_ghostModeMenu = nullptr;
_ghostMode = _readOnInteract = _scheduleMessages = _sendWithoutSound
= nullptr;
_pasteboard = nullptr; _pasteboard = nullptr;
_pasteboardChangeCount = -1; _pasteboardChangeCount = -1;
_pasteboardHasText = false; _pasteboardHasText = false;