mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-04-17 11:58:27 +00:00
improve windows notification ui
This commit is contained in:
parent
e08112d8c8
commit
49900c5a91
10 changed files with 66 additions and 54 deletions
|
|
@ -1,10 +1,5 @@
|
|||
#include "AbstractNotificationBackend.hpp"
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QPainter>
|
||||
#include <QStandardPaths>
|
||||
#include <QSvgRenderer>
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(AbstractNotificationBackend)
|
||||
|
||||
const QHash<int, AbstractNotificationBackend::Notification> AbstractNotificationBackend::Notifications = {
|
||||
|
|
@ -13,26 +8,3 @@ const QHash<int, AbstractNotificationBackend::Notification> AbstractNotification
|
|||
|
||||
AbstractNotificationBackend::AbstractNotificationBackend(QObject *parent) : QObject(parent) {
|
||||
}
|
||||
|
||||
QString AbstractNotificationBackend::getIconAsPng(const QString &imagePath, const QSize &size) {
|
||||
// Convertit "image://internal/phone-disconnect.svg" en ":/data/image/phone-disconnect.svg"
|
||||
QString resourcePath = imagePath;
|
||||
if (imagePath.startsWith("image://internal/"))
|
||||
resourcePath = ":/data/image/" + imagePath.mid(QString("image://internal/").length());
|
||||
|
||||
QSvgRenderer renderer(resourcePath);
|
||||
if (!renderer.isValid()) return QString();
|
||||
|
||||
QImage image(size, QImage::Format_ARGB32_Premultiplied);
|
||||
image.fill(Qt::transparent);
|
||||
QPainter painter(&image);
|
||||
renderer.render(&painter);
|
||||
painter.end();
|
||||
|
||||
QString outPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/linphone_" +
|
||||
QFileInfo(resourcePath).baseName() + ".png";
|
||||
|
||||
if (!QFile::exists(outPath)) image.save(outPath, "PNG");
|
||||
|
||||
return outPath;
|
||||
}
|
||||
|
|
@ -23,8 +23,6 @@ public:
|
|||
AbstractNotificationBackend(QObject *parent = Q_NULLPTR);
|
||||
~AbstractNotificationBackend() = default;
|
||||
|
||||
QString getIconAsPng(const QString &imagePath, const QSize &size = QSize(64, 64));
|
||||
|
||||
enum NotificationType {
|
||||
ReceivedMessage,
|
||||
ReceivedCall
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ using namespace Microsoft::WRL::Wrappers;
|
|||
|
||||
namespace DesktopNotificationManagerCompat {
|
||||
HRESULT RegisterComServer(GUID clsid, const wchar_t exePath[]);
|
||||
HRESULT RegisterAumidInRegistry(const wchar_t *aumid);
|
||||
HRESULT RegisterAumidInRegistry(const wchar_t *aumid, const wchar_t *iconPath = nullptr);
|
||||
HRESULT EnsureRegistered();
|
||||
bool IsRunningAsUwp();
|
||||
|
||||
|
|
@ -100,7 +100,7 @@ HRESULT CreateStartMenuShortcut(const wchar_t *aumid, GUID clsid) {
|
|||
return persistFile->Save(shortcutPath, TRUE);
|
||||
}
|
||||
|
||||
HRESULT RegisterAumidInRegistry(const wchar_t *aumid) {
|
||||
HRESULT RegisterAumidInRegistry(const wchar_t *aumid, const wchar_t *iconPath) {
|
||||
std::wstring keyPath = std::wstring(L"Software\\Classes\\AppUserModelId\\") + aumid;
|
||||
|
||||
HKEY key;
|
||||
|
|
@ -114,11 +114,16 @@ HRESULT RegisterAumidInRegistry(const wchar_t *aumid) {
|
|||
res = ::RegSetValueExW(key, L"DisplayName", 0, REG_SZ, reinterpret_cast<const BYTE *>(displayName),
|
||||
static_cast<DWORD>((wcslen(displayName) + 1) * sizeof(wchar_t)));
|
||||
|
||||
if (iconPath != nullptr) {
|
||||
res = ::RegSetValueExW(key, L"IconUri", 0, REG_SZ, reinterpret_cast<const BYTE *>(iconPath),
|
||||
static_cast<DWORD>((wcslen(iconPath) + 1) * sizeof(wchar_t)));
|
||||
}
|
||||
|
||||
::RegCloseKey(key);
|
||||
return HRESULT_FROM_WIN32(res);
|
||||
}
|
||||
|
||||
HRESULT RegisterAumidAndComServer(const wchar_t *aumid, GUID clsid) {
|
||||
HRESULT RegisterAumidAndComServer(const wchar_t *aumid, GUID clsid, const wchar_t *iconPath) {
|
||||
// If running as Desktop Bridge
|
||||
qDebug() << QString("CLSID : {%1-%2-%3-%4%5-%6%7%8%9%10%11}")
|
||||
.arg(clsid.Data1, 8, 16, QChar('0'))
|
||||
|
|
@ -168,7 +173,7 @@ HRESULT RegisterAumidAndComServer(const wchar_t *aumid, GUID clsid) {
|
|||
RETURN_IF_FAILED(RegisterComServer(clsid, exePath));
|
||||
|
||||
qInfo() << "Register aumid in registry";
|
||||
RETURN_IF_FAILED(RegisterAumidInRegistry(aumid));
|
||||
RETURN_IF_FAILED(RegisterAumidInRegistry(aumid, iconPath));
|
||||
|
||||
s_registeredAumidAndComServer = true;
|
||||
return S_OK;
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ HRESULT CreateStartMenuShortcut(const wchar_t *aumid, GUID clsid);
|
|||
/// </summary>
|
||||
/// <param name="aumid">An AUMID that uniquely identifies your application.</param>
|
||||
/// <param name="clsid">The CLSID of your NotificationActivator class.</param>
|
||||
HRESULT RegisterAumidAndComServer(const wchar_t *aumid, GUID clsid);
|
||||
HRESULT RegisterAumidAndComServer(const wchar_t *aumid, GUID clsid, const wchar_t *iconPath = nullptr);
|
||||
|
||||
/// <summary>
|
||||
/// Registers your module to handle COM activations. Call this upon application startup.
|
||||
|
|
|
|||
|
|
@ -349,17 +349,19 @@ void Notifier::notifyReceivedCall(const shared_ptr<linphone::Call> &call) {
|
|||
auto callLog = call->getCallLog();
|
||||
auto displayName = callLog && callLog->getConferenceInfo()
|
||||
? Utils::coreStringToAppString(callLog->getConferenceInfo()->getSubject())
|
||||
: ToolModel::getDisplayName(call->getRemoteAddress());
|
||||
: ToolModel::getDisplayName(remoteAddress);
|
||||
auto remoteAddrString = Utils::coreStringToAppString(remoteAddress->asStringUriOnly());
|
||||
|
||||
// Accessibility alert
|
||||
//: New call from %1
|
||||
AccessibilityHelper::announceMessage(tr("new_call_alert_accessible_name").arg(displayName));
|
||||
|
||||
App::postCoreAsync([this, gui, displayName]() {
|
||||
App::postCoreAsync([this, gui, displayName, remoteAddrString]() {
|
||||
mustBeInMainThread(getClassName());
|
||||
QVariantMap map;
|
||||
|
||||
map["displayName"].setValue(displayName);
|
||||
map["remoteAddress"].setValue(remoteAddrString);
|
||||
map["call"].setValue(gui);
|
||||
|
||||
CREATE_NOTIFICATION(AbstractNotificationBackend::ReceivedCall, map)
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ uint NotificationBackend::sendCallNotification(QVariantMap data) {
|
|||
// Actions : paires (clé, label)
|
||||
QStringList actions = {"accept", tr("accept_button"), "decline", tr("decline_button")};
|
||||
|
||||
QString appIcon = getIconAsPng(Utils::getAppIcon("logo").toString());
|
||||
QString appIcon = Utils::getIconAsPng(Utils::getAppIcon("logo").toString());
|
||||
// QString appIcon = QString("call-start"); // icône freedesktop standard
|
||||
|
||||
QDBusReply<uint> reply = mInterface->call(QString("Notify"),
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ void NotificationBackend::sendMessageNotification(QVariantMap data) {
|
|||
auto remoteAddress = data["remoteAddress"].toString().toStdWString();
|
||||
auto chatRoomName = data["chatRoomName"].toString().toStdWString();
|
||||
auto chatRoomAddress = data["chatRoomAddress"].toString().toStdWString();
|
||||
auto appIcon = Utils::getIconAsPng(Utils::getAppIcon("logo").toString()).toStdWString();
|
||||
auto avatarUri = data["avatarUri"].toString().toStdWString();
|
||||
bool isGroup = data["isGroupChat"].toBool();
|
||||
ChatGui *chat = data["chat"].value<ChatGui *>();
|
||||
|
|
@ -53,6 +54,9 @@ void NotificationBackend::sendMessageNotification(QVariantMap data) {
|
|||
std::wstring xml = L"<toast>"
|
||||
L" <visual>"
|
||||
L" <binding template=\"ToastGeneric\">"
|
||||
L" <image src=\"file:///" +
|
||||
appIcon +
|
||||
L"\" placement=\"appLogoOverride\"/>"
|
||||
L" <text><![CDATA[" +
|
||||
chatRoomName +
|
||||
L"]]></text>"
|
||||
|
|
@ -82,7 +86,7 @@ void NotificationBackend::sendMessageNotification(QVariantMap data) {
|
|||
IToastNotification *toast = nullptr;
|
||||
hr = DesktopNotificationManagerCompat::CreateToastNotification(doc, &toast);
|
||||
if (FAILED(hr) || !toast) {
|
||||
qWarning() << "CreateToastNotification failed:" << Qt::hex << hr;
|
||||
lWarning() << "CreateToastNotification failed:" << Qt::hex << hr;
|
||||
doc->Release();
|
||||
notifier->Release();
|
||||
Utils::showInformationPopup(tr("info_popup_error_title"), tr("info_popup_error_creating_notification"), false);
|
||||
|
|
@ -103,7 +107,7 @@ void NotificationBackend::sendMessageNotification(QVariantMap data) {
|
|||
|
||||
hr = notifier->Show(toast);
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << "Toast Show failed:" << Qt::hex << hr;
|
||||
lWarning() << "Toast Show failed:" << Qt::hex << hr;
|
||||
}
|
||||
|
||||
toast->Release();
|
||||
|
|
@ -121,6 +125,7 @@ void NotificationBackend::sendCallNotification(QVariantMap data) {
|
|||
}
|
||||
|
||||
auto displayName = data["displayName"].toString().toStdWString();
|
||||
auto remoteAddress = data["remoteAddress"].toString().toStdWString();
|
||||
CallGui *call = data["call"].value<CallGui *>();
|
||||
int timeout = 2;
|
||||
// AbstractNotificationBackend::Notifications[(int)NotificationType::ReceivedCall].getTimeout();
|
||||
|
|
@ -129,8 +134,9 @@ void NotificationBackend::sendCallNotification(QVariantMap data) {
|
|||
auto callDescription = tr("incoming_call").toStdWString();
|
||||
|
||||
QList<ToastButton> actions;
|
||||
QString declineIcon = getIconAsPng(Utils::getAppIcon("endCall").toString());
|
||||
QString acceptIcon = getIconAsPng(Utils::getAppIcon("phone").toString());
|
||||
QString declineIcon = Utils::getIconAsPng(Utils::getAppIcon("endCall").toString());
|
||||
QString acceptIcon = Utils::getIconAsPng(Utils::getAppIcon("phone").toString());
|
||||
auto appIcon = Utils::getIconAsPng(Utils::getAppIcon("logo").toString()).toStdWString();
|
||||
actions.append(ToastButton(tr("accept_button"), "accept", acceptIcon));
|
||||
actions.append(ToastButton(tr("decline_button"), "decline", declineIcon));
|
||||
std::wstring wActions;
|
||||
|
|
@ -150,9 +156,15 @@ void NotificationBackend::sendCallNotification(QVariantMap data) {
|
|||
std::wstring xml = L"<toast scenario=\"reminder\">"
|
||||
L" <visual>"
|
||||
L" <binding template=\"ToastGeneric\">"
|
||||
L" <image src=\"file:///" +
|
||||
appIcon +
|
||||
L"\" placement=\"appLogoOverride\"/>"
|
||||
L" <text hint-style=\"header\">" +
|
||||
displayName +
|
||||
L"</text>"
|
||||
L" <text hint-style=\"base\">" +
|
||||
remoteAddress +
|
||||
L"</text>"
|
||||
L" <text hint-style=\"body\">" +
|
||||
callDescription +
|
||||
L"</text>"
|
||||
|
|
@ -173,7 +185,7 @@ void NotificationBackend::sendCallNotification(QVariantMap data) {
|
|||
IToastNotification *toast = nullptr;
|
||||
hr = DesktopNotificationManagerCompat::CreateToastNotification(doc, &toast);
|
||||
if (FAILED(hr) || !toast) {
|
||||
qWarning() << "CreateToastNotification failed:" << Qt::hex << hr;
|
||||
lWarning() << "CreateToastNotification failed:" << Qt::hex << hr;
|
||||
doc->Release();
|
||||
notifier->Release();
|
||||
Utils::showInformationPopup(tr("info_popup_error_title"), tr("info_popup_error_creating_notification"), false);
|
||||
|
|
@ -182,12 +194,12 @@ void NotificationBackend::sendCallNotification(QVariantMap data) {
|
|||
|
||||
ComPtr<IToastNotification2> toast2;
|
||||
hr = toast->QueryInterface(IID_PPV_ARGS(&toast2));
|
||||
if (FAILED(hr)) qWarning() << "QueryInterface failed";
|
||||
if (FAILED(hr)) lWarning() << "QueryInterface failed";
|
||||
auto callId = call->mCore->getCallId();
|
||||
qDebug() << "put tag to toast" << callId;
|
||||
hr = toast2->put_Tag(HStringReference(reinterpret_cast<const wchar_t *>(callId.utf16())).Get());
|
||||
toast2->put_Group(HStringReference(L"linphone").Get());
|
||||
if (FAILED(hr)) qWarning() << "puting tag on toast failed";
|
||||
if (FAILED(hr)) lWarning() << "puting tag on toast failed";
|
||||
|
||||
connect(call->mCore.get(), &CallCore::stateChanged, this, [this, call, notifier, toast] {
|
||||
if (call->mCore->getState() == LinphoneEnums::CallState::End ||
|
||||
|
|
@ -201,7 +213,7 @@ void NotificationBackend::sendCallNotification(QVariantMap data) {
|
|||
|
||||
auto hr = history->RemoveGroupedTag(reinterpret_cast<const wchar_t *>(callId.utf16()), L"linphone");
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << "removing toast failed";
|
||||
lWarning() << "removing toast failed";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -248,7 +260,7 @@ void NotificationBackend::sendCallNotification(QVariantMap data) {
|
|||
|
||||
hr = notifier->Show(toast);
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << "Toast Show failed:" << Qt::hex << hr;
|
||||
lWarning() << "Toast Show failed:" << Qt::hex << hr;
|
||||
}
|
||||
|
||||
toast->Release();
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ FILE *gStream = NULL;
|
|||
#define WIDEN2(x) L##x
|
||||
#define WIDEN(x) WIDEN2(x)
|
||||
|
||||
static const wchar_t *mAumid = WIDEN(APPLICATION_ID);
|
||||
static const wchar_t *mAumid = WIDEN(APPLICATION_NAME);
|
||||
|
||||
void cleanStream() {
|
||||
#ifdef _WIN32
|
||||
|
|
@ -69,13 +69,8 @@ int main(int argc, char *argv[]) {
|
|||
HRESULT hrCom = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||
qInfo() << "CoInitializeEx STA result:" << Qt::hex << hrCom;
|
||||
|
||||
auto hr = DesktopNotificationManagerCompat::CreateStartMenuShortcut(mAumid, __uuidof(NotificationActivator));
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << "CreateStartMenuShortcut failed:" << Qt::hex << hr;
|
||||
}
|
||||
|
||||
// Register AUMID and COM server (for a packaged app, this is a no-operation)
|
||||
hr = DesktopNotificationManagerCompat::RegisterAumidAndComServer(L"Linphone", __uuidof(NotificationActivator));
|
||||
auto hr = DesktopNotificationManagerCompat::RegisterAumidAndComServer(mAumid, __uuidof(NotificationActivator));
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << "RegisterAumidAndComServer failed:" << Qt::hex << hr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,15 +46,19 @@
|
|||
#include <QClipboard>
|
||||
#include <QCryptographicHash>
|
||||
#include <QDesktopServices>
|
||||
#include <QFileInfo>
|
||||
#include <QHostAddress>
|
||||
#include <QImageReader>
|
||||
#include <QMimeDatabase>
|
||||
#include <QPainter>
|
||||
#include <QProcess>
|
||||
#include <QQmlComponent>
|
||||
#include <QQmlProperty>
|
||||
#include <QQuickWindow>
|
||||
#include <QRandomGenerator>
|
||||
#include <QRegularExpression>
|
||||
#include <QStandardPaths>
|
||||
#include <QSvgRenderer>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#ifndef NOMINMAX
|
||||
|
|
@ -1815,6 +1819,29 @@ QUrl Utils::getAppIcon(const QString &iconName) {
|
|||
return QQmlProperty::read(appIconsSingleton, iconName).value<QUrl>();
|
||||
}
|
||||
|
||||
QString Utils::getIconAsPng(const QString &imagePath, const QSize &size) {
|
||||
// Convertit "image://internal/phone-disconnect.svg" en ":/data/image/phone-disconnect.svg"
|
||||
QString resourcePath = imagePath;
|
||||
if (imagePath.startsWith("image://internal/"))
|
||||
resourcePath = ":/data/image/" + imagePath.mid(QString("image://internal/").length());
|
||||
|
||||
QSvgRenderer renderer(resourcePath);
|
||||
if (!renderer.isValid()) return QString();
|
||||
|
||||
QImage image(size, QImage::Format_ARGB32_Premultiplied);
|
||||
image.fill(Qt::transparent);
|
||||
QPainter painter(&image);
|
||||
renderer.render(&painter);
|
||||
painter.end();
|
||||
|
||||
QString outPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/linphone_" +
|
||||
QFileInfo(resourcePath).baseName() + ".png";
|
||||
|
||||
if (!QFile::exists(outPath)) image.save(outPath, "PNG");
|
||||
|
||||
return outPath;
|
||||
}
|
||||
|
||||
QColor Utils::getPresenceColor(LinphoneEnums::Presence presence) {
|
||||
mustBeInMainThread(sLog().arg(Q_FUNC_INFO));
|
||||
QColor presenceColor = QColorConstants::Transparent;
|
||||
|
|
|
|||
|
|
@ -254,6 +254,7 @@ public:
|
|||
|
||||
// Presence
|
||||
|
||||
static QString getIconAsPng(const QString &imagePath, const QSize &size = QSize(64, 64));
|
||||
static QColor getDefaultStyleColor(const QString &colorName);
|
||||
static QUrl getAppIcon(const QString &iconName);
|
||||
static QUrl getRegistrationStateIcon(LinphoneEnums::RegistrationState state);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue