Notification improvements.
This commit is contained in:
parent
a0fcd00a6f
commit
bb069197d6
|
@ -1,5 +1,5 @@
|
|||
import QtQuick 2.9
|
||||
|
||||
RoomForm {
|
||||
roomListModel.onNewMessage: if (!window.visible) spectralController.showMessage(roomName, content, icon)
|
||||
roomListModel.onNewMessage: if (!window.visible) spectralController.postNotification(roomId, eventId, roomName, senderName, text, icon)
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ Page {
|
|||
property alias filter: roomListForm.filter
|
||||
|
||||
property alias roomListModel: roomListModel
|
||||
property alias enteredRoom: roomListForm.enteredRoom
|
||||
|
||||
id: page
|
||||
|
||||
|
|
|
@ -36,6 +36,12 @@ Rectangle {
|
|||
}
|
||||
|
||||
onClicked: currentRoom.chooseAndUploadFile()
|
||||
|
||||
BusyIndicator {
|
||||
anchors.fill: parent
|
||||
|
||||
running: false
|
||||
}
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
|
|
|
@ -38,6 +38,10 @@ ApplicationWindow {
|
|||
window.requestActivate()
|
||||
}
|
||||
onHideWindow: window.hide()
|
||||
onNotificationClicked: {
|
||||
roomPage.enteredRoom = currentConnection.room(roomId)
|
||||
showWindow()
|
||||
}
|
||||
onErrorOccured: {
|
||||
errorDialog.error = error
|
||||
errorDialog.detail = detail
|
||||
|
|
61
spectral.pro
61
spectral.pro
|
@ -1,4 +1,4 @@
|
|||
QT += quick widgets multimedia
|
||||
QT += quick widgets multimedia dbus
|
||||
CONFIG += c++14
|
||||
CONFIG += object_parallel_to_source
|
||||
CONFIG += link_pkgconfig
|
||||
|
@ -36,18 +36,6 @@ DEFINES += QT_DEPRECATED_WARNINGS
|
|||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
SOURCES += src/main.cpp \
|
||||
src/controller.cpp \
|
||||
src/roomlistmodel.cpp \
|
||||
src/imageprovider.cpp \
|
||||
src/messageeventmodel.cpp \
|
||||
src/emojimodel.cpp \
|
||||
src/spectralroom.cpp \
|
||||
src/userlistmodel.cpp \
|
||||
src/imageitem.cpp \
|
||||
src/accountlistmodel.cpp \
|
||||
src/spectraluser.cpp
|
||||
|
||||
RESOURCES += \
|
||||
res.qrc
|
||||
|
||||
|
@ -85,13 +73,40 @@ mac {
|
|||
}
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/src/controller.h \
|
||||
$$PWD/src/roomlistmodel.h \
|
||||
$$PWD/src/imageprovider.h \
|
||||
$$PWD/src/messageeventmodel.h \
|
||||
$$PWD/src/emojimodel.h \
|
||||
$$PWD/src/spectralroom.h \
|
||||
$$PWD/src/userlistmodel.h \
|
||||
$$PWD/src/imageitem.h \
|
||||
$$PWD/src/accountlistmodel.h \
|
||||
$$PWD/src/spectraluser.h
|
||||
src/controller.h \
|
||||
src/roomlistmodel.h \
|
||||
src/imageprovider.h \
|
||||
src/messageeventmodel.h \
|
||||
src/emojimodel.h \
|
||||
src/spectralroom.h \
|
||||
src/userlistmodel.h \
|
||||
src/imageitem.h \
|
||||
src/accountlistmodel.h \
|
||||
src/spectraluser.h \
|
||||
src/notifications/manager.h
|
||||
|
||||
SOURCES += src/main.cpp \
|
||||
src/controller.cpp \
|
||||
src/roomlistmodel.cpp \
|
||||
src/imageprovider.cpp \
|
||||
src/messageeventmodel.cpp \
|
||||
src/emojimodel.cpp \
|
||||
src/spectralroom.cpp \
|
||||
src/userlistmodel.cpp \
|
||||
src/imageitem.cpp \
|
||||
src/accountlistmodel.cpp \
|
||||
src/spectraluser.cpp
|
||||
|
||||
unix:!mac {
|
||||
SOURCES += src/notifications/managerlinux.cpp
|
||||
}
|
||||
|
||||
win32 {
|
||||
HEADERS += src/notifications/wintoastlib.h
|
||||
SOURCES += src/notifications/managerwin.cpp \
|
||||
src/notifications/wintoastlib.cpp
|
||||
}
|
||||
|
||||
mac {
|
||||
SOURCES += src/notifications/managermac.mm
|
||||
}
|
||||
|
|
|
@ -27,18 +27,20 @@
|
|||
#include <QtNetwork/QAuthenticator>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
||||
Controller::Controller(QObject* parent) : QObject(parent) {
|
||||
tray->setIcon(QIcon(":/assets/img/icon.png"));
|
||||
tray->setToolTip("Spectral");
|
||||
connect(tray, &QSystemTrayIcon::activated,
|
||||
Controller::Controller(QObject* parent)
|
||||
: QObject(parent), tray(this), notificationsManager(this) {
|
||||
connect(¬ificationsManager, &NotificationsManager::notificationClicked,
|
||||
this, &Controller::notificationClicked);
|
||||
tray.setIcon(QIcon(":/assets/img/icon.png"));
|
||||
tray.setToolTip("Spectral");
|
||||
connect(&tray, &QSystemTrayIcon::activated,
|
||||
[this](QSystemTrayIcon::ActivationReason r) {
|
||||
if (r != QSystemTrayIcon::Context) emit showWindow();
|
||||
});
|
||||
connect(tray, &QSystemTrayIcon::messageClicked, [=] { emit showWindow(); });
|
||||
trayMenu->addAction("Hide Window", [=] { emit hideWindow(); });
|
||||
trayMenu->addAction("Quit", [=] { QApplication::quit(); });
|
||||
tray->setContextMenu(trayMenu);
|
||||
tray->show();
|
||||
trayMenu.addAction("Hide Window", [=] { emit hideWindow(); });
|
||||
trayMenu.addAction("Quit", [=] { QApplication::quit(); });
|
||||
tray.setContextMenu(&trayMenu);
|
||||
tray.show();
|
||||
|
||||
Connection::setRoomType<SpectralRoom>();
|
||||
Connection::setUserType<SpectralUser>();
|
||||
|
@ -226,11 +228,6 @@ void Controller::playAudio(QUrl localFile) {
|
|||
connect(player, &QMediaPlayer::stateChanged, [=] { player->deleteLater(); });
|
||||
}
|
||||
|
||||
void Controller::showMessage(const QString& title, const QString& msg,
|
||||
const QIcon& icon) {
|
||||
tray->showMessage(title, msg, icon);
|
||||
}
|
||||
|
||||
QImage Controller::safeImage(QImage image) {
|
||||
if (image.isNull()) return QImage();
|
||||
return image;
|
||||
|
@ -243,3 +240,11 @@ QColor Controller::color(QString userId) {
|
|||
void Controller::setColor(QString userId, QColor newColor) {
|
||||
SettingsGroup("UI/Color").setValue(userId, newColor.name());
|
||||
}
|
||||
|
||||
void Controller::postNotification(const QString& roomId, const QString& eventId,
|
||||
const QString& roomName,
|
||||
const QString& senderName,
|
||||
const QString& text, const QImage& icon) {
|
||||
notificationsManager.postNotification(roomId, eventId, roomName, senderName,
|
||||
text, icon);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define CONTROLLER_H
|
||||
|
||||
#include "connection.h"
|
||||
#include "notifications/manager.h"
|
||||
#include "settings.h"
|
||||
#include "user.h"
|
||||
|
||||
|
@ -39,8 +40,9 @@ class Controller : public QObject {
|
|||
|
||||
private:
|
||||
QClipboard* m_clipboard = QApplication::clipboard();
|
||||
QSystemTrayIcon* tray = new QSystemTrayIcon();
|
||||
QMenu* trayMenu = new QMenu();
|
||||
QSystemTrayIcon tray;
|
||||
QMenu trayMenu;
|
||||
NotificationsManager notificationsManager;
|
||||
QVector<Connection*> m_connections;
|
||||
|
||||
QByteArray loadAccessToken(const AccountSettings& account);
|
||||
|
@ -60,6 +62,7 @@ class Controller : public QObject {
|
|||
void connectionAdded(Connection* conn);
|
||||
void connectionDropped(Connection* conn);
|
||||
void initiated();
|
||||
void notificationClicked(const QString roomId, const QString eventId);
|
||||
|
||||
public slots:
|
||||
void logout(Connection* conn);
|
||||
|
@ -68,7 +71,9 @@ class Controller : public QObject {
|
|||
void createDirectChat(Connection* c, const QString& userID);
|
||||
void copyToClipboard(const QString& text);
|
||||
void playAudio(QUrl localFile);
|
||||
void showMessage(const QString& title, const QString& msg, const QIcon& icon);
|
||||
void postNotification(const QString& roomId, const QString& eventId,
|
||||
const QString& roomName, const QString& senderName,
|
||||
const QString& text, const QImage& icon);
|
||||
|
||||
static QImage safeImage(QImage image);
|
||||
};
|
||||
|
|
|
@ -49,8 +49,9 @@ int main(int argc, char *argv[]) {
|
|||
qmlRegisterUncreatableType<RoomType>("Spectral", 0, 1, "RoomType", "ENUM");
|
||||
|
||||
qRegisterMetaType<User *>("User*");
|
||||
qRegisterMetaType<Room *>("Room*");
|
||||
qRegisterMetaType<MessageEventType>("MessageEventType");
|
||||
qRegisterMetaType<SpectralRoom *>("SpectralRoom");
|
||||
qRegisterMetaType<SpectralRoom *>("SpectralRoom*");
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
#pragma once
|
||||
|
||||
#include <QImage>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
#include <QtDBus/QDBusArgument>
|
||||
#include <QtDBus/QDBusInterface>
|
||||
#endif
|
||||
|
||||
struct roomEventId {
|
||||
QString roomId;
|
||||
QString eventId;
|
||||
};
|
||||
|
||||
class NotificationsManager : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
NotificationsManager(QObject *parent = nullptr);
|
||||
|
||||
void postNotification(const QString &roomId, const QString &eventId,
|
||||
const QString &roomName, const QString &senderName,
|
||||
const QString &text, const QImage &icon);
|
||||
|
||||
signals:
|
||||
void notificationClicked(const QString roomId, const QString eventId);
|
||||
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
private:
|
||||
QDBusInterface dbus;
|
||||
uint showNotification(const QString summary, const QString text,
|
||||
const QImage image);
|
||||
|
||||
// notification ID to (room ID, event ID)
|
||||
QMap<uint, roomEventId> notificationIds;
|
||||
#endif
|
||||
|
||||
// these slots are platform specific (D-Bus only)
|
||||
// but Qt slot declarations can not be inside an ifdef!
|
||||
private slots:
|
||||
void actionInvoked(uint id, QString action);
|
||||
void notificationClosed(uint id, uint reason);
|
||||
};
|
||||
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
QDBusArgument &operator<<(QDBusArgument &arg, const QImage &image);
|
||||
const QDBusArgument &operator>>(const QDBusArgument &arg, QImage &);
|
||||
#endif
|
|
@ -0,0 +1,133 @@
|
|||
#include "manager.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QImage>
|
||||
#include <QtDBus/QDBusConnection>
|
||||
#include <QtDBus/QDBusMessage>
|
||||
#include <QtDBus/QDBusMetaType>
|
||||
|
||||
NotificationsManager::NotificationsManager(QObject *parent)
|
||||
: QObject(parent),
|
||||
dbus("org.freedesktop.Notifications", "/org/freedesktop/Notifications",
|
||||
"org.freedesktop.Notifications", QDBusConnection::sessionBus(),
|
||||
this) {
|
||||
qDBusRegisterMetaType<QImage>();
|
||||
|
||||
QDBusConnection::sessionBus().connect(
|
||||
"org.freedesktop.Notifications", "/org/freedesktop/Notifications",
|
||||
"org.freedesktop.Notifications", "ActionInvoked", this,
|
||||
SLOT(actionInvoked(uint, QString)));
|
||||
QDBusConnection::sessionBus().connect(
|
||||
"org.freedesktop.Notifications", "/org/freedesktop/Notifications",
|
||||
"org.freedesktop.Notifications", "NotificationClosed", this,
|
||||
SLOT(notificationClosed(uint, uint)));
|
||||
}
|
||||
|
||||
void NotificationsManager::postNotification(
|
||||
const QString &roomid, const QString &eventid, const QString &roomname,
|
||||
const QString &sender, const QString &text, const QImage &icon) {
|
||||
uint id = showNotification(roomname, sender + ": " + text, icon);
|
||||
notificationIds[id] = roomEventId{roomid, eventid};
|
||||
}
|
||||
/**
|
||||
* This function is based on code from
|
||||
* https://github.com/rohieb/StratumsphereTrayIcon
|
||||
* Copyright (C) 2012 Roland Hieber <rohieb@rohieb.name>
|
||||
* Licensed under the GNU General Public License, version 3
|
||||
*/
|
||||
uint NotificationsManager::showNotification(const QString summary,
|
||||
const QString text,
|
||||
const QImage image) {
|
||||
QVariantMap hints;
|
||||
hints["image-data"] = image;
|
||||
QList<QVariant> argumentList;
|
||||
argumentList << "Spectral"; // app_name
|
||||
argumentList << uint(0); // replace_id
|
||||
argumentList << ""; // app_icon
|
||||
argumentList << summary; // summary
|
||||
argumentList << text; // body
|
||||
argumentList << (QStringList("default") << "reply"); // actions
|
||||
argumentList << hints; // hints
|
||||
argumentList << int(-1); // timeout in ms
|
||||
|
||||
static QDBusInterface notifyApp("org.freedesktop.Notifications",
|
||||
"/org/freedesktop/Notifications",
|
||||
"org.freedesktop.Notifications");
|
||||
QDBusMessage reply =
|
||||
notifyApp.callWithArgumentList(QDBus::AutoDetect, "Notify", argumentList);
|
||||
if (reply.type() == QDBusMessage::ErrorMessage) {
|
||||
qDebug() << "D-Bus Error:" << reply.errorMessage();
|
||||
return 0;
|
||||
} else {
|
||||
return reply.arguments().first().toUInt();
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationsManager::actionInvoked(uint id, QString action) {
|
||||
if (action == "default" && notificationIds.contains(id)) {
|
||||
roomEventId idEntry = notificationIds[id];
|
||||
emit notificationClicked(idEntry.roomId, idEntry.eventId);
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationsManager::notificationClosed(uint id, uint reason) {
|
||||
Q_UNUSED(reason);
|
||||
notificationIds.remove(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatic marshaling of a QImage for org.freedesktop.Notifications.Notify
|
||||
*
|
||||
* This function is from the Clementine project (see
|
||||
* http://www.clementine-player.org) and licensed under the GNU General Public
|
||||
* License, version 3 or later.
|
||||
*
|
||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
*/
|
||||
QDBusArgument &operator<<(QDBusArgument &arg, const QImage &image) {
|
||||
if (image.isNull()) {
|
||||
arg.beginStructure();
|
||||
arg << 0 << 0 << 0 << false << 0 << 0 << QByteArray();
|
||||
arg.endStructure();
|
||||
return arg;
|
||||
}
|
||||
|
||||
QImage scaled = image.scaledToHeight(100, Qt::SmoothTransformation);
|
||||
scaled = scaled.convertToFormat(QImage::Format_ARGB32);
|
||||
|
||||
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
|
||||
// ABGR -> ARGB
|
||||
QImage i = scaled.rgbSwapped();
|
||||
#else
|
||||
// ABGR -> GBAR
|
||||
QImage i(scaled.size(), scaled.format());
|
||||
for (int y = 0; y < i.height(); ++y) {
|
||||
QRgb *p = (QRgb *)scaled.scanLine(y);
|
||||
QRgb *q = (QRgb *)i.scanLine(y);
|
||||
QRgb *end = p + scaled.width();
|
||||
while (p < end) {
|
||||
*q = qRgba(qGreen(*p), qBlue(*p), qAlpha(*p), qRed(*p));
|
||||
p++;
|
||||
q++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
arg.beginStructure();
|
||||
arg << i.width();
|
||||
arg << i.height();
|
||||
arg << i.bytesPerLine();
|
||||
arg << i.hasAlphaChannel();
|
||||
int channels = i.isGrayscale() ? 1 : (i.hasAlphaChannel() ? 4 : 3);
|
||||
arg << i.depth() / channels;
|
||||
arg << channels;
|
||||
arg << QByteArray(reinterpret_cast<const char *>(i.bits()), i.sizeInBytes());
|
||||
arg.endStructure();
|
||||
return arg;
|
||||
}
|
||||
|
||||
const QDBusArgument &operator>>(const QDBusArgument &arg, QImage &) {
|
||||
// This is needed to link but shouldn't be called.
|
||||
Q_ASSERT(0);
|
||||
return arg;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#include "manager.h"
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
#include <QtMac>
|
||||
|
||||
@interface NSUserNotification (CFIPrivate)
|
||||
- (void)set_identityImage:(NSImage *)image;
|
||||
@end
|
||||
|
||||
NotificationsManager::NotificationsManager(QObject *parent) : QObject(parent) {}
|
||||
|
||||
void NotificationsManager::postNotification(const QString &roomId, const QString &eventId,
|
||||
const QString &roomName, const QString &senderName,
|
||||
const QString &text, const QImage &icon) {
|
||||
Q_UNUSED(roomId);
|
||||
Q_UNUSED(eventId);
|
||||
Q_UNUSED(icon);
|
||||
|
||||
NSUserNotification *notif = [[NSUserNotification alloc] init];
|
||||
|
||||
notif.title = roomName.toNSString();
|
||||
notif.subtitle = QString("%1 sent a message").arg(senderName).toNSString();
|
||||
notif.informativeText = text.toNSString();
|
||||
notif.soundName = NSUserNotificationDefaultSoundName;
|
||||
|
||||
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notif];
|
||||
[notif autorelease];
|
||||
}
|
||||
|
||||
// unused
|
||||
void NotificationsManager::actionInvoked(uint, QString) {}
|
||||
|
||||
void NotificationsManager::notificationClosed(uint, uint) {}
|
|
@ -0,0 +1,59 @@
|
|||
#include "manager.h"
|
||||
#include "wintoastlib.h"
|
||||
|
||||
using namespace WinToastLib;
|
||||
|
||||
class CustomHandler : public IWinToastHandler {
|
||||
public:
|
||||
void toastActivated() const {}
|
||||
void toastActivated(int) const {}
|
||||
void toastFailed() const {
|
||||
std::wcout << L"Error showing current toast" << std::endl;
|
||||
}
|
||||
void toastDismissed(WinToastDismissalReason) const {}
|
||||
};
|
||||
|
||||
namespace {
|
||||
bool isInitialized = false;
|
||||
|
||||
void init() {
|
||||
isInitialized = true;
|
||||
|
||||
WinToast::instance()->setAppName(L"Spectral");
|
||||
WinToast::instance()->setAppUserModelId(
|
||||
WinToast::configureAUMI(L"Spectral", L"Spectral"));
|
||||
if (!WinToast::instance()->initialize())
|
||||
std::wcout << "Your system in not compatible with toast notifications\n";
|
||||
}
|
||||
} // namespace
|
||||
|
||||
NotificationsManager::NotificationsManager(QObject *parent) : QObject(parent) {}
|
||||
|
||||
void NotificationsManager::postNotification(
|
||||
const QString &room_id, const QString &event_id, const QString &room_name,
|
||||
const QString &sender, const QString &text, const QImage &icon) {
|
||||
Q_UNUSED(room_id)
|
||||
Q_UNUSED(event_id)
|
||||
Q_UNUSED(icon)
|
||||
|
||||
if (!isInitialized) init();
|
||||
|
||||
auto templ = WinToastTemplate(WinToastTemplate::ImageAndText02);
|
||||
if (room_name != sender)
|
||||
templ.setTextField(
|
||||
QString("%1 - %2").arg(sender).arg(room_name).toStdWString(),
|
||||
WinToastTemplate::FirstLine);
|
||||
else
|
||||
templ.setTextField(QString("%1").arg(sender).toStdWString(),
|
||||
WinToastTemplate::FirstLine);
|
||||
templ.setTextField(QString("%1").arg(text).toStdWString(),
|
||||
WinToastTemplate::SecondLine);
|
||||
// TODO: implement room or user avatar
|
||||
// templ.setImagePath(L"C:/example.png");
|
||||
|
||||
WinToast::instance()->showToast(templ, new CustomHandler());
|
||||
}
|
||||
|
||||
void NotificationsManager::actionInvoked(uint, QString) {}
|
||||
|
||||
void NotificationsManager::notificationClosed(uint, uint) {}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,164 @@
|
|||
#ifndef WINTOASTLIB_H
|
||||
#define WINTOASTLIB_H
|
||||
#include <Windows.h>
|
||||
#include <sdkddkver.h>
|
||||
#include <WinUser.h>
|
||||
#include <ShObjIdl.h>
|
||||
#include <wrl/implements.h>
|
||||
#include <wrl/event.h>
|
||||
#include <windows.ui.notifications.h>
|
||||
#include <strsafe.h>
|
||||
#include <Psapi.h>
|
||||
#include <ShlObj.h>
|
||||
#include <roapi.h>
|
||||
#include <propvarutil.h>
|
||||
#include <functiondiscoverykeys.h>
|
||||
#include <iostream>
|
||||
#include <winstring.h>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace ABI::Windows::Data::Xml::Dom;
|
||||
using namespace ABI::Windows::Foundation;
|
||||
using namespace ABI::Windows::UI::Notifications;
|
||||
using namespace Windows::Foundation;
|
||||
|
||||
#define DEFAULT_SHELL_LINKS_PATH L"\\Microsoft\\Windows\\Start Menu\\Programs\\"
|
||||
#define DEFAULT_LINK_FORMAT L".lnk"
|
||||
namespace WinToastLib {
|
||||
|
||||
class IWinToastHandler {
|
||||
public:
|
||||
enum WinToastDismissalReason {
|
||||
UserCanceled = ToastDismissalReason::ToastDismissalReason_UserCanceled,
|
||||
ApplicationHidden = ToastDismissalReason::ToastDismissalReason_ApplicationHidden,
|
||||
TimedOut = ToastDismissalReason::ToastDismissalReason_TimedOut
|
||||
};
|
||||
virtual ~IWinToastHandler() {}
|
||||
virtual void toastActivated() const = 0;
|
||||
virtual void toastActivated(int actionIndex) const = 0;
|
||||
virtual void toastDismissed(WinToastDismissalReason state) const = 0;
|
||||
virtual void toastFailed() const = 0;
|
||||
};
|
||||
|
||||
class WinToastTemplate {
|
||||
public:
|
||||
enum Duration { System, Short, Long };
|
||||
enum AudioOption { Default = 0, Silent = 1, Loop = 2 };
|
||||
enum TextField { FirstLine = 0, SecondLine, ThirdLine };
|
||||
enum WinToastTemplateType {
|
||||
ImageAndText01 = ToastTemplateType::ToastTemplateType_ToastImageAndText01,
|
||||
ImageAndText02 = ToastTemplateType::ToastTemplateType_ToastImageAndText02,
|
||||
ImageAndText03 = ToastTemplateType::ToastTemplateType_ToastImageAndText03,
|
||||
ImageAndText04 = ToastTemplateType::ToastTemplateType_ToastImageAndText04,
|
||||
Text01 = ToastTemplateType::ToastTemplateType_ToastText01,
|
||||
Text02 = ToastTemplateType::ToastTemplateType_ToastText02,
|
||||
Text03 = ToastTemplateType::ToastTemplateType_ToastText03,
|
||||
Text04 = ToastTemplateType::ToastTemplateType_ToastText04,
|
||||
WinToastTemplateTypeCount
|
||||
};
|
||||
|
||||
WinToastTemplate(_In_ WinToastTemplateType type = WinToastTemplateType::ImageAndText02);
|
||||
~WinToastTemplate();
|
||||
|
||||
void setTextField(_In_ const std::wstring& txt, _In_ TextField pos);
|
||||
void setImagePath(_In_ const std::wstring& imgPath);
|
||||
void setAudioPath(_In_ const std::wstring& audioPath);
|
||||
void setAttributionText(_In_ const std::wstring & attributionText);
|
||||
void addAction(_In_ const std::wstring& label);
|
||||
void setAudioOption(_In_ WinToastTemplate::AudioOption audioOption);
|
||||
void setDuration(_In_ Duration duration);
|
||||
void setExpiration(_In_ INT64 millisecondsFromNow);
|
||||
std::size_t textFieldsCount() const;
|
||||
std::size_t actionsCount() const;
|
||||
bool hasImage() const;
|
||||
const std::vector<std::wstring>& textFields() const;
|
||||
const std::wstring& textField(_In_ TextField pos) const;
|
||||
const std::wstring& actionLabel(_In_ int pos) const;
|
||||
const std::wstring& imagePath() const;
|
||||
const std::wstring& audioPath() const;
|
||||
const std::wstring& attributionText() const;
|
||||
INT64 expiration() const;
|
||||
WinToastTemplateType type() const;
|
||||
WinToastTemplate::AudioOption audioOption() const;
|
||||
Duration duration() const;
|
||||
private:
|
||||
std::vector<std::wstring> _textFields;
|
||||
std::vector<std::wstring> _actions;
|
||||
std::wstring _imagePath = L"";
|
||||
std::wstring _audioPath = L"";
|
||||
std::wstring _attributionText = L"";
|
||||
INT64 _expiration = 0;
|
||||
AudioOption _audioOption = WinToastTemplate::AudioOption::Default;
|
||||
WinToastTemplateType _type = WinToastTemplateType::Text01;
|
||||
Duration _duration = Duration::System;
|
||||
};
|
||||
|
||||
class WinToast {
|
||||
public:
|
||||
enum WinToastError {
|
||||
NoError = 0,
|
||||
NotInitialized,
|
||||
SystemNotSupported,
|
||||
ShellLinkNotCreated,
|
||||
InvalidAppUserModelID,
|
||||
InvalidParameters,
|
||||
InvalidHandler,
|
||||
NotDisplayed,
|
||||
UnknownError
|
||||
};
|
||||
|
||||
enum ShortcutResult {
|
||||
SHORTCUT_UNCHANGED = 0,
|
||||
SHORTCUT_WAS_CHANGED = 1,
|
||||
SHORTCUT_WAS_CREATED = 2,
|
||||
|
||||
SHORTCUT_MISSING_PARAMETERS = -1,
|
||||
SHORTCUT_INCOMPATIBLE_OS = -2,
|
||||
SHORTCUT_COM_INIT_FAILURE = -3,
|
||||
SHORTCUT_CREATE_FAILED = -4
|
||||
};
|
||||
|
||||
WinToast(void);
|
||||
virtual ~WinToast();
|
||||
static WinToast* instance();
|
||||
static bool isCompatible();
|
||||
static bool isSupportingModernFeatures();
|
||||
static std::wstring configureAUMI(_In_ const std::wstring& companyName,
|
||||
_In_ const std::wstring& productName,
|
||||
_In_ const std::wstring& subProduct = std::wstring(),
|
||||
_In_ const std::wstring& versionInformation = std::wstring()
|
||||
);
|
||||
virtual bool initialize(_Out_ WinToastError* error = nullptr);
|
||||
virtual bool isInitialized() const;
|
||||
virtual bool hideToast(_In_ INT64 id);
|
||||
virtual INT64 showToast(_In_ const WinToastTemplate& toast, _In_ IWinToastHandler* handler, _Out_ WinToastError* error = nullptr);
|
||||
virtual void clear();
|
||||
virtual enum ShortcutResult createShortcut();
|
||||
|
||||
const std::wstring& appName() const;
|
||||
const std::wstring& appUserModelId() const;
|
||||
void setAppUserModelId(_In_ const std::wstring& appName);
|
||||
void setAppName(_In_ const std::wstring& appName);
|
||||
|
||||
protected:
|
||||
bool _isInitialized;
|
||||
bool _hasCoInitialized;
|
||||
std::wstring _appName;
|
||||
std::wstring _aumi;
|
||||
std::map<INT64, ComPtr<IToastNotification>> _buffer;
|
||||
|
||||
HRESULT validateShellLinkHelper(_Out_ bool& wasChanged);
|
||||
HRESULT createShellLinkHelper();
|
||||
HRESULT setImageFieldHelper(_In_ IXmlDocument *xml, _In_ const std::wstring& path);
|
||||
HRESULT setAudioFieldHelper(_In_ IXmlDocument *xml, _In_ const std::wstring& path, _In_opt_ WinToastTemplate::AudioOption option = WinToastTemplate::AudioOption::Default);
|
||||
HRESULT setTextFieldHelper(_In_ IXmlDocument *xml, _In_ const std::wstring& text, _In_ int pos);
|
||||
HRESULT setAttributionTextFieldHelper(_In_ IXmlDocument *xml, _In_ const std::wstring& text);
|
||||
HRESULT addActionHelper(_In_ IXmlDocument *xml, _In_ const std::wstring& action, _In_ const std::wstring& arguments);
|
||||
HRESULT addDurationHelper(_In_ IXmlDocument *xml, _In_ const std::wstring& duration);
|
||||
ComPtr<IToastNotifier> notifier(_In_ bool* succeded) const;
|
||||
void setError(_Out_ WinToastError* error, _In_ WinToastError value);
|
||||
};
|
||||
}
|
||||
#endif // WINTOASTLIB_H
|
|
@ -80,10 +80,10 @@ void RoomListModel::connectRoomSignals(SpectralRoom* room) {
|
|||
if (event->isStateEvent()) return;
|
||||
User* sender = room->user(event->senderId());
|
||||
if (sender == room->localUser()) return;
|
||||
emit newMessage(room->displayName(),
|
||||
sender->displayname() + ": " +
|
||||
event->contentJson().value("body").toString(),
|
||||
QPixmap::fromImage(room->avatar(64)));
|
||||
emit newMessage(room->id(), event->id(), room->displayName(),
|
||||
sender->displayname(),
|
||||
event->contentJson().value("body").toString(),
|
||||
room->avatar(64));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -74,8 +74,9 @@ class RoomListModel : public QAbstractListModel {
|
|||
signals:
|
||||
void connectionChanged();
|
||||
void roomAdded(SpectralRoom* room);
|
||||
void newMessage(const QString& roomName, const QString& content,
|
||||
const QIcon& icon);
|
||||
void newMessage(const QString& roomId, const QString& eventId,
|
||||
const QString& roomName, const QString& senderName,
|
||||
const QString& text, const QImage& icon);
|
||||
};
|
||||
|
||||
#endif // ROOMLISTMODEL_H
|
||||
|
|
Loading…
Reference in New Issue