FlightGear next
LauncherNotificationsController.cxx
Go to the documentation of this file.
1// Written by James Turner, started October 2020
2//
3// Copyright (C) 2020 James Turner <james@flightgear.org>
4//
5// This program is free software; you can redistribute it and/or
6// modify it under the terms of the GNU General Public License as
7// published by the Free Software Foundation; either version 2 of the
8// License, or (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful, but
11// WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13// General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program; if not, write to the Free Software
17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
20
21#include <QAbstractListModel>
22#include <QDebug>
23#include <QQmlEngine>
24#include <QSettings>
25
27
28namespace {
29
30const int IdRole = Qt::UserRole + 1;
31const int SourceRole = Qt::UserRole + 2;
32const int ArgsRole = Qt::UserRole + 3;
33
34} // namespace
35
37{
38public:
39 int rowCount(const QModelIndex&) const override
40 {
41 return static_cast<int>(_data.size());
42 }
43
44 QVariant data(const QModelIndex& index, int role) const override
45 {
46 const int row = index.row();
47 if ((row < 0) || (row >= static_cast<int>(_data.size()))) {
48 return {};
49 }
50
51 const auto& d = _data.at(row);
52 switch (role) {
53 case IdRole: return d.id;
54 case SourceRole: return d.source;
55 case ArgsRole: return QVariant::fromValue(d.args);
56 default:
57 break;
58 }
59
60 return {};
61 }
62
63 QHash<int, QByteArray> roleNames() const override
64 {
65 QHash<int, QByteArray> result = QAbstractListModel::roleNames();
66 result[IdRole] = "id";
67 result[SourceRole] = "source";
68 result[ArgsRole] = "args";
69 return result;
70 }
71
72 void removeIndex(int row)
73 {
74 // work aroud the role-by-role destruction order of model data
75 // clear out the source first so the Loader unloads, before we
76 // null args. This avoids 'args is null' warnings from the loaded
77 // notification
78 _data[row].source.clear();
79 const auto idx = index(row, 0);
80 emit dataChanged(idx, idx, {SourceRole});
81
82 // now we can remove everything else
83 beginRemoveRows({}, row, row);
84 _data.erase(_data.begin() + row);
85 endRemoveRows();
86 }
87
88 void append(QString id, QUrl source, QJSValue args)
89 {
90 const int newRow = static_cast<int>(_data.size());
91 beginInsertRows({}, newRow, newRow);
92 _data.push_back({id, source, args});
93 endInsertRows();
94 }
95
96 struct Data {
97 QString id;
98 QUrl source;
99 QJSValue args;
100 };
101
102 std::vector<Data> _data;
103};
104
105LauncherNotificationsController::LauncherNotificationsController(QObject* pr, QQmlEngine* engine) : QObject(pr)
106{
107 Q_ASSERT(static_instance == nullptr);
108 static_instance = this;
109
110 _model = new NotificationsModel;
111
112 _qmlEngine = engine;
113}
114
119
124
126{
127 return _model;
128}
129
131{
132 if ((index < 0) || (index >= static_cast<int>(_model->_data.size()))) {
133 return {};
134 }
135 const auto& d = _model->_data.at(index);
136 qDebug() << Q_FUNC_INFO << index;
137 return d.args;
138}
139
141{
142 return _qmlEngine;
143}
144
146{
147 const auto& d = _model->_data.at(index);
148
149 // if the notificsation supports persistent dismissal, then record this
150 // fact in the global settings, so we don't show it again.
151 // restore defaults will of course clear these settings, but that's
152 // desirable anyway.
153 if (d.args.property("persistent-dismiss").toBool()) {
154 QSettings settings;
155 settings.beginGroup("dismissed-notifications");
156 settings.setValue(d.id, true);
157 }
158
159 _model->removeIndex(index);
160}
161
162void LauncherNotificationsController::postNotification(QString id, QUrl source, QJSValue args)
163{
164 const bool supportsPersistentDismiss = args.property("persistent-dismiss").toBool();
165 if (supportsPersistentDismiss) {
166 QSettings settings;
167 settings.beginGroup("dismissed-notifications");
168 bool alreadyDimissed = settings.value(id).toBool();
169 if (alreadyDimissed) {
170 return;
171 }
172 }
173
174 _model->append(id, source, args);
175}
static std::unique_ptr< FavouriteAircraftData > static_instance
QVariant data(const QModelIndex &index, int role) const override
static LauncherNotificationsController * instance()
LauncherNotificationsController(QObject *pr, QQmlEngine *qmlEngine)
Q_INVOKABLE QJSValue argsForIndex(int index) const
void postNotification(QString id, QUrl source, QJSValue args={})