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

Support multiple conferences

The application is now configurable, supporting events that provide an
ical file. The conf.kde.in conference has been pre-loaded.
parent b8b6834d
......@@ -8,7 +8,7 @@ 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.")
message(FATAL_ERROR "KDE Conference Companion requires an out of source build. Please create a separate build directory.")
endif()
option(REMINDERS_ENABLED "Build with reminders support" OFF)
......
# KDE FOSDEM 2020 Companion
# KDE Conference Companion
Companion application for FOSDEM 2020
Companion application for conferences
## Build
......
[Global]
IconName=kalarm
Comment=KDE FOSDEM Companion
Name=KDE FOSDEM Companion
Comment=KDE Conference Companion
Name=KDE Conference Companion
[Context/uid]
Name=Incidence uid
......
......@@ -33,8 +33,8 @@ int main(int argc, char **argv)
QApplication app(argc, argv);
app.setAttribute(Qt::AA_UseHighDpiPixmaps, true);
KAboutData aboutData(QStringLiteral("kdefosdemac"), i18n("KDE FOSDEM Alarm Check Daemon"),
QString(), i18n("KDE FOSDEM Alarm Check Daemon"),
KAboutData aboutData(QStringLiteral("kdefosdemac"), i18n("KDE Conference Alarm Check Daemon"),
QString(), i18n("KDE Conference Alarm Check Daemon"),
KAboutLicense::GPL,
i18n("(c) 2020 Dimitris Kardarakos"),
QString(), QString());
......
[Desktop Entry]
Name=KDE FOSDEM Companion Reminder Client
Name=KDE Conference Companion Reminder Client
Exec=kdefosdemac
Icon=kdefosdem
Type=Application
Categories=Qt;KDE;
GenericName=KDE FOSDEM Companion Reminder Client
GenericName[x-test]=xxKDE FOSDEM Companion Reminder Clienttxx
GenericName=KDE Conference Companion Reminder Client
GenericName[x-test]=xxKDE Conference Companion Reminder Clienttxx
Terminal=false
X-KDE-autostart-phase=2
X-KDE-autostart-condition=kdefosdemrc:General:Autostart:true
......
......@@ -3,10 +3,10 @@
<id>org.kde.phone.kdefosdem.desktop</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0+</project_license>
<name>KDE FOSDEM Companion</name>
<summary>KDE FOSDEM companion application</summary>
<name>KDE Conference Companion</name>
<summary>KDE Conference companion application</summary>
<description>
<p>KDE FOSDEM is companion application for FOSDEM made by KDE</p>
<p>KDE Conference is companion application for conferences made by KDE</p>
</description>
<url type="bugtracker"></url>
<project_group>KDE</project_group>
......
[Desktop Entry]
Name=KDE FOSDEM Companion
Comment=KDE FOSDEM Companion
Name=KDE Conference Companion
Comment=KDE Conference Companion
Exec=kdefosdem
MimeType=application/x-kdefosdem;
Icon=kdefosdem
......
......@@ -47,6 +47,8 @@ if(ANDROID)
view-categories
internet-services
favorite
group
object-select-symbolic
)
endif()
......
var conferences =
[
{
name: "fosdem",
details: "FOSDEM is a free event for software developers to meet, share ideas and collaborate. Every year, thousands of developers of free and open source software from all over the world gather at the event in Brussels.",
days: ["2020-02-01", "2020-02-02"],
categories: ["Ada","Backup and Recovery","BSD","Certification","Coding for Language Communities","Collaborative Information and Content Management Applications","Community and Ethics","Community devroom","Containers","Containers and Security","Continuous Integration and Continuous Deployment","Databases","Debugging Tools","Decentralized Internet and Privacy","Dependency Management","Distributions","DNS","Embedded, Mobile and Automotive","Erlang, Elixir and Friends","Freedom","Free Java","Free Software Radio","Free Tools and Editors","Game Development","Geospatial","Go","Graphics","Graph Systems and Algorithms","Hardware-aided Trusted Computing","Hardware Enablement","History","HPC, Big Data, and Data Science","Infra Management Devroom","Internet of Things","JavaScript","Keynotes","Kotlin","Legal and Policy Issues","Lightning Talks","LLVM","Microkernels and Component-based OS","Minimalistic, Experimental and Emerging Languages","Miscellaneous","Monitoring and Observability","Mozilla","MySQL, MariaDB and Friends","Open Document Editors","Open Media","Open Research Tools and Technologies","Open Source Computer Aided Modeling and Design","Open Source Design","Open Source Firmware, BMC and Bootloader","PostgreSQL","Python","Real Time Communications","Retrocomputing","RISC-V","Rust","Security","Software Defined Networking","Software Defined Storage","Testing and Automation","Virtualization and IaaS","Web Performance","Workshops"],
url: "https://fosdem.org/2020/schedule/ical",
map: {
image: "fosdemCampusMap.png",
latitude: "N50.812375",
longitude: "E4.380734",
url: "http://www.openstreetmap.org/?mlat=50.812375&mlon=4.38073"
}
},
{
name: "conf.kde.in",
details: "conf.kde.in 2020 will be held in Maharaja Agrasen Institute of Technology, located in Rohini, Delhi, India. The aim of MAIT is to promote quality education in the field of Technology.",
days: ["2020-01-17", "2020-01-18", "2020-01-19"],
categories: [],
url: "https://conf.kde.org/en/cki2020/public/schedule.ics",
map: {}
}
]
/*
* Copyright 2020 Dimitris Kardarakos <dimkard@posteo.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 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 Library General Public License for more details
*
* You should have received a copy of the GNU Library 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.
*/
import QtQuick 2.7
import QtQuick.Controls 2.4 as Controls
import org.kde.kirigami 2.4 as Kirigami
import org.kde.phone.kdefosdem 0.1 as KDEFOSDEM
Kirigami.Page {
id: root
title: i18n("Conferences")
property var conferencesList
signal selected(int conferenceId)
Kirigami.CardsGridView {
id: view
anchors.fill: parent
model: conferencesList
delegate: Kirigami.Card {
id: card
banner {
title: modelData.name
}
contentItem: Controls.Label {
wrapMode: Text.WordWrap
text: modelData.details
}
actions: [
Kirigami.Action {
text: i18n("Select")
iconName: "object-select-symbolic"
onTriggered: root.selected(model.index)
}
]
}
}
}
......@@ -22,6 +22,7 @@ import QtQuick.Layouts 1.2
import org.kde.kirigami 2.0 as Kirigami
import QtQuick.Controls 2.4 as Controls2
import org.kde.phone.kdefosdem 0.1 as KDEFOSDEM
import "ConferenceData.js" as ConferenceData
Kirigami.ApplicationWindow {
id: root
......@@ -31,37 +32,63 @@ Kirigami.ApplicationWindow {
*/
signal refreshNeeded;
property var categories: ["Ada","Backup and Recovery","BSD","Certification","Coding for Language Communities","Collaborative Information and Content Management Applications","Community and Ethics","Community devroom","Containers","Containers and Security","Continuous Integration and Continuous Deployment","Databases","Debugging Tools","Decentralized Internet and Privacy","Dependency Management","Distributions","DNS","Embedded, Mobile and Automotive","Erlang, Elixir and Friends","Freedom","Free Java","Free Software Radio","Free Tools and Editors","Game Development","Geospatial","Go","Graphics","Graph Systems and Algorithms","Hardware-aided Trusted Computing","Hardware Enablement","History","HPC, Big Data, and Data Science","Infra Management Devroom","Internet of Things","JavaScript","Keynotes","Kotlin","Legal and Policy Issues","Lightning Talks","LLVM","Microkernels and Component-based OS","Minimalistic, Experimental and Emerging Languages","Miscellaneous","Monitoring and Observability","Mozilla","MySQL, MariaDB and Friends","Open Document Editors","Open Media","Open Research Tools and Technologies","Open Source Computer Aided Modeling and Design","Open Source Design","Open Source Firmware, BMC and Bootloader","PostgreSQL","Python","Real Time Communications","Retrocomputing","RISC-V","Rust","Security","Software Defined Networking","Software Defined Storage","Testing and Automation","Virtualization and IaaS","Web Performance","Workshops"]
property int activeConference: 0
property string conference: activeConference >= 0 ? ConferenceData.conferences[activeConference].name : []
property var categories: activeConference >= 0 ? ConferenceData.conferences[activeConference].categories : []
property var conferenceDays: activeConference >= 0 ? ConferenceData.conferences[activeConference].days : []
function loadDynamicActions()
{
var categoryChildren = [];
for (var i=0; i < categories.length; ++i)
{
categoryChildren.push(categoryAction.createObject(categoryActions, {text: root.categories[i]}));
}
categoryActions.children = categoryChildren;
var dayChildren = [];
for (var i=0; i < conferenceDays.length; ++i)
{
dayChildren.push(dayAction.createObject(dayActions, { conferenceDay: new Date(root.conferenceDays[i]) }));
}
dayActions.children = dayChildren;
var conferenceNames = [];
for (var i=0; i < ConferenceData.conferences.length; ++i)
{
conferenceNames.push(conferenceAction.createObject(conferenceSelector, {idx: i}));
}
conferenceSelector.children = conferenceNames;
}
globalDrawer: Kirigami.GlobalDrawer {
id: drawer
title: "KDE FOSDEM Companion"
title: "Conference Companion"
actions: [
Kirigami.Action {
text: i18n("Full Schedule", onlineCalendar.name)
iconName: "view-calendar-agenda"
onTriggered: {
pageStack.clear();
pageStack.push(eventsView, {title: i18n("Schedule"),eventStartDt: ""});
}
id: conferenceSelector
text: i18n("Conferences")
iconName: "group"
},
Kirigami.Action {
text: i18n("Saturday", onlineCalendar.name)
iconName: "view-calendar-day"
text: i18n("Full Schedule")
iconName: "view-calendar-agenda"
onTriggered: {
pageStack.clear();
pageStack.push(eventsView, {title: i18n("Saturday"), eventStartDt: new Date('2020-02-01')});
pageStack.push(eventsView, {title: i18n("Schedule"),eventStartDt: ""});
}
},
Kirigami.Action {
text: i18n("Sunday")
id: dayActions
text: i18n("Days")
iconName: "view-calendar-day"
onTriggered: {
pageStack.clear();
pageStack.push(eventsView, {title: i18n("Sunday"), eventStartDt: new Date('2020-02-02')});
}
},
Kirigami.Action {
id: categoryActions
......@@ -77,6 +104,7 @@ Kirigami.ApplicationWindow {
pageStack.push(favoritesView, {title: i18n("Favorites"), eventStartDt: ""});
}
},
Kirigami.Action {
text: i18n("Map")
iconName: "find-location"
......@@ -87,14 +115,7 @@ Kirigami.ApplicationWindow {
}
]
Component.onCompleted: {
var childrenActions = [];
for (var i=0; i < categories.length; ++i)
{
childrenActions.push(categoryAction.createObject(categoryActions, { text: categories[i] }));
}
categoryActions.children = childrenActions;
}
Component.onCompleted: loadDynamicActions()
}
// contextDrawer: Kirigami.ContextDrawer {
......@@ -102,33 +123,30 @@ Kirigami.ApplicationWindow {
// }
pageStack {
initialPage: [eventsView]
initialPage: [conferencesView]
separatorVisible: false
}
// KDEFOSDEM.Config {
// id: kdefosdemConfig
// }
KDEFOSDEM.LocalCalendar {
id: onlineCalendar
name: "fosdemonline"
calendarInfo: {"name": ConferenceData.conferences[root.activeConference].name, "url": ConferenceData.conferences[root.activeConference].url}
onNameChanged: {
onCalendarInfoChanged: {
root.refreshNeeded();
if (root.pageStack.depth > 1) {
root.pageStack.pop(null);
}
root.loadDynamicActions();
}
}
KDEFOSDEM.LocalCalendar {
id: favoritesCalendar
name: "favorites"
calendarInfo: {"name": "favorites"}
onNameChanged: {
onCalendarInfoChanged: {
root.refreshNeeded();
if (root.pageStack.depth > 1) {
root.pageStack.pop(null);
......@@ -144,6 +162,8 @@ Kirigami.ApplicationWindow {
rwCalendar: favoritesCalendar
viewMode: "events"
title: i18n("Schedule")
onEventsUpdated: root.refreshNeeded()
Connections {
......@@ -172,10 +192,30 @@ Kirigami.ApplicationWindow {
}
}
Component {
id: conferencesView
Conferences {
conferencesList: ConferenceData.conferences
onSelected: {
pageStack.clear();
root.activeConference = conferenceId;
onlineCalendar.calendarInfo = {name: ConferenceData.conferences[conferenceId].name, url: ConferenceData.conferences[conferenceId].url};
pageStack.push(eventsView, {title: i18n("Schedule"),eventStartDt: ""});
}
}
}
Component {
id: mapView
MapView {}
MapView {
imageUrl: activeConference >= 0 && ConferenceData.conferences[activeConference].map.hasOwnProperty("image") ?ConferenceData.conferences[activeConference].map.image : ""
latitude: activeConference >= 0 && ConferenceData.conferences[activeConference].map.hasOwnProperty("latitude") ? ConferenceData.conferences[activeConference].map.latitude : "";
longitude: activeConference >= 0 && ConferenceData.conferences[activeConference].map.hasOwnProperty("longitude") ?ConferenceData.conferences[activeConference].map.longitude : ""
geoUrl: activeConference >= 0 && ConferenceData.conferences[activeConference].map.hasOwnProperty("url") ? ConferenceData.conferences[activeConference].map.url : ""
}
}
Component {
......@@ -189,4 +229,35 @@ Kirigami.ApplicationWindow {
}
}
}
Component {
id: dayAction
Kirigami.Action {
property date conferenceDay
text: conferenceDay.toLocaleDateString(Qt.locale(), "dddd")
onTriggered: {
pageStack.clear();
pageStack.push(eventsView, {title: conferenceDay.toLocaleDateString(Qt.locale(), "dddd"), eventStartDt: conferenceDay});
}
}
}
Component {
id: conferenceAction
Kirigami.Action {
property string idx
text: ConferenceData.conferences[idx].name
iconName: idx == root.activeConference ? "object-select-symbolic" : ""
onTriggered: {
pageStack.clear();
root.activeConference = idx;
onlineCalendar.calendarInfo = {name: ConferenceData.conferences[idx].name, url: ConferenceData.conferences[idx].url};
pageStack.push(eventsView, {title: i18n("Schedule"),eventStartDt: ""});
}
}
}
}
......@@ -24,38 +24,43 @@ import org.kde.kirigami 2.4 as Kirigami
Kirigami.Page {
id: root
property string imageUrl
property string latitude
property string longitude
property string geoUrl
title: i18n("Map")
ColumnLayout {
anchors.fill: parent
Image {
Layout.fillWidth: true
source: "campusmap.png"
visible: imageUrl != ""
source: root.imageUrl
fillMode: Image.PreserveAspectFit
asynchronous: true
}
Controls2.Label {
id: latitude
Layout.alignment : Qt.AlignHCenter
text: i18n("Latitude: N50.812375")
visible: root.latitude != ""
text: i18n("Latitude: %1", root.latitude)
}
Controls2.Label {
id: longitude
Controls2.Label {
Layout.alignment : Qt.AlignHCenter
text: i18n("Longitude: E4.380734")
}
visible: root.longitude != ""
text: i18n("Longitude: %1", root.longitude)
}
Controls2.Button {
Layout.alignment : Qt.AlignHCenter
visible: root.geoUrl != ""
text: i18n("OpenStreetMaps")
onClicked: Qt.openUrlExternally("http://www.openstreetmap.org/?mlat=50.812375&mlon=4.38073")
onClicked: Qt.openUrlExternally(root.geoUrl)
}
}
}
......@@ -28,7 +28,7 @@
using namespace KCalendarCore;
LocalCalendar::LocalCalendar(QObject* parent)
: QObject(parent)
: QObject(parent), m_calendarInfo(QVariantMap())
{
connect(&m_DownloadManager, SIGNAL(finished(QNetworkReply*)),
SLOT(downloadFinished(QNetworkReply*)));
......@@ -49,29 +49,29 @@ FileStorage::Ptr LocalCalendar::calendarstorage() const
QString LocalCalendar::name() const
{
return m_name;
return m_calendarInfo.contains("name") ? m_calendarInfo["name"].toString() : QString();
}
void LocalCalendar::setName(QString calendarName)
void LocalCalendar::setCalendarInfo(const QVariantMap& calendarInfoMap)
{
if (m_name != calendarName)
if (calendarInfoMap.contains("name") && calendarInfoMap.contains("url"))
{
m_name = calendarName;
m_calendarInfo["name"] = calendarInfoMap["name"].toString();
m_calendarInfo["url"] = calendarInfoMap["url"].toString();
KDEFosdemConfig* config = new KDEFosdemConfig();
m_fullpath = config->calendarFile(calendarInfoMap["name"].toString());
m_fullpath = config->calendarFile(calendarName);
if(calendarName == "fosdemonline")
{
QUrl url = QUrl::fromEncoded("https://fosdem.org/2020/schedule/ical");
QNetworkRequest request(url);
m_DownloadManager.get(request);
}
else
{
createLocalCalendar(calendarName);
}
QUrl url = QUrl::fromEncoded(calendarInfoMap["url"].toByteArray());
QNetworkRequest request(url);
m_DownloadManager.get(request);
}
else if (calendarInfoMap.contains("name"))
{
createLocalCalendar(calendarInfoMap["name"].toString());
}
else {
qDebug() << "No sufficient calendar information provided";
}
}
......@@ -237,7 +237,7 @@ void LocalCalendar::downloadFinished(QNetworkReply *reply)
m_cal_storage = storage;
}
emit nameChanged();
emit calendarInfoChanged();
emit memorycalendarChanged();
}
}
......@@ -247,6 +247,9 @@ void LocalCalendar::downloadFinished(QNetworkReply *reply)
}
void LocalCalendar::createLocalCalendar(const QString& calendarName)
{
KDEFosdemConfig* config = new KDEFosdemConfig();
m_fullpath = config->calendarFile(calendarName);
MemoryCalendar::Ptr calendar(new MemoryCalendar(QTimeZone::systemTimeZoneId()));
FileStorage::Ptr storage(new FileStorage(calendar));
storage->setFileName(m_fullpath);
......@@ -259,11 +262,17 @@ void LocalCalendar::createLocalCalendar(const QString& calendarName)
if(storage->load())
{
m_name = calendarName;
m_calendarInfo["name"] = calendarName;
m_calendarInfo["url"] = "";
m_calendar = calendar;
m_cal_storage = storage;
}
emit nameChanged();
emit calendarInfoChanged();
emit memorycalendarChanged();
}
QVariantMap LocalCalendar::calendarInfo() const
{
return m_calendarInfo;
}
......@@ -31,7 +31,8 @@ using namespace KCalendarCore;
class LocalCalendar : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(QVariantMap calendarInfo READ calendarInfo WRITE setCalendarInfo NOTIFY calendarInfoChanged)
Q_PROPERTY(QString name READ name)
Q_PROPERTY(QSharedPointer<MemoryCalendar> memorycalendar READ memorycalendar WRITE setMemorycalendar NOTIFY memorycalendarChanged)
Q_PROPERTY(QSharedPointer<FileStorage> calendarstorage READ calendarstorage WRITE setCalendarstorage NOTIFY calendarstorageChanged)
Q_PROPERTY(QDateTime nulldate READ nulldate CONSTANT)
......@@ -43,12 +44,13 @@ public:
MemoryCalendar::Ptr memorycalendar() const;
FileStorage::Ptr calendarstorage() const;
QString name() const;
QVariantMap calendarInfo() const;
QDateTime nulldate() const;
void setMemorycalendar(MemoryCalendar::Ptr memoryCalendar);
void setCalendarstorage(FileStorage::Ptr calendarStorage);
void setName(QString calendarName);
bool saveToDisk(const QString &filename, QIODevice *data);
bool saveToDisk(const QString& filename, QIODevice *data);
void setCalendarInfo(const QVariantMap& calendarInfoMap);
public Q_SLOTS:
int todosCount(const QDate &date) const;
......@@ -60,7 +62,7 @@ public Q_SLOTS:
Q_SIGNALS:
void memorycalendarChanged();
void calendarstorageChanged();
void nameChanged();
void calendarInfoChanged();
private:
static QVariantMap canCreateFile(const QString& calendarName);
......@@ -68,9 +70,10 @@ private:
MemoryCalendar::Ptr m_calendar;
FileStorage::Ptr m_cal_storage;
QString m_name;
QString m_fullpath;
QNetworkAccessManager m_DownloadManager;
QVariantMap m_calendarInfo;