diff --git a/plugins/welcomepage/qml/NewsFeed.qml b/plugins/welcomepage/qml/NewsFeed.qml new file mode 100644 --- /dev/null +++ b/plugins/welcomepage/qml/NewsFeed.qml @@ -0,0 +1,125 @@ +/* KDevelop + * + * Copyright 2017 Kevin Funk + * + * 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. + */ + +import QtQuick 2.0 +import QtQuick.Controls 1.3 +import QtQuick.Layouts 1.2 +import QtQuick.XmlListModel 2.0 + +ListView { + id: root + + property bool enabled: false + /// Max age (in minutes) of a news entry so it is shown in the list view + /// TODO: Implement me + property int maxNewsAge: 3 * 30 * 24 * 60 // 3 months + /// Max age (in minutes) of a news entry so it is considered 'new' (thus highlighted with a bold font) + property int maxHighlightedNewsAge: 30 * 24 * 60 // a month + + readonly property string feedUrl: "https://www.kdevelop.org/taxonomy/term/27/feed" + readonly property bool loading: feedModel.status === XmlListModel.Loading + + /// Returns a date parsed from the pubDate + function parsePubDate(pubDate) { + // We need to modify the pubDate read from the RSS feed + // so the JavaScript Date object can interpret it + var d = pubDate.replace(',','').split(' '); + if (d.length != 6) + return new Date(NaN); + + return new Date([d[0], d[2], d[1], d[3], d[4], 'GMT' + d[5]].join(' ')); + } + + spacing: 10 + + onLoadingChanged: { + if (feedModel.status == XmlListModel.Ready) + root.positionViewAtBeginning() + } + + model: XmlListModel { + id: feedModel + + source: enabled ? feedUrl : "" + query: "/rss/channel/item" + + XmlRole { name: "title"; query: "title/string()" } + XmlRole { name: "link"; query: "link/string()" } + XmlRole { name: "pubDate"; query: "pubDate/string()" } + } + + delegate: Column { + id: feedDelegate + + readonly property date publicationDate: parsePubDate(model.pubDate) + readonly property int ageInMinutes: !isNaN(publicationDate.getDate()) ? + Math.floor(Number((new Date() - publicationDate)) / 60000) : + -1 + readonly property bool isNew: ageInMinutes != -1 && ageInMinutes < maxHighlightedNewsAge + readonly property string dateString: isNaN(publicationDate.getDate()) ? model.pubDate : publicationDate.toLocaleDateString(Qt.locale(), Locale.ShortFormat) + + x: 10 + width: parent.width - 2*x + + Link { + width: parent.width + + text: model.title + + onClicked: Qt.openUrlExternally(model.link) + } + + Label { + width: parent.width + + font.bold: isNew + font.pointSize: 8 + color: disabledPalette.windowText + + text: isNew ? i18nc("Example: Tue, 03 Jan 2017 10:00:00 (new)", "%1 (new)", dateString) : dateString + } + } + + BusyIndicator { + id: busyIndicator + + height: newsHeading.height + + running: newsFeed.loading + } + + Label { + id: placeHolderLabel + + x: 10 + width: parent.width - 2*x + + text: i18n("No news entries available") + color: disabledPalette.windowText + visible: root.count === 0 && !root.loading + + Behavior on opacity { NumberAnimation {} } + } + + SystemPalette { + id: disabledPalette + colorGroup: SystemPalette.Disabled + } +} diff --git a/plugins/welcomepage/qml/area_code.qml b/plugins/welcomepage/qml/area_code.qml --- a/plugins/welcomepage/qml/area_code.qml +++ b/plugins/welcomepage/qml/area_code.qml @@ -61,6 +61,37 @@ } Heading { + id: newsHeading + + Layout.fillWidth: true + text: i18n("News") + } + + NewsFeed { + id: newsFeed + + readonly property int maxEntries: 3 + + Layout.fillWidth: true + Layout.minimumHeight: enabled && !loading ? (Math.min(count, maxEntries) * 40) : 30 + + Behavior on Layout.minimumHeight { PropertyAnimation {} } + + Timer { + // delay loading a bit so it has no effect on the KDevelop startup + interval: 3000 + running: true + onTriggered: newsFeed.enabled = true + } + } + + // add some spacing + Item { + Layout.fillWidth: true + height: 10 + } + + Heading { text: i18n("Need Help?") } diff --git a/plugins/welcomepage/welcomepage.qrc b/plugins/welcomepage/welcomepage.qrc --- a/plugins/welcomepage/welcomepage.qrc +++ b/plugins/welcomepage/welcomepage.qrc @@ -9,6 +9,7 @@ qml/GettingStarted.qml qml/Link.qml qml/StandardPage.qml + qml/NewsFeed.qml qml/Heading.qml qml/StandardBackground.qml qml/ProjectsDashboard.qml