Initial Commit

This commit is contained in:
Tobias Fella 2020-02-28 23:25:08 +01:00
commit 5ae34b56f7
No known key found for this signature in database
GPG Key ID: E55EDAB3CA5D9925
20 changed files with 1025 additions and 0 deletions

88
.clang-format Normal file
View File

@ -0,0 +1,88 @@
---
# SPDX-License-Identifier: MIT
#
# Copyright (C) 2019 Christoph Cullmann <cullmann@kde.org>
# Copyright (C) 2019 Gernot Gebhard <gebhard@absint.com>
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# Style for C++
Language: Cpp
# base is WebKit coding style: https://webkit.org/code-style-guidelines/
# below are only things set that diverge from this style!
BasedOnStyle: WebKit
# enforce C++11 (e.g. for std::vector<std::vector<lala>>
Standard: Cpp11
# 4 spaces indent
TabWidth: 4
# 3 * 80 wide lines
ColumnLimit: 240
# sort includes inside line separated groups
SortIncludes: true
# break before braces on function, namespace and class definitions.
BreakBeforeBraces: Linux
# CrlInstruction *a;
PointerAlignment: Right
# horizontally aligns arguments after an open bracket.
AlignAfterOpenBracket: Align
# align trailing comments
AlignTrailingComments: true
# don't move all parameters to new line
AllowAllParametersOfDeclarationOnNextLine: false
# no single line functions
AllowShortFunctionsOnASingleLine: None
# always break before you encounter multi line strings
AlwaysBreakBeforeMultilineStrings: true
# don't move arguments to own lines if they are not all on the same
BinPackArguments: false
# don't move parameters to own lines if they are not all on the same
BinPackParameters: false
# don't break binary ops
BreakBeforeBinaryOperators: None
# format C++11 braced lists like function calls
Cpp11BracedListStyle: true
# remove empty lines
KeepEmptyLinesAtTheStartOfBlocks: false
# no namespace indentation to keep indent level low
NamespaceIndentation: None
# we use template< without space.
SpaceAfterTemplateKeyword: false
# macros for which the opening brace stays attached.
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH, forever, Q_FOREVER, QBENCHMARK, QBENCHMARK_ONCE ]

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
build/

33
CMakeLists.txt Executable file
View File

@ -0,0 +1,33 @@
project(Alligator)
cmake_minimum_required(VERSION 2.8.12)
set(KF5_MIN_VERSION "5.18.0")
set(QT_MIN_VERSION "5.5.0")
if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
message(FATAL_ERROR "This application requires an out of source build. Please create a separate build directory.")
endif()
include(FeatureSummary)
find_package(ECM 5.67.0 REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR})
include(ECMSetupVersion)
include(ECMGenerateHeaders)
include(KDEInstallDirs)
include(KDECMakeSettings)
include(ECMPoQmTools)
include(KDECompilerSettings NO_POLICY_SCOPE)
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED NO_MODULE COMPONENTS Core Quick Test Gui Svg QuickControls2 Sql)
find_package(KF5Kirigami2 ${KF5_MIN_VERSION} REQUIRED)
find_package(KF5Syndication ${KF5_MIN_VERSION} REQUIRED)
find_package(KF5KIO ${KF5_MIN_VERSION} REQUIRED)
set(CMAKE_CXX_STANDARD 11)
add_subdirectory(src)
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)

4
README.md Executable file
View File

@ -0,0 +1,4 @@
# Alligator
Alligator is an RSS/Atom feed reader, currently under development.

14
src/CMakeLists.txt Executable file
View File

@ -0,0 +1,14 @@
set(alligator_SRCS
main.cpp
feedListModel.cpp
entryListModel.cpp
fetcher.cpp
feed.cpp
entry.cpp
resources.qrc
)
add_executable(alligator ${alligator_SRCS} ${RESOURCES})
target_link_libraries(alligator Qt5::Core Qt5::Qml Qt5::Quick Qt5::Svg Qt5::Sql KF5::KIOCore KF5::KIOFileWidgets KF5::KIONTLM KF5::Syndication)
install(TARGETS alligator ${KF5_INSTALL_TARGETS_DEFAULT_ARGS})

View File

@ -0,0 +1,80 @@
/**
* Copyright 2020 Tobias Fella <fella@posteo.de>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 <https://www.gnu.org/licenses/>.
*/
import QtQuick 2.7
import QtQuick.Controls 2.10 as Controls
import org.kde.kirigami 2.4 as Kirigami
import org.kde.alligator 1.0
Kirigami.ScrollablePage {
id: page
property string name
property string url
title: name
contextualActions: [
Kirigami.Action {
text: "Details"
onTriggered: ;//pageStack.push("qrc:/qml/FeedDetailsPage.qml", {"modelData": atomModel})
}
]
Component.onCompleted: {
entryListModel.fetch(url);
}
ListView {
model: EntryListModel {
id: entryListModel
feed: url
}
Connections {
target: entryListModel
}
delegate: Kirigami.SwipeListItem {
Controls.Label {
id: postTitle
width: parent.width
text: model.display
color: model.read ? Kirigami.Theme.disabledTextColor : Kirigami.Theme.textColor
}
actions: [
Kirigami.Action {
icon.name: model.bookmark ? "bookmark-remove" : "bookmark-new"
text: "Bookmark"
onTriggered: {
model.bookmark = !model.bookmark
}
}
]
onClicked: {
model.read = true;
//pageStack.push("qrc:/qml/EntryDetailsPage.qml", {"modelData": model})
}
}
}
}

View File

@ -0,0 +1,97 @@
/**
* Copyright 2020 Tobias Fella <fella@posteo.de>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 <https://www.gnu.org/licenses/>.
*/
import QtQuick 2.14
import QtQuick.Controls 2.10 as Controls
import QtQuick.Layouts 1.12
import org.kde.kirigami 2.4 as Kirigami
import org.kde.alligator 1.0
Component {
Kirigami.ScrollablePage {
title: "Alligator"
contextualActions: [
Kirigami.Action {
text: "Add feed"
onTriggered: {
addSheet.open()
}
}
]
Kirigami.OverlaySheet {
id: addSheet
contentItem: Kirigami.FormLayout {
Controls.TextField {
id: urlField
Layout.fillWidth: true
//placeholderText: "https://example.org/feed.xml"
text: "https://rss.golem.de/rss.php?feed=RSS2.0"
Kirigami.FormData.label: "Url"
}
Controls.Button {
text: "Add"
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
enabled: urlField.text
onClicked: {
feedListModel.add_feed(urlField.text)
addSheet.close()
}
}
}
}
ListView {
anchors.fill: parent
model: FeedListModel {
id: feedListModel
}
delegate: Kirigami.SwipeListItem {
Controls.Label {
text: model.display
}
onTextChanged: console.log(model.display)
width: parent.width
height: Kirigami.Units.gridUnit * 2
actions: [
Kirigami.Action {
icon.name: "list-remove"
text: "Remove"
onTriggered: feedListModel.remove_feed(index)
},
Kirigami.Action {
icon.name: "document-edit"
text: "Edit"
onTriggered:; //TODO
}
]
onClicked: {
pageStack.push("qrc:/EntryListPage.qml", {"name": model.display, "url": model.url})
}
}
}
}
}

40
src/contents/ui/main.qml Executable file
View File

@ -0,0 +1,40 @@
/**
* Copyright 2020 Tobias Fella <fella@posteo.de>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 <https://www.gnu.org/licenses/>.
*/
import QtQuick 2.1
import QtQuick.Controls 2.0 as Controls
import org.kde.kirigami 2.4 as Kirigami
Kirigami.ApplicationWindow {
id: root
title: "Alligator"
pageStack.initialPage: feedList
contextDrawer: Kirigami.ContextDrawer {
id: contextDrawer
}
FeedListPage {
id: feedList
}
}

60
src/entry.cpp Normal file
View File

@ -0,0 +1,60 @@
/**
* Copyright 2020 Tobias Fella <fella@posteo.de>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 <https://www.gnu.org/licenses/>.
*/
#include "entry.h"
Entry::Entry(const QString title, const bool bookmark, const bool read)
: m_title(title)
, m_bookmark(bookmark)
, m_read(read)
{
}
Entry::Entry(const Entry &other)
: m_title(other.title())
, m_bookmark(other.isBookmark())
, m_read(other.isRead())
{
}
bool Entry::isRead() const
{
return m_read;
}
bool Entry::isBookmark() const
{
return m_bookmark;
}
QString Entry::title() const
{
return m_title;
}
void Entry::setRead(bool read)
{
m_read = read;
}
void Entry::setBookmark(bool bookmark)
{
m_bookmark = bookmark;
}

42
src/entry.h Normal file
View File

@ -0,0 +1,42 @@
/**
* Copyright 2020 Tobias Fella <fella@posteo.de>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <QString>
class Entry
{
public:
Entry(const Entry &);
Entry(const QString title, const bool bookmark, const bool read);
QString title() const;
bool isBookmark() const;
bool isRead() const;
void setRead(bool read);
void setBookmark(bool bookmark);
private:
QString m_title;
bool m_bookmark;
bool m_read;
};

92
src/entryListModel.cpp Normal file
View File

@ -0,0 +1,92 @@
/**
* Copyright 2020 Tobias Fella <fella@posteo.de>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 <https://www.gnu.org/licenses/>.
*/
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QVector>
#include <syndication.h>
#include "entryListModel.h"
#include "fetcher.h"
EntryListModel::EntryListModel(QObject *parent)
: QAbstractListModel(parent)
{
}
QVariant EntryListModel::data(const QModelIndex &index, int role) const
{
if (role == Bookmark)
return QVariant(m_entries[index.row()].isBookmark());
if (role == Read)
return QVariant(m_entries[index.row()].isRead());
if (role == Qt::DisplayRole)
return m_entries[index.row()].title();
return QVariant(index.row());
}
int EntryListModel::rowCount(const QModelIndex &index) const
{
return m_entries.size();
}
QHash<int, QByteArray> EntryListModel::roleNames() const
{
QHash<int, QByteArray> roleNames;
roleNames[Qt::DisplayRole] = "display";
roleNames[Bookmark] = "bookmark";
roleNames[Read] = "read";
return roleNames;
}
bool EntryListModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (role == Bookmark) {
m_entries[index.row()].setBookmark(value.toBool());
} else if (role == Read) {
m_entries[index.row()].setRead(value.toBool());
}
emit dataChanged(index, index, QVector<int>({role}));
return true;
}
void EntryListModel::fetch()
{
connect(&Fetcher::instance(), &Fetcher::finished, this, [this]() {
beginResetModel();
QSqlQuery query = QSqlQuery(QSqlDatabase::database());
query.prepare(QStringLiteral("SELECT id, title, content FROM Entries WHERE feed=:feed;"));
query.bindValue(QStringLiteral(":feed"), m_feed);
query.exec();
while (query.next()) {
m_entries.append(Entry(query.value(1).toString(), false, false));
}
endResetModel();
});
Fetcher::instance().fetch(m_feed);
}
QString EntryListModel::feed() const
{
return m_feed;
}
void EntryListModel::setFeed(QString feed)
{
m_feed = feed;
}

56
src/entryListModel.h Normal file
View File

@ -0,0 +1,56 @@
/**
* Copyright 2020 Tobias Fella <fella@posteo.de>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <QAbstractListModel>
#include <QObject>
#include <syndication.h>
#include "entry.h"
class EntryListModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(QString feed READ feed WRITE setFeed NOTIFY feedChanged)
public:
enum DataRole {
Bookmark = Qt::UserRole + 1,
Read,
};
explicit EntryListModel(QObject *parent = nullptr);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &index) const override;
QHash<int, QByteArray> roleNames() const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
QString feed() const;
void setFeed(QString feed);
Q_INVOKABLE void fetch();
Q_SIGNALS:
void feedChanged(QString);
private:
QVector<Entry> m_entries;
QString m_feed;
};

54
src/feed.cpp Normal file
View File

@ -0,0 +1,54 @@
/**
* Copyright 2020 Tobias Fella <fella@posteo.de>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 <https://www.gnu.org/licenses/>.
*/
#include "feed.h"
Feed::Feed(const QString url)
: m_url(url)
, m_name(url)
{
}
Feed::Feed(const QString url, const QString name)
: m_url(url)
, m_name(name)
{
}
Feed::Feed(const Feed &other)
: m_url(other.url())
, m_name(other.name())
{
}
QString Feed::url() const
{
return m_url;
}
QString Feed::name() const
{
return m_name;
}
void Feed::setName(QString name)
{
m_name = name;
}

45
src/feed.h Normal file
View File

@ -0,0 +1,45 @@
/**
* Copyright 2020 Tobias Fella <fella@posteo.de>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <QObject>
#include <QString>
class Feed : public QObject
{
Q_OBJECT
public:
Feed(const QString url);
Feed(const Feed &other);
Feed(const QString url, const QString name);
QString name() const;
QString url() const;
void setName(QString name);
Q_SIGNALS:
void nameChanged(const QString &name);
private:
QString m_url;
QString m_name;
};

87
src/feedListModel.cpp Normal file
View File

@ -0,0 +1,87 @@
/**
* Copyright 2020 Tobias Fella <fella@posteo.de>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 <https://www.gnu.org/licenses/>.
*/
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QUrl>
#include <syndication.h>
#include "feedListModel.h"
#include "fetcher.h"
FeedListModel::FeedListModel(QObject *parent)
: QAbstractListModel(parent)
{
QSqlQuery query = QSqlQuery(QSqlDatabase::database());
query.exec(QStringLiteral("SELECT name, url FROM Feeds"));
beginInsertRows(QModelIndex(), 0, query.size());
while (query.next()) {
feeds += Feed(query.value(1).toString(), query.value(0).toString());
}
endInsertRows();
}
QHash<int, QByteArray> FeedListModel::roleNames() const
{
QHash<int, QByteArray> roleNames;
roleNames[Qt::DisplayRole] = "display";
roleNames[Url] = "url";
return roleNames;
}
QVariant FeedListModel::data(const QModelIndex &index, int role) const
{
if (role == Url)
return QVariant(this->feeds[index.row()].url());
if (role == Qt::DisplayRole)
return QVariant(this->feeds[index.row()].name());
return QVariant();
}
int FeedListModel::rowCount(const QModelIndex &index) const
{
return this->feeds.size();
}
void FeedListModel::add_feed(QString url)
{
Fetcher::instance().fetch(QUrl(url));
beginInsertRows(QModelIndex(), feeds.size(), feeds.size());
feeds.append(Feed(url));
endInsertRows();
QSqlQuery query = QSqlQuery(QSqlDatabase::database());
query.prepare(QStringLiteral("INSERT INTO Feeds VALUES (:url, :name);"));
query.bindValue(QStringLiteral(":url"), url);
query.bindValue(QStringLiteral(":name"), url);
query.exec();
}
void FeedListModel::remove_feed(int index)
{
Feed toRemove = feeds[index];
QSqlQuery query = QSqlQuery(QSqlDatabase::database());
query.prepare(QStringLiteral("DELETE FROM Feeds WHERE name=:name AND url=url;"));
query.bindValue(QStringLiteral(":url"), toRemove.url());
query.bindValue(QStringLiteral(":name"), toRemove.name());
query.exec();
beginRemoveRows(QModelIndex(), index, index);
feeds.remove(index);
endRemoveRows();
}

48
src/feedListModel.h Normal file
View File

@ -0,0 +1,48 @@
/**
* Copyright 2020 Tobias Fella <fella@posteo.de>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <QAbstractListModel>
#include <QUrl>
#include <QVector>
#include "feed.h"
#include "fetcher.h"
class FeedListModel : public QAbstractListModel
{
Q_OBJECT
public:
enum DataRole {
Url = Qt::UserRole + 1,
};
explicit FeedListModel(QObject *parent = nullptr);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &index) const override;
QHash<int, QByteArray> roleNames() const override;
Q_INVOKABLE void add_feed(QString url);
Q_INVOKABLE void remove_feed(int index);
private:
QVector<Feed> feeds;
};

69
src/fetcher.cpp Normal file
View File

@ -0,0 +1,69 @@
/**
* Copyright 2020 Tobias Fella <fella@posteo.de>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 <https://www.gnu.org/licenses/>.
*/
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <syndication.h>
#include "fetcher.h"
Fetcher::Fetcher() {
}
void Fetcher::fetch(QUrl url)
{
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
manager->setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy);
manager->setStrictTransportSecurityEnabled(true);
manager->enableStrictTransportSecurityStore(true);
QNetworkRequest request = QNetworkRequest(QUrl(url));
QNetworkReply *reply = manager->get(request);
connect(reply, &QNetworkReply::finished, this, [this, url, reply]() {
QByteArray data = reply->readAll();
Syndication::DocumentSource *document = new Syndication::DocumentSource(data, url.toString());
Syndication::FeedPtr feed = Syndication::parserCollection()->parse(*document, QStringLiteral("Atom"));
QSqlDatabase db = QSqlDatabase::database();
QSqlQuery query = QSqlQuery(db);
for (const auto &entry : feed->items()) {
query = QSqlQuery(db);
query.prepare(QStringLiteral("INSERT INTO Entries VALUES (:feed, :id, :title, :contents);"));
query.bindValue(QStringLiteral(":feed"), url.toString());
query.bindValue(QStringLiteral(":id"), entry->id());
query.bindValue(QStringLiteral(":title"), entry->title());
query.bindValue(QStringLiteral(":contents"), entry->content());
query.exec();
for (const auto &author : entry->authors()) {
query = QSqlQuery(db);
query.prepare(QStringLiteral("INSERT INTO Authors VALUES(:id, :name, :uri, :email);"));
query.bindValue(QStringLiteral(":id"), entry->id());
query.bindValue(QStringLiteral(":name"), author->name());
query.bindValue(QStringLiteral(":uri"), author->uri());
query.bindValue(QStringLiteral(":email"), author->email());
query.exec();
}
}
emit finished();
});
}

43
src/fetcher.h Normal file
View File

@ -0,0 +1,43 @@
/**
* Copyright 2020 Tobias Fella <fella@posteo.de>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <QObject>
#include <QUrl>
class Fetcher : public QObject
{
Q_OBJECT
public:
static Fetcher &instance()
{
static Fetcher _instance;
return _instance;
}
void fetch(QUrl);
private:
Fetcher();
Fetcher(const Fetcher &);
Q_SIGNALS:
void finished();
};

65
src/main.cpp Normal file
View File

@ -0,0 +1,65 @@
/**
* Copyright 2020 Tobias Fella <fella@posteo.de>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 <https://www.gnu.org/licenses/>.
*/
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQuickView>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QUrl>
#include <QStandardPaths>
#include <QDir>
#include "entryListModel.h"
#include "feedListModel.h"
int main(int argc, char *argv[])
{
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
QCoreApplication::setOrganizationName(QStringLiteral("KDE"));
QCoreApplication::setOrganizationDomain(QStringLiteral("kde.org"));
QCoreApplication::setApplicationName(QStringLiteral("Alligator"));
QCoreApplication::setApplicationVersion(QStringLiteral("0.1"));
qmlRegisterType<FeedListModel>("org.kde.alligator", 1, 0, "FeedListModel");
qmlRegisterType<EntryListModel>("org.kde.alligator", 1, 0, "EntryListModel");
QQmlApplicationEngine engine;
QSqlDatabase db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"));
QString databasePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
QDir(databasePath).mkpath(databasePath);
db.setDatabaseName(databasePath + "/database.db3");
db.open();
QSqlQuery query = QSqlQuery(db);
query.exec(QStringLiteral("CREATE TABLE IF NOT EXISTS Feeds (name TEXT, url TEXT);"));
query.exec(QStringLiteral("CREATE TABLE IF NOT EXISTS Entries (feed TEXT, id TEXT UNIQUE, title TEXT, content TEXT);"));
query.exec(QStringLiteral("CREATE TABLE IF NOT EXISTS Authors (id TEXT, name TEXT, uri TEXT, email TEXT);"));
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
if (engine.rootObjects().isEmpty()) {
return -1;
}
return app.exec();
}

7
src/resources.qrc Executable file
View File

@ -0,0 +1,7 @@
<RCC>
<qresource prefix="/">
<file alias="main.qml">contents/ui/main.qml</file>
<file alias="EntryListPage.qml">contents/ui/EntryListPage.qml</file>
<file alias="FeedListPage.qml">contents/ui/FeedListPage.qml</file>
</qresource>
</RCC>