mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Add reply from Windows native notifications.
This commit is contained in:
parent
967e86f4ab
commit
8c71d03959
1 changed files with 135 additions and 25 deletions
|
@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "windows_quiethours_h.h"
|
#include "windows_quiethours_h.h"
|
||||||
|
#include "styles/style_chat.h"
|
||||||
|
|
||||||
#include <QtCore/QOperatingSystemVersion>
|
#include <QtCore/QOperatingSystemVersion>
|
||||||
|
|
||||||
|
@ -32,7 +33,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include <winrt/Windows.Foundation.h>
|
#include <winrt/Windows.Foundation.h>
|
||||||
#include <winrt/Windows.Data.Xml.Dom.h>
|
#include <winrt/Windows.Data.Xml.Dom.h>
|
||||||
#include <winrt/Windows.UI.Notifications.h>
|
#include <winrt/Windows.UI.Notifications.h>
|
||||||
#include <winrt/Windows.UI.Notifications.Management.h>
|
|
||||||
|
|
||||||
HICON qt_pixmapToWinHICON(const QPixmap &);
|
HICON qt_pixmapToWinHICON(const QPixmap &);
|
||||||
|
|
||||||
|
@ -48,6 +48,43 @@ namespace Notifications {
|
||||||
#ifndef __MINGW32__
|
#ifndef __MINGW32__
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kNotificationTemplate = LR"(
|
||||||
|
<toast launch="action=open">
|
||||||
|
<visual>
|
||||||
|
<binding template="ToastGeneric">
|
||||||
|
<image placement="appLogoOverride" hint-crop="circle" src=""/>
|
||||||
|
<text hint-maxLines="1"></text>
|
||||||
|
<text></text>
|
||||||
|
<text></text>
|
||||||
|
</binding>
|
||||||
|
</visual>
|
||||||
|
<actions>
|
||||||
|
<input id="fastReply" type="text" placeHolderContent=""/>
|
||||||
|
<action
|
||||||
|
content="Send"
|
||||||
|
arguments="action=reply"
|
||||||
|
activationType="background"
|
||||||
|
imageUri=""
|
||||||
|
hint-inputId="fastReply"/>
|
||||||
|
</actions>
|
||||||
|
<audio silent="true"/>
|
||||||
|
</toast>
|
||||||
|
)";
|
||||||
|
|
||||||
|
constexpr auto kNotificationTemplateSmall = LR"(
|
||||||
|
<toast launch="action=open">
|
||||||
|
<visual>
|
||||||
|
<binding template="ToastGeneric">
|
||||||
|
<image placement="appLogoOverride" hint-crop="circle" src=""/>
|
||||||
|
<text hint-maxLines="1"></text>
|
||||||
|
<text></text>
|
||||||
|
<text></text>
|
||||||
|
</binding>
|
||||||
|
</visual>
|
||||||
|
<audio silent="true"/>
|
||||||
|
</toast>
|
||||||
|
)";
|
||||||
|
|
||||||
bool init() {
|
bool init() {
|
||||||
if (!IsWindows8OrGreater()) {
|
if (!IsWindows8OrGreater()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -100,6 +137,28 @@ void SetImageSrc(const XmlDocument &toastXml, const std::wstring &path) {
|
||||||
L"file:///" + path);
|
L"file:///" + path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Throws.
|
||||||
|
void SetReplyIconSrc(const XmlDocument &toastXml, const std::wstring &path) {
|
||||||
|
const auto nodeList = toastXml.GetElementsByTagName(L"action");
|
||||||
|
const auto attributes = nodeList.Item(0).Attributes();
|
||||||
|
return SetNodeValueString(
|
||||||
|
toastXml,
|
||||||
|
attributes.GetNamedItem(L"imageUri"),
|
||||||
|
L"file:///" + path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throws.
|
||||||
|
void SetReplyPlaceholder(
|
||||||
|
const XmlDocument &toastXml,
|
||||||
|
const std::wstring &placeholder) {
|
||||||
|
const auto nodeList = toastXml.GetElementsByTagName(L"input");
|
||||||
|
const auto attributes = nodeList.Item(0).Attributes();
|
||||||
|
return SetNodeValueString(
|
||||||
|
toastXml,
|
||||||
|
attributes.GetNamedItem(L"placeHolderContent"),
|
||||||
|
placeholder);
|
||||||
|
}
|
||||||
|
|
||||||
auto Checked = false;
|
auto Checked = false;
|
||||||
auto InitSucceeded = false;
|
auto InitSucceeded = false;
|
||||||
|
|
||||||
|
@ -340,8 +399,10 @@ private:
|
||||||
const QString &msg,
|
const QString &msg,
|
||||||
bool hideNameAndPhoto,
|
bool hideNameAndPhoto,
|
||||||
bool hideReplyButton);
|
bool hideReplyButton);
|
||||||
|
[[nodiscard]] std::wstring ensureSendButtonIcon();
|
||||||
|
|
||||||
Window::Notifications::CachedUserpics _cachedUserpics;
|
Window::Notifications::CachedUserpics _cachedUserpics;
|
||||||
|
std::wstring _sendButtonIconPath;
|
||||||
|
|
||||||
std::shared_ptr<Manager*> _guarded;
|
std::shared_ptr<Manager*> _guarded;
|
||||||
ToastNotifier _notifier = nullptr;
|
ToastNotifier _notifier = nullptr;
|
||||||
|
@ -469,6 +530,15 @@ bool Manager::Private::showNotification(
|
||||||
}).value_or(false);
|
}).value_or(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::wstring Manager::Private::ensureSendButtonIcon() {
|
||||||
|
if (_sendButtonIconPath.empty()) {
|
||||||
|
const auto path = cWorkingDir() + u"tdata/temp/fast_reply.png"_q;
|
||||||
|
st::historySendIcon.instance(Qt::white, 300).save(path, "PNG");
|
||||||
|
_sendButtonIconPath = path.toStdWString();
|
||||||
|
}
|
||||||
|
return _sendButtonIconPath;
|
||||||
|
}
|
||||||
|
|
||||||
bool Manager::Private::showNotificationInTryCatch(
|
bool Manager::Private::showNotificationInTryCatch(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
std::shared_ptr<Data::CloudImageView> &userpicView,
|
std::shared_ptr<Data::CloudImageView> &userpicView,
|
||||||
|
@ -479,17 +549,35 @@ bool Manager::Private::showNotificationInTryCatch(
|
||||||
bool hideNameAndPhoto,
|
bool hideNameAndPhoto,
|
||||||
bool hideReplyButton) {
|
bool hideReplyButton) {
|
||||||
const auto withSubtitle = !subtitle.isEmpty();
|
const auto withSubtitle = !subtitle.isEmpty();
|
||||||
const auto toastXml = ToastNotificationManager::GetTemplateContent(
|
auto toastXml = XmlDocument();
|
||||||
(withSubtitle
|
const auto modern = Platform::IsWindows10OrGreater();
|
||||||
? ToastTemplateType::ToastImageAndText04
|
if (modern) {
|
||||||
: ToastTemplateType::ToastImageAndText02));
|
toastXml.LoadXml(hideReplyButton
|
||||||
SetAudioSilent(toastXml);
|
? kNotificationTemplateSmall
|
||||||
|
: kNotificationTemplate);
|
||||||
|
} else {
|
||||||
|
toastXml = ToastNotificationManager::GetTemplateContent(
|
||||||
|
(withSubtitle
|
||||||
|
? ToastTemplateType::ToastImageAndText04
|
||||||
|
: ToastTemplateType::ToastImageAndText02));
|
||||||
|
SetAudioSilent(toastXml);
|
||||||
|
}
|
||||||
|
|
||||||
const auto userpicKey = hideNameAndPhoto
|
const auto userpicKey = hideNameAndPhoto
|
||||||
? InMemoryKey()
|
? InMemoryKey()
|
||||||
: peer->userpicUniqueKey(userpicView);
|
: peer->userpicUniqueKey(userpicView);
|
||||||
const auto userpicPath = _cachedUserpics.get(userpicKey, peer, userpicView);
|
const auto userpicPath = _cachedUserpics.get(
|
||||||
const auto userpicPathWide = QDir::toNativeSeparators(userpicPath).toStdWString();
|
userpicKey,
|
||||||
|
peer,
|
||||||
|
userpicView);
|
||||||
|
const auto userpicPathWide = QDir::toNativeSeparators(
|
||||||
|
userpicPath).toStdWString();
|
||||||
|
if (modern && !hideReplyButton) {
|
||||||
|
SetReplyIconSrc(toastXml, ensureSendButtonIcon());
|
||||||
|
SetReplyPlaceholder(
|
||||||
|
toastXml,
|
||||||
|
tr::lng_message_ph(tr::now).toStdWString());
|
||||||
|
}
|
||||||
|
|
||||||
SetImageSrc(toastXml, userpicPathWide);
|
SetImageSrc(toastXml, userpicPathWide);
|
||||||
|
|
||||||
|
@ -525,30 +613,52 @@ bool Manager::Private::showNotificationInTryCatch(
|
||||||
.full = key,
|
.full = key,
|
||||||
.msgId = msgId
|
.msgId = msgId
|
||||||
};
|
};
|
||||||
|
|
||||||
auto toast = ToastNotification(toastXml);
|
auto toast = ToastNotification(toastXml);
|
||||||
const auto token1 = toast.Activated([=](
|
const auto token1 = toast.Activated([=](
|
||||||
const ToastNotification &sender,
|
const ToastNotification &sender,
|
||||||
const winrt::Windows::Foundation::IInspectable &args) {
|
const winrt::Windows::Foundation::IInspectable &object) {
|
||||||
performOnMainQueue([notificationId](Manager *manager) {
|
if (const auto args = object.try_as<ToastActivatedEventArgs>()) {
|
||||||
manager->notificationActivated(notificationId);
|
const auto arguments = args.Arguments();
|
||||||
});
|
const auto userInput = args.UserInput();
|
||||||
|
if (arguments == L"action=reply") {
|
||||||
|
const auto reply = userInput.TryLookup(L"fastReply");
|
||||||
|
const auto data = reply.try_as<IReference<winrt::hstring>>();
|
||||||
|
auto text = data
|
||||||
|
? QString::fromWCharArray(data.GetString().c_str())
|
||||||
|
: QString();
|
||||||
|
if (text.indexOf(QChar('\n')) < 0) {
|
||||||
|
text.replace(QChar('\r'), QChar('\n'));
|
||||||
|
}
|
||||||
|
performOnMainQueue([notificationId, text](Manager *manager) {
|
||||||
|
manager->notificationReplied(notificationId, { text });
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
performOnMainQueue([notificationId](Manager *manager) {
|
||||||
|
manager->notificationActivated(notificationId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
performOnMainQueue([notificationId](Manager *manager) {
|
||||||
|
manager->notificationActivated(notificationId);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
const auto token2 = toast.Dismissed([=](
|
const auto token2 = toast.Dismissed([=](
|
||||||
const ToastNotification &sender,
|
const ToastNotification &sender,
|
||||||
const ToastDismissedEventArgs &args) {
|
const ToastDismissedEventArgs &args) {
|
||||||
base::WinRT::Try([&] {
|
const auto reason = args.Reason();
|
||||||
switch (args.Reason()) {
|
switch (reason) {
|
||||||
case ToastDismissalReason::ApplicationHidden:
|
case ToastDismissalReason::ApplicationHidden:
|
||||||
case ToastDismissalReason::TimedOut: // Went to Action Center.
|
case ToastDismissalReason::TimedOut: // Went to Action Center.
|
||||||
break;
|
break;
|
||||||
case ToastDismissalReason::UserCanceled:
|
case ToastDismissalReason::UserCanceled:
|
||||||
default:
|
default:
|
||||||
performOnMainQueue([notificationId](Manager *manager) {
|
performOnMainQueue([notificationId](Manager *manager) {
|
||||||
manager->clearNotification(notificationId);
|
manager->clearNotification(notificationId);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
});
|
||||||
const auto token3 = toast.Failed([=](
|
const auto token3 = toast.Failed([=](
|
||||||
const auto &sender,
|
const auto &sender,
|
||||||
|
|
Loading…
Add table
Reference in a new issue