Commit b8b6834d authored by Dimitris Kardarakos's avatar Dimitris Kardarakos
Browse files

Introduce KDE FOSDEM Companion

Mostly a spin of Calindori, it consumes the ical schedule of FOSDEM 2020
and presents the conference events using Kirigami components
parent 293d978d
<?xml version='1.0' encoding='utf-8'?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.kde.phone.kdefosdem"
android:versionName="0.0.1"
android:versionCode="1"
android:installLocation="auto">
<application android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="KDEFOSDEM" android:icon="@drawable/kdefosdem">
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation"
android:name="org.qtproject.qt5.android.bindings.QtActivity"
android:label="KDEFOSDEM"
android:windowSoftInputMode="adjustResize"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data android:name="android.app.lib_name" android:value="kdefosdem"/>
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
<meta-data android:name="android.app.repository" android:value="default"/>
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
<meta-data android:name="android.app.extract_android_style" android:value="minimal"/>
<!-- Deploy Qt libs as part of package -->
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
<meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
<meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
<!-- Run with local libs -->
<meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
<meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
<meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/>
<meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
<meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
<!-- Messages maps -->
<meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
<meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
<!-- Splash screen -->
<!-- <meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/splash"/> -->
<!-- Background running -->
<meta-data android:name="android.app.background_running" android:value="false"/>
<!-- auto screen scale factor -->
<meta-data android:name="android.app.auto_screen_scale_factor" android:value="true"/>
</activity>
</application>
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/>
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
</manifest>
cmake_minimum_required(VERSION 3.0)
project(kdefosdem)
set(KF5_MIN_VERSION "5.63.0")
set(QT_MIN_VERSION "5.7.0")
################# Disallow in-source build #################
if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
message(FATAL_ERROR "KDE FOSDEM Companion requires an out of source build. Please create a separate build directory.")
endif()
option(REMINDERS_ENABLED "Build with reminders support" OFF)
include(FeatureSummary)
################# set KDE specific information #################
find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH})
include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings NO_POLICY_SCOPE)
include(ECMPoQmTools)
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED NO_MODULE COMPONENTS DBus Core Quick Gui Svg Test Qml QuickControls2 Network)
find_package(KF5Config)
find_package(KF5Kirigami2)
find_package(KF5I18n)
find_package(KF5CalendarCore REQUIRED)
if(REMINDERS_ENABLED)
find_package(KF5DBusAddons CONFIG REQUIRED)
find_package(KF5Notifications CONFIG REQUIRED)
find_package(KF5Service CONFIG REQUIRED)
endif()
################# Enable C++11 features for clang and gcc #################
if(UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++0x")
endif()
################# now find all used packages #################
find_package(PkgConfig)
#########################################################################
add_subdirectory(src)
if(REMINDERS_ENABLED)
add_subdirectory(kdefosdemac)
endif()
if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/po")
ecm_install_po_files_as_qm(po)
endif()
install(FILES org.kde.phone.kdefosdem.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR})
install(PROGRAMS org.kde.phone.kdefosdem.desktop DESTINATION ${KDE_INSTALL_APPDIR})
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
add_definitions(-DTRANSLATION_DOMAIN=\"kdefosdemac\")
set(kdefosdemac_SRCS
calalarmclient.cpp
kdefosdemacmain.cpp
alarmsmodel.cpp
alarmnotification.cpp
notificationhandler.cpp
)
qt5_add_dbus_adaptor(kdefosdemac_SRCS org.kde.kdefosdemac.xml calalarmclient.h CalAlarmClient)
add_executable(kdefosdemac ${kdefosdemac_SRCS} ${RESOURCES})
target_link_libraries(kdefosdemac
KF5::CalendarCore
KF5::DBusAddons
KF5::Notifications
KF5::Service
KF5::I18n
Qt5::DBus
)
install(TARGETS
kdefosdemac ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}
)
install(FILES
org.kde.kdefosdemac.desktop
DESTINATION ${KDE_INSTALL_AUTOSTARTDIR}
)
install(FILES
org.kde.kdefosdemac.xml
DESTINATION ${DBUS_INTERFACES_INSTALL_DIR}
)
install(FILES kdefosdemac.notifyrc DESTINATION ${KNOTIFYRC_INSTALL_DIR})
#! /bin/sh
$XGETTEXT `find . -name "*.cpp" -o -name "*.h" | grep -v '/tests/'` -o $podir/kdefosdemac.pot
/*
* Copyright (c) 2019 Dimitris Kardarakos <dimkard@posteo.net>
*
* 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 2 of the License, or
* (at your option) 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* As a special exception, permission is given to link this program
* with any edition of Qt, and distribute the resulting executable,
* without including the source code for Qt in the source distribution.
*/
#include "alarmnotification.h"
#include <KLocalizedString>
#include <QDebug>
#include "notificationhandler.h"
AlarmNotification::AlarmNotification(NotificationHandler* handler, const QString & uid) : mUid(uid), mRemindAt(QDateTime()), mNotificationHandler(handler)
{
mNotification = new KNotification("alarm");
mNotification->setActions({i18n("Suspend"),i18n("Dismiss")});
connect(mNotification, &KNotification::action1Activated, this, &AlarmNotification::suspend);
connect(mNotification, &KNotification::action2Activated, this, &AlarmNotification::dismiss);
connect(this, &AlarmNotification::suspend, mNotificationHandler, [=](){ mNotificationHandler->suspend(this);});
connect(this, &AlarmNotification::dismiss, mNotificationHandler, [=](){ mNotificationHandler->dismiss(this);});
}
AlarmNotification::~AlarmNotification()
{
delete mNotification;
}
void AlarmNotification::send() const
{
mNotification->sendEvent();
}
QString AlarmNotification::uid() const
{
return mUid;
}
QString AlarmNotification::text() const
{
return mNotification->text();
}
void AlarmNotification::setText(const QString& alarmText)
{
mNotification->setText(alarmText);
}
QDateTime AlarmNotification::remindAt() const
{
return mRemindAt;
}
void AlarmNotification::setRemindAt(const QDateTime& remindAtDt)
{
mRemindAt = remindAtDt;
}
/*
* Copyright (c) 2019 Dimitris Kardarakos <dimkard@posteo.net>
*
* 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 2 of the License, or
* (at your option) 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* As a special exception, permission is given to link this program
* with any edition of Qt, and distribute the resulting executable,
* without including the source code for Qt in the source distribution.
*/
#ifndef ALARMNOTIFICATION_H
#define ALARMNOTIFICATION_H
#include <KNotification>
#include <QDateTime>
class NotificationHandler;
/**
* @brief The alarm notification that should be displayed. It is a wrapper of a KNotification enhanced with alarm properties, like uid and remind time
*
*/
class AlarmNotification : public QObject
{
Q_OBJECT
public:
explicit AlarmNotification(NotificationHandler* handler, const QString& uid);
~AlarmNotification() override;
/**
* @brief Sends the notification so as to be displayed
*/
void send() const;
/**
* @return The uid of the Incidence of the alarm of the notification
*/
QString uid() const;
/**
* @brief The text of the notification that should be displayed
*/
QString text() const;
/**
* @brief Sets the to-be-displayed text of the notification
*/
void setText(const QString& alarmText);
/**
* @return In case of a suspended notification, the time that the notification should be displayed. Otherwise, it is empty.
*/
QDateTime remindAt() const;
/**
* @brief Sets the time that should be displayed a suspended notification
*/
void setRemindAt(const QDateTime & remindAtDt);
Q_SIGNALS:
/**
* @brief Signal that should be emitted when the user clicks to the Dismiss action button of the KNotification displayed
*
*/
void dismiss();
/**
* @brief Signal that should be emitted when the user clicks to the Suspend action button of the KNotification displayed
*
*/
void suspend();
private:
KNotification* mNotification;
QString mUid;
QDateTime mRemindAt;
NotificationHandler* mNotificationHandler;
};
#endif
/*
* Copyright (c) 2019 Dimitris Kardarakos <dimkard@posteo.net>
*
* 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 2 of the License, or
* (at your option) 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* As a special exception, permission is given to link this program
* with any edition of Qt, and distribute the resulting executable,
* without including the source code for Qt in the source distribution.
*/
#include "alarmsmodel.h"
#include <KSharedConfig>
#include <KConfigGroup>
#include <QFile>
#include <QDebug>
AlarmsModel::AlarmsModel(QObject* parent) : QAbstractListModel(parent), mMemoryCalendars(QVector<MemoryCalendar::Ptr>()), mFileStorages(QVector<FileStorage::Ptr>()), mAlarms(Alarm::List()), mCalendarFiles(QStringList()), mParams(QHash<QString, QVariant>())
{
connect(this, &AlarmsModel::paramsChanged, this, &AlarmsModel::loadAlarms);
}
AlarmsModel::~AlarmsModel() = default;
QHash<int, QByteArray> AlarmsModel::roleNames() const
{
QHash<int, QByteArray> roles = QAbstractListModel::roleNames();
roles.insert(Uid, "uid");
roles.insert(Text, "text");
roles.insert(Time, "time");
roles.insert(IncidenceStartDt, "incidenceStartDt");
return roles;
}
QVariant AlarmsModel::data(const QModelIndex& index, int role) const
{
if(!index.isValid())
{
return QVariant();
}
switch(role)
{
case Qt::DisplayRole:
return mAlarms.at(index.row())->parentUid();
case Uid:
return mAlarms.at(index.row())->parentUid();
case Time:
return mAlarms.at(index.row())->time();
case Text:
return mAlarms.at(index.row())->text();
case IncidenceStartDt:
return parentStartDt(index.row());
}
return QVariant();
}
int AlarmsModel::rowCount(const QModelIndex& parent) const
{
if(parent.isValid())
{
return 0;
}
return mAlarms.count();
}
void AlarmsModel::loadAlarms()
{
qDebug() << "\nloadAlarms";
beginResetModel();
mAlarms.clear();
openLoadStorages();
int cnt = 0;
QVector<MemoryCalendar::Ptr>::const_iterator itr = mMemoryCalendars.constBegin();
while(itr != mMemoryCalendars.constEnd())
{
QDateTime from = mPeriod["from"].toDateTime();
QDateTime to = mPeriod["to"].toDateTime();
qDebug() << "loadAlarms:\tLooking for alarms in calendar #" << cnt << ", from" << from.toString("dd.MM.yyyy hh:mm:ss") << "to" << to.toString("dd.MM.yyyy hh:mm:ss");
Alarm::List calendarAlarms;
if(from.isValid() && to.isValid())
{
calendarAlarms = (*itr)->alarms(from, to, true);
}
else if(!(from.isValid()) && to.isValid())
{
calendarAlarms = (*itr)->alarmsTo(to);
}
qDebug() << "loadAlarms:\t" << calendarAlarms.count() << "alarms found in calendar #" << cnt;
if(!(calendarAlarms.empty()))
{
mAlarms.append(calendarAlarms);
}
++cnt;
++itr;
}
closeStorages();
endResetModel();
}
void AlarmsModel::setCalendars()
{
mFileStorages.clear();
mMemoryCalendars.clear();
qDebug() << "\nsetCalendars";
QStringList::const_iterator itr = mCalendarFiles.constBegin();
while(itr != mCalendarFiles.constEnd())
{
MemoryCalendar::Ptr calendar(new MemoryCalendar(QTimeZone::systemTimeZoneId()));
FileStorage::Ptr storage(new FileStorage(calendar));
storage->setFileName(*itr);
if(!(storage->fileName().isNull()))
{
qDebug() << "setCalendars:\t"<< "Appending calendar" << *itr;
mFileStorages.append(storage);
mMemoryCalendars.append(calendar);
}
++itr;
}
}
QHash<QString, QVariant> AlarmsModel::params() const
{
return mParams;
}
void AlarmsModel::setParams(const QHash<QString, QVariant>& parameters)
{
mParams = parameters;
QStringList calendarFiles = mParams["calendarFiles"].toStringList();
QVariantMap period = (mParams["period"].value<QVariant>()).value<QVariantMap>();
mCalendarFiles = calendarFiles;
setCalendars();
mPeriod = period;
emit paramsChanged();
}
void AlarmsModel::openLoadStorages()
{
QVector<FileStorage::Ptr>::const_iterator itr = mFileStorages.constBegin();
while(itr != mFileStorages.constEnd())
{
if((*itr)->open())
{
qDebug() << "loadAlarms:\t" << (*itr)->fileName() << "opened";
}
if((*itr)->load())
{
qDebug() << "loadAlarms:\t" << (*itr)->fileName() << "loaded";
}
++itr;
}
}
void AlarmsModel::closeStorages()
{
QVector<FileStorage::Ptr>::const_iterator itr = mFileStorages.constBegin();
while(itr != mFileStorages.constEnd())
{
if((*itr)->close())
{
qDebug() << "loadAlarms:\t" << (*itr)->fileName() << "closed";
}
++itr;
}
}
QDateTime AlarmsModel::parentStartDt(const int idx) const
{
Alarm::Ptr alarm = mAlarms.at(idx);
Duration offsetDuration;
QDateTime alarmTime = mAlarms.at(idx)->time();
if(alarm->hasStartOffset())
{
offsetDuration = alarm->startOffset();
}
if(!(offsetDuration.isNull()))
{
int secondsFromStart = offsetDuration.asSeconds();
return alarmTime.addSecs(-1*secondsFromStart);
}
return alarmTime;
}
/*
Copyright (c) 2019 Dimitris Kardarakos <dimkard@posteo.net>
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 2 of the License, or
(at your option) 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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, permission is given to link this program
with any edition of Qt, and distribute the resulting executable,
without including the source code for Qt in the source distribution.
*/
#ifndef ALARMSMODEL_H
#define ALARMSMODEL_H
#include <QAbstractListModel>
#include <KCalendarCore/Alarm>
#include <KCalendarCore/MemoryCalendar>
#include <KCalendarCore/FileStorage>
#include <QVariantMap>
using namespace KCalendarCore;
/**
* @brief Model that serves the alarms found in a set of calendar files for a specific time period, as set in the model input parameters
*
*/
class AlarmsModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(QHash<QString, QVariant> params READ params WRITE setParams NOTIFY paramsChanged);
public:
enum Roles
{
Uid = Qt::UserRole+1,
Time,
Text,
IncidenceStartDt
};
explicit AlarmsModel(QObject *parent = nullptr);
~AlarmsModel() override;
QHash<int, QByteArray> roleNames() const override;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex & parent = QModelIndex()) const override;
/**
* @return A QHash< QString, QVariant > of the input parameters of the model
*/
QHash<QString, QVariant> params() const;