mirror of https://github.com/cutefishos/core
Add notification window
parent
d5b02178fd
commit
4b627ab25b
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: Reion Wong <reion@cutefishos.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "application.h"
|
||||
#include "notificationsmodel.h"
|
||||
#include "screenhelper.h"
|
||||
#include "notificationadaptor.h"
|
||||
#include "historymodel.h"
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusPendingCall>
|
||||
#include <QDBusConnection>
|
||||
#include <QPixmapCache>
|
||||
#include <QTranslator>
|
||||
#include <QFileInfo>
|
||||
#include <QIcon>
|
||||
#include <QDir>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
Application::Application(int& argc, char** argv)
|
||||
: QApplication(argc, argv)
|
||||
, m_notificationServer(NotificationServer::self())
|
||||
, m_model(NotificationsModel::self())
|
||||
, m_window(nullptr)
|
||||
, m_instance(false)
|
||||
{
|
||||
if (QDBusConnection::sessionBus().registerService("com.cutefish.Notification")) {
|
||||
setOrganizationName("cutefishos");
|
||||
|
||||
// Translations
|
||||
QLocale locale;
|
||||
QString qmFilePath = QString("%1/%2.qm").arg("/usr/share/cutefish-notificationd/translations/").arg(locale.name());
|
||||
if (QFile::exists(qmFilePath)) {
|
||||
QTranslator *translator = new QTranslator(this);
|
||||
if (translator->load(qmFilePath)) {
|
||||
installTranslator(translator);
|
||||
} else {
|
||||
translator->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
new NotificationAdaptor(this);
|
||||
QDBusConnection::sessionBus().registerObject("/Notification", this);
|
||||
|
||||
qmlRegisterType<NotificationsModel>("Cutefish.Notification", 1, 0, "NotificationsModel");
|
||||
qmlRegisterType<HistoryModel>("Cutefish.Notification", 1, 0, "HistoryModel");
|
||||
qmlRegisterType<ScreenHelper>("Cutefish.Notification", 1, 0, "ScreenHelper");
|
||||
|
||||
m_instance = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Application::showWindow()
|
||||
{
|
||||
if (m_window)
|
||||
m_window->open();
|
||||
}
|
||||
|
||||
int Application::run()
|
||||
{
|
||||
if (!parseCommandLineArgs())
|
||||
return 0;
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
engine.rootContext()->setContextProperty("notificationsModel", m_model);
|
||||
engine.load(QUrl("qrc:/qml/main.qml"));
|
||||
|
||||
m_window = new NotificationWindow;
|
||||
|
||||
return QApplication::exec();
|
||||
}
|
||||
|
||||
bool Application::parseCommandLineArgs()
|
||||
{
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(QStringLiteral("Notification"));
|
||||
parser.addHelpOption();
|
||||
|
||||
QCommandLineOption showOption(QStringList() << "s" << "show" << "Show dialog");
|
||||
parser.addOption(showOption);
|
||||
|
||||
parser.process(arguments());
|
||||
|
||||
if (m_instance) {
|
||||
QPixmapCache::setCacheLimit(2048);
|
||||
} else {
|
||||
QDBusInterface iface("com.cutefish.Notification",
|
||||
"/Notification",
|
||||
"com.cutefish.Notification",
|
||||
QDBusConnection::sessionBus(), this);
|
||||
if (iface.isValid() && parser.isSet(showOption)) {
|
||||
iface.call("showWindow");
|
||||
}
|
||||
}
|
||||
|
||||
return m_instance;
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: Reion Wong <reion@cutefishos.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef APPLICATION_H
|
||||
#define APPLICATION_H
|
||||
|
||||
#include <QApplication>
|
||||
#include "notificationwindow.h"
|
||||
|
||||
class NotificationServer;
|
||||
class NotificationsModel;
|
||||
class Application : public QApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Application(int& argc, char** argv);
|
||||
|
||||
void showWindow();
|
||||
|
||||
int run();
|
||||
bool parseCommandLineArgs();
|
||||
|
||||
private:
|
||||
NotificationServer *m_notificationServer;
|
||||
NotificationsModel *m_model;
|
||||
NotificationWindow *m_window;
|
||||
bool m_instance;
|
||||
};
|
||||
|
||||
#endif // APPLICATION_H
|
||||
@ -0,0 +1,6 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="com.cutefish.Notification">
|
||||
<method name="showWindow"></method>
|
||||
</interface>
|
||||
</node>
|
||||
@ -0,0 +1,130 @@
|
||||
#include "historymodel.h"
|
||||
|
||||
#include <QSettings>
|
||||
#include <QDataStream>
|
||||
#include <QMetaEnum>
|
||||
|
||||
static HistoryModel *s_historyModel = nullptr;
|
||||
|
||||
HistoryModel *HistoryModel::self()
|
||||
{
|
||||
if (!s_historyModel)
|
||||
s_historyModel = new HistoryModel;
|
||||
|
||||
return s_historyModel;
|
||||
}
|
||||
|
||||
HistoryModel::HistoryModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
initDatas();
|
||||
}
|
||||
|
||||
QVariant HistoryModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
const Notification ¬ification = m_notifications.at(index.row());
|
||||
|
||||
switch (role) {
|
||||
case HistoryModel::IdRole:
|
||||
return notification.id;
|
||||
case HistoryModel::SummaryRole:
|
||||
return notification.summary;
|
||||
case HistoryModel::ImageRole:
|
||||
return "";
|
||||
case HistoryModel::CreatedRole:
|
||||
return notification.created;
|
||||
case HistoryModel::BodyRole:
|
||||
return notification.body;
|
||||
case HistoryModel::IconNameRole:
|
||||
return notification.appIcon;
|
||||
case HistoryModel::HasDefaultActionRole:
|
||||
return notification.actions.contains("default");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int HistoryModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
|
||||
return m_notifications.size();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> HistoryModel::roleNames() const
|
||||
{
|
||||
static QHash<int, QByteArray> s_roles;
|
||||
|
||||
if (s_roles.isEmpty()) {
|
||||
// This generates role names from the Roles enum in the form of: FooRole -> foo
|
||||
const QMetaEnum e = QMetaEnum::fromType<HistoryModel::Roles>();
|
||||
|
||||
// Qt built-in roles we use
|
||||
s_roles.insert(Qt::DisplayRole, QByteArrayLiteral("display"));
|
||||
s_roles.insert(Qt::DecorationRole, QByteArrayLiteral("decoration"));
|
||||
|
||||
for (int i = 0; i < e.keyCount(); ++i) {
|
||||
const int value = e.value(i);
|
||||
|
||||
QByteArray key(e.key(i));
|
||||
key[0] = key[0] + 32; // lower case first letter
|
||||
key.chop(4); // strip "Role" suffix
|
||||
|
||||
s_roles.insert(value, key);
|
||||
}
|
||||
|
||||
s_roles.insert(HistoryModel::IdRole, QByteArrayLiteral("notificationId")); // id is QML-reserved
|
||||
}
|
||||
|
||||
return s_roles;
|
||||
}
|
||||
|
||||
void HistoryModel::add(const Notification ¬ification)
|
||||
{
|
||||
beginInsertRows(QModelIndex(), m_notifications.size(), m_notifications.size());
|
||||
m_notifications.append(std::move(notification));
|
||||
endInsertRows();
|
||||
save();
|
||||
}
|
||||
|
||||
void HistoryModel::remove(int index)
|
||||
{
|
||||
if (index > m_notifications.size() && index < 0)
|
||||
return;
|
||||
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
m_notifications.removeAt(index);
|
||||
endRemoveRows();
|
||||
save();
|
||||
}
|
||||
|
||||
void HistoryModel::clearAll()
|
||||
{
|
||||
beginResetModel();
|
||||
m_notifications.clear();
|
||||
endResetModel();
|
||||
save();
|
||||
}
|
||||
|
||||
void HistoryModel::save()
|
||||
{
|
||||
QSettings settings(QSettings::UserScope, "cutefishos", "notifications");
|
||||
settings.clear();
|
||||
|
||||
QByteArray datas;
|
||||
QDataStream out(&datas, QIODevice::WriteOnly);
|
||||
|
||||
out << m_notifications;
|
||||
|
||||
settings.setValue("datas", datas);
|
||||
}
|
||||
|
||||
void HistoryModel::initDatas()
|
||||
{
|
||||
QSettings settings(QSettings::UserScope, "cutefishos", "notifications");
|
||||
QByteArray listByteArray = settings.value("datas").toByteArray();
|
||||
QDataStream in(&listByteArray, QIODevice::ReadOnly);
|
||||
in >> m_notifications;
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
#ifndef HISTORYMODEL_H
|
||||
#define HISTORYMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include "notification.h"
|
||||
|
||||
class HistoryModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Roles {
|
||||
IdRole = Qt::UserRole + 1,
|
||||
SummaryRole = Qt::DisplayRole,
|
||||
ImageRole = Qt::DecorationRole,
|
||||
CreatedRole,
|
||||
UpdatedRole,
|
||||
BodyRole,
|
||||
IconNameRole,
|
||||
HasDefaultActionRole
|
||||
};
|
||||
Q_ENUM(Roles)
|
||||
|
||||
static HistoryModel* self();
|
||||
explicit HistoryModel(QObject *parent = nullptr);
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
Q_INVOKABLE void add(const Notification ¬ification);
|
||||
Q_INVOKABLE void remove(int index);
|
||||
Q_INVOKABLE void clearAll();
|
||||
Q_INVOKABLE void save();
|
||||
|
||||
void initDatas();
|
||||
|
||||
private:
|
||||
QVector<Notification> m_notifications;
|
||||
};
|
||||
|
||||
#endif // HISTORYMODEL_H
|
||||
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<metadata>
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
<dc:title/>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs>
|
||||
<style id="current-color-scheme" type="text/css">.ColorScheme-Text {
|
||||
color:#363636;
|
||||
}</style>
|
||||
</defs>
|
||||
<path class="ColorScheme-Text" d="m18.564 3.7559-3.2656 5.8184-2.416-1.4355-1.0215 1.7188 5.6504 3.3594 1.0215-1.7207-2.375-1.4121 3.2773-5.8398-0.87109-0.48828zm-10.564 3.2441a1 1 0 0 0-1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0-1-1zm-3.5 1a0.5 0.5 0 0 0-0.5 0.5 0.5 0.5 0 0 0 0.5 0.5 0.5 0.5 0 0 0 0.5-0.5 0.5 0.5 0 0 0-0.5-0.5zm1.5 2a1 1 0 0 0-1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0-1-1zm5 1c-1.1185 1.5643-3.1645 2.8109-7 3v1c2.1137 3.3717 5 5 9 5h1c1.3112-1.5872 2.3575-3.0324 3-5v-1l-5-3h-1zm0.5293 1.1016 4.3281 2.5977c-0.57283 1.5466-1.472 2.9036-2.584 4.2695-3.2734 0.03125-6.2207-1.4282-7.9473-4.1387 3.1182-0.31062 5.0195-1.2848 6.2031-2.7285z" fill="#fff"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,13 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<defs id="defs3051">
|
||||
<style type="text/css" id="current-color-scheme">
|
||||
.ColorScheme-Text {
|
||||
color:#363636;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path style="fill:currentColor;fill-opacity:1;stroke:none"
|
||||
d="M 18.564453 3.7558594 L 15.298828 9.5742188 L 12.882812 8.1386719 L 11.861328 9.8574219 L 17.511719 13.216797 L 18.533203 11.496094 L 16.158203 10.083984 L 19.435547 4.2441406 L 18.564453 3.7558594 z M 8 7 A 1 1 0 0 0 7 8 A 1 1 0 0 0 8 9 A 1 1 0 0 0 9 8 A 1 1 0 0 0 8 7 z M 4.5 8 A 0.5 0.5 0 0 0 4 8.5 A 0.5 0.5 0 0 0 4.5 9 A 0.5 0.5 0 0 0 5 8.5 A 0.5 0.5 0 0 0 4.5 8 z M 6 10 A 1 1 0 0 0 5 11 A 1 1 0 0 0 6 12 A 1 1 0 0 0 7 11 A 1 1 0 0 0 6 10 z M 11 11 C 9.8815125 12.564268 7.8355055 13.810894 4 14 L 4 15 C 6.1137135 18.371692 9 20 13 20 L 14 20 C 15.311249 18.412805 16.357513 16.967619 17 15 L 17 14 L 12 11 L 11 11 z M 11.529297 12.101562 L 15.857422 14.699219 C 15.284594 16.24586 14.385404 17.602833 13.273438 18.96875 C 9.999999 19 7.052768 17.540538 5.3261719 14.830078 C 8.4443879 14.51946 10.345716 13.545307 11.529297 12.101562 z "
|
||||
class="ColorScheme-Text"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,53 @@
|
||||
#include "notificationwindow.h"
|
||||
#include "notificationsmodel.h"
|
||||
#include "historymodel.h"
|
||||
|
||||
#include <QQmlContext>
|
||||
|
||||
#include <KWindowSystem>
|
||||
#include <KWindowEffects>
|
||||
|
||||
NotificationWindow::NotificationWindow(QQuickView *parent)
|
||||
: QQuickView(parent)
|
||||
{
|
||||
installEventFilter(this);
|
||||
|
||||
setFlags(Qt::Popup);
|
||||
setResizeMode(QQuickView::SizeRootObjectToView);
|
||||
setColor(Qt::transparent);
|
||||
|
||||
rootContext()->setContextProperty("NotificationDialog", this);
|
||||
rootContext()->setContextProperty("notificationsModel", NotificationsModel::self());
|
||||
rootContext()->setContextProperty("historyModel", HistoryModel::self());
|
||||
|
||||
// KWindowEffects::slideWindow(winId(), KWindowEffects::RightEdge);
|
||||
setSource(QUrl("qrc:/qml/NotificationWindow.qml"));
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
void NotificationWindow::open()
|
||||
{
|
||||
setVisible(true);
|
||||
setMouseGrabEnabled(true);
|
||||
setKeyboardGrabEnabled(true);
|
||||
}
|
||||
|
||||
bool NotificationWindow::eventFilter(QObject *object, QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::MouseButtonPress) {
|
||||
if (QWindow *w = qobject_cast<QWindow*>(object)) {
|
||||
if (!w->geometry().contains(static_cast<QMouseEvent*>(event)->globalPos())) {
|
||||
QQuickView::setVisible(false);
|
||||
}
|
||||
}
|
||||
} else if (event->type() == QEvent::KeyPress) {
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
|
||||
if (keyEvent->key() == Qt::Key_Escape) {
|
||||
QQuickView::setVisible(false);
|
||||
}
|
||||
} else if (event->type() == QEvent::Show) {
|
||||
KWindowSystem::setState(winId(), NET::SkipTaskbar | NET::SkipPager | NET::SkipSwitcher);
|
||||
}
|
||||
|
||||
return QObject::eventFilter(object, event);
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
#ifndef NOTIFICATIONWINDOW_H
|
||||
#define NOTIFICATIONWINDOW_H
|
||||
|
||||
#include <QQuickView>
|
||||
|
||||
class NotificationWindow : public QQuickView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit NotificationWindow(QQuickView *parent = nullptr);
|
||||
|
||||
void open();
|
||||
|
||||
bool eventFilter(QObject *object, QEvent *event) override;
|
||||
};
|
||||
|
||||
#endif // NOTIFICATIONWINDOW_H
|
||||
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: Reion Wong <reion@cutefishos.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import FishUI 1.0 as FishUI
|
||||
|
||||
Item {
|
||||
id: control
|
||||
|
||||
property url source
|
||||
property real size: 30
|
||||
property string popupText
|
||||
|
||||
signal leftButtonClicked
|
||||
signal rightButtonClicked
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
hoverEnabled: control.visible ? true : false
|
||||
|
||||
onClicked: {
|
||||
if (mouse.button === Qt.LeftButton)
|
||||
control.leftButtonClicked()
|
||||
else if (mouse.button === Qt.RightButton)
|
||||
control.rightButtonClicked()
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 1
|
||||
// radius: parent.height * 0.2
|
||||
radius: parent.height / 2
|
||||
|
||||
color: {
|
||||
if (mouseArea.containsMouse) {
|
||||
if (mouseArea.containsPress)
|
||||
return (FishUI.Theme.darkMode) ? Qt.rgba(255, 255, 255, 0.3) : Qt.rgba(0, 0, 0, 0.2)
|
||||
else
|
||||
return (FishUI.Theme.darkMode) ? Qt.rgba(255, 255, 255, 0.2) : Qt.rgba(0, 0, 0, 0.1)
|
||||
}
|
||||
|
||||
return "transparent"
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: iconImage
|
||||
anchors.centerIn: parent
|
||||
width: parent.height * 0.8
|
||||
height: width
|
||||
sourceSize.width: width
|
||||
sourceSize.height: height
|
||||
source: control.source
|
||||
asynchronous: true
|
||||
antialiasing: true
|
||||
smooth: false
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Copyright (C) 2021 CutefishOS Team.
|
||||
*
|
||||
* Author: Reion Wong <reion@cutefishos.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQml 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Window 2.12
|
||||
import QtGraphicalEffects 1.0
|
||||
import FishUI 1.0 as FishUI
|
||||
import Cutefish.Notification 1.0
|
||||
|
||||
Item {
|
||||
id: control
|
||||
|
||||
visible: true
|
||||
|
||||
Rectangle {
|
||||
id: _background
|
||||
anchors.fill: parent
|
||||
color: FishUI.Theme.secondBackgroundColor
|
||||
radius: NotificationDialog.width * 0.05 //FishUI.Theme.bigRadius
|
||||
opacity: 0.7
|
||||
|
||||
border.width: 1
|
||||
border.color: FishUI.Theme.darkMode ? Qt.rgba(255, 255, 255, 0.1)
|
||||
: Qt.rgba(0, 0, 0, 0.05)
|
||||
}
|
||||
|
||||
readonly property rect screenRect: {
|
||||
let rect = Qt.rect(screen.screenGeometry.x + screen.availableScreenRect.x,
|
||||
screen.screenGeometry.y + screen.availableScreenRect.y,
|
||||
screen.availableScreenRect.width,
|
||||
screen.availableScreenRect.height)
|
||||
return rect
|
||||
}
|
||||
|
||||
onScreenRectChanged: {
|
||||
NotificationDialog.width = 350
|
||||
NotificationDialog.height = screenRect.height - FishUI.Units.smallSpacing * 3
|
||||
NotificationDialog.x = screenRect.x + screenRect.width - NotificationDialog.width - FishUI.Units.smallSpacing * 1.5
|
||||
NotificationDialog.y = screenRect.y + FishUI.Units.smallSpacing * 1.5
|
||||
}
|
||||
|
||||
ScreenHelper {
|
||||
id: screen
|
||||
}
|
||||
|
||||
FishUI.WindowHelper {
|
||||
id: windowHelper
|
||||
}
|
||||
|
||||
FishUI.WindowShadow {
|
||||
view: NotificationDialog
|
||||
radius: _background.radius
|
||||
}
|
||||
|
||||
FishUI.WindowBlur {
|
||||
view: NotificationDialog
|
||||
geometry: Qt.rect(NotificationDialog.x,
|
||||
NotificationDialog.y,
|
||||
NotificationDialog.width,
|
||||
NotificationDialog.height)
|
||||
windowRadius: _background.radius
|
||||
enabled: true
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: FishUI.Units.largeSpacing
|
||||
spacing: FishUI.Units.largeSpacing
|
||||
|
||||
RowLayout {
|
||||
Label {
|
||||
text: qsTr("Notification Center")
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
leftPadding: FishUI.Units.smallSpacing
|
||||
color: FishUI.Theme.textColor
|
||||
font.pointSize: 15
|
||||
}
|
||||
|
||||
IconButton {
|
||||
visible: _view.count > 0
|
||||
Layout.preferredHeight: 30
|
||||
Layout.preferredWidth: 30
|
||||
source: FishUI.Theme.darkMode ? "qrc:/images/dark/clear.svg"
|
||||
: "qrc:/images/light/clear.svg"
|
||||
onLeftButtonClicked: historyModel.clearAll()
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
ListView {
|
||||
id: _view
|
||||
anchors.fill: parent
|
||||
model: historyModel
|
||||
spacing: FishUI.Units.largeSpacing
|
||||
highlightFollowsCurrentItem: true
|
||||
clip: true
|
||||
|
||||
Label {
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("No notifications")
|
||||
color: FishUI.Theme.disabledTextColor
|
||||
font.pointSize: 15
|
||||
visible: _view.count === 0
|
||||
}
|
||||
|
||||
addDisplaced: Transition {
|
||||
NumberAnimation { properties: "x, y"; duration: 300 }
|
||||
}
|
||||
|
||||
removeDisplaced: Transition {
|
||||
NumberAnimation { properties: "x, y"; duration: 300 }
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
width: ListView.view.width
|
||||
height: 70
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: FishUI.Theme.darkMode ? "white"
|
||||
: "black"
|
||||
radius: FishUI.Theme.bigRadius
|
||||
opacity: FishUI.Theme.darkMode ? 0.1
|
||||
: 0.03
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: FishUI.Units.smallSpacing
|
||||
spacing: FishUI.Units.smallSpacing
|
||||
|
||||
Image {
|
||||
id: _icon
|
||||
width: 48
|
||||
height: width
|
||||
source: "image://icontheme/%1".arg(model.iconName)
|
||||
sourceSize: Qt.size(width, height)
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
antialiasing: true
|
||||
smooth: true
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
Label {
|
||||
text: model.summary
|
||||
visible: text
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
rightPadding: FishUI.Units.smallSpacing
|
||||
}
|
||||
|
||||
Label {
|
||||
text: model.body
|
||||
visible: text
|
||||
rightPadding: FishUI.Units.smallSpacing
|
||||
maximumLineCount: 2
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.Wrap
|
||||
Layout.fillWidth: true
|
||||
// Layout.fillHeight: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: FishUI.Units.smallSpacing / 2
|
||||
anchors.rightMargin: FishUI.Units.smallSpacing / 2
|
||||
width: 24
|
||||
height: 24
|
||||
source: "qrc:/images/" + (FishUI.Theme.darkMode ? "dark" : "light") + "/close.svg"
|
||||
sourceSize: Qt.size(width, height)
|
||||
visible: true
|
||||
z: 9999
|
||||
|
||||
Rectangle {
|
||||
property color hoveredColor: FishUI.Theme.darkMode ? Qt.lighter(FishUI.Theme.backgroundColor, 2)
|
||||
: Qt.darker(FishUI.Theme.backgroundColor, 1.2)
|
||||
property color pressedColor: FishUI.Theme.darkMode ? Qt.lighter(FishUI.Theme.backgroundColor, 1.5)
|
||||
: Qt.darker(FishUI.Theme.backgroundColor, 1.3)
|
||||
|
||||
z: -1
|
||||
anchors.fill: parent
|
||||
color: _closeBtnArea.pressed ? pressedColor : _closeBtnArea.containsMouse ? hoveredColor : "transparent"
|
||||
radius: height / 2
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: _closeBtnArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
historyModel.remove(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1">
|
||||
<context>
|
||||
<name>NotificationWindow</name>
|
||||
<message>
|
||||
<location filename="../qml/NotificationWindow.qml" line="91"/>
|
||||
<source>Notification Center</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/NotificationWindow.qml" line="123"/>
|
||||
<source>No notifications</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1">
|
||||
<context>
|
||||
<name>NotificationWindow</name>
|
||||
<message>
|
||||
<location filename="../qml/NotificationWindow.qml" line="91"/>
|
||||
<source>Notification Center</source>
|
||||
<translation>通知中心</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../qml/NotificationWindow.qml" line="123"/>
|
||||
<source>No notifications</source>
|
||||
<translation>无通知</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
Loading…
Reference in New Issue