Compare commits

..

1 commit

Author SHA1 Message Date
5862478593 Downoad all images in the background and keep them in memory
As one of the first steps to offline capability we download all
images and put them into the JSON stirng and into the content
as data-uris for <img>-tags. This way you can go offline and keep
enjoying pictures in your feeds, at least untill you restart
FeedTheMonkey for now.
2016-10-24 07:52:58 +02:00
18 changed files with 214 additions and 264 deletions

View file

@ -1,33 +0,0 @@
language: cpp
compiler: gcc
sudo: require
dist: trusty
before_install:
- sudo add-apt-repository ppa:beineri/opt-qt58-trusty -y
- sudo apt-get update -qq
install:
- sudo apt-get -y install qt58base qt58webengine qt58quickcontrols
- source /opt/qt58/bin/qt58-env.sh
script:
- qmake PREFIX=/usr
- make -j4
- sudo make INSTALL_ROOT=appdir install ; sudo chown -R $USER appdir ; find appdir/
- wget -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage"
- chmod a+x linuxdeployqt*.AppImage
- unset QTDIR; unset QT_PLUGIN_PATH ; unset LD_LIBRARY_PATH
- "./linuxdeployqt*.AppImage ./appdir/usr/share/applications/*.desktop -qmldir=./qml/
-bundle-non-qt-libs"
- "./linuxdeployqt*.AppImage ./appdir/usr/share/applications/*.desktop -qmldir=./qml/
-appimage"
- find ./appdir -executable -type f -exec ldd {} \; | grep " => /usr" | cut -d " "
-f 2-3 | sort | uniq
- mv FeedTheMonkey*.AppImage FeedTheMonkey.AppImage
deploy:
provider: releases
api_key:
secure: d+hHwOnmeLPVvuue6VDCs2LwLS+BFzJF/BB5iObtkCYBwQ8ybnVzUcgnjJKOt37SHI0T9kLegI+Lq/843ECYiGiDjQg4PvCF69V8ODgHv3v1qiN5oG/eroBXd83a0+xhi4BuJt0SwcV9mcv4uD9bCPhj944rmMLH+3qD4ysgImBmbYSbbLecE9+QAs7bfrCwQRfdCePBORX3FHa/p12NEtln7xv6ZRyku9LdJSzAcdgm4zc95ggTAVC1+aQB6J0q2QzWPlQcOkLx+ZYmOqClhbSMFpIyPXP8UpXjYyvUlTAd0+wH8BGf0O3lpOqACc7IKIbj9d5oPmghVZo55SyW+RR77G+az+IbGJ7iXZsMfQZsMvtB7hNYhNvUUxQrAau7Y/ve+6sMQmvA7aMHV8kDUvnNW/c2r2jAWwk+N8QzGcP/rclDCKeOWZqZABmrzTViXZVAeXh4hJ8r6mbq8iwagBUPCsVYhVuerQt/KIoWxyn6/1GmMfKGi3dA/v3u1qU61vzrz3yLlJBmUAVPxZdVmqfRweh4BXjImxFMFmf5PYm5FnDg1gmw8rWsgii7+IPYw7DjTAHpjYbtXvDwDgG1nRXiRp2TGtPPgKW1/Uk8r/j5vfB5WcEZ7exLUgsPPjny5MGvzjqOxeLvwK1Pg9jFBFXIx7l1tNMJQxQU0r3DmBg=
file: FeedTheMonkey.AppImage
on:
repo: jeena/FeedTheMonkey
skip_cleanup: true
draft: true

View file

@ -1,6 +1,6 @@
# FeedTheMonkey # FeedTheMonkey
<img align=right src="http://jeena.net/feedthemonkey/feedthemonkey-icon.png" width='256' alt='Icon'> <img align=right src="http://jabs.nu/feedthemonkey/feedthemonkey-icon.png" width='256' alt='Icon'>
FeedTheMonkey is a desktop client for [TinyTinyRSS](http://tt-rss.org). That means that FeedTheMonkey is a desktop client for [TinyTinyRSS](http://tt-rss.org). That means that
it doesn't work as a standalone feed reader but only as a client for the TinyTinyRSS API it doesn't work as a standalone feed reader but only as a client for the TinyTinyRSS API
@ -11,12 +11,10 @@ to have Qt 5.6 installed to be able to compile and have a account on a TinyTinyR
## Installation ## Installation
If you run Linux then there is an AppImage on the [Latest release](https://github.com/jeena/FeedTheMonkey/releases/latest) page. You download it, make executable and are able to run, it should work on most of the distributions out there. Download the latest release code from: https://github.com/jeena/FeedTheMonkey/releases/latest
For ArchLinux I package it and it's available on https://aur.archlinux.org/packages/feedthemonkey/
You can compile and install it everywhere Qt is suported, this means on macOS, Windows You can compile and install it everywhere Qt is suported, this means on macOS, Windows
and Linux. and Linux. For ArchLinux I package it and it's available on https://aur.archlinux.org/packages/feedthemonkey/
## Keyboard shortcuts ## Keyboard shortcuts
@ -43,13 +41,13 @@ the use on a desktop computer but I'd like to see it on a mobile device too.
## Screenshot ## Screenshot
![Feed the Monkey screenshot](http://jeena.net/feedthemonkey/feedthemonkey-dark.png) ![Feed the Monkey screenshot](http://jabs.nu/feedthemonkey/screenshot.png)
## License ## License
This file is part of FeedTheMonkey. This file is part of FeedTheMonkey.
Copyright 2015-2017 Jeena Copyright 2015 Jeena
FeedTheMonkey is free software: you can redistribute it and/or modify FeedTheMonkey is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by

View file

@ -25,12 +25,13 @@ html, body {
body { body {
background: #eee; background: #eee;
font-family: sans-serif; font-family: sans-serif;
word-wrap: break-word; padding: 2em;
font-weight: lighter;
} }
.nightmode { .nightmode {
background: #353535; background: #111;
color: #ddd; color: #aaa;
} }
.nightmode::-webkit-scrollbar { .nightmode::-webkit-scrollbar {
@ -49,28 +50,32 @@ body {
} }
h1 { h1 {
font-weight: lighter;
font-size: 1.4em; font-size: 1.4em;
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
#date {
border-bottom: 1px solid #aaa;
margin-bottom: 1em;
padding-bottom: 1em;
display: block;
}
.nightmode #date {
border-bottom-color: #333;
}
.starred:after { .starred:after {
content: "*"; content: "*";
} }
header {
padding: 2em;
border-bottom: 1px solid #aaa;
}
.nightmode header {
border-bottom-color: #222;
}
header p { header p {
color: #666; color: #aaa;
margin: 0; margin: 0;
padding: 0; padding: 0;
font-size: 0.8em;
} }
.nightmode header p { .nightmode header p {
@ -84,7 +89,6 @@ a {
article { article {
line-height: 1.6; line-height: 1.6;
margin: 2em;
} }
article a { article a {

View file

@ -4,96 +4,7 @@
<meta charset="utf-8"> <meta charset="utf-8">
<title>TTRSS</title> <title>TTRSS</title>
<link href="content.css" media="all" rel="stylesheet"> <link href="content.css" media="all" rel="stylesheet">
<script type="text/javascript"> <script type="text/javascript" src="content.js"></script>
/*
* This file is part of FeedTheMonkey.
*
* Copyright 2015 Jeena
*
* FeedTheMonkey 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 3 of the License, or
* (at your option) any later version.
*
* FeedTheMonkey 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 FeedTheMonkey. If not, see <http://www.gnu.org/licenses/>.
*/
function $(id) {
return document.getElementById(id);
}
function setArticle(article) {
window.scrollTo(0, 0);
$("date").innerHTML = "";
$("title").innerHTML = "";
$("title").href = "";
$("title").title = "";
$("feed_title").innerHTML = "";
$("author").innerHTML = "";
$("article").innerHTML = "";
if(article === "empty") {
$("article").innerHTML = "No unread articles to display.";
} else if(article === "loading") {
$("article").innerHTML = "Loading <blink>&hellip;</blink>";
} else if (article === "logout") {
} else if(article) {
$("date").innerHTML = (new Date(parseInt(article.updated, 10) * 1000));
$("title").innerHTML = article.title;
$("title").href = article.link;
$("title").title = article.link;
$("feed_title").innerHTML = article.feed_title;
$("title").className = article.marked ? "starred" : "";
$("author").innerHTML = "";
if(article.author && article.author.length > 0)
$("author").innerHTML = "&ndash; " + article.author
$("article").innerHTML = article.content;
var as = $("article").getElementsByTagName("a");
for(var i = 0; i < as.length; i++) {
as[i].target = "";
}
}
}
function setFont(font, size) {
document.body.style.fontFamily = font;
document.body.style.fontSize = size + "pt";
}
function setNightmode(nightmode) {
if(nightmode) document.body.className = "nightmode";
else document.body.className = "";
}
function checkKey(e) {
e = e || window.event;
if (e.keyCode === 37) {
window.location.href = "feedthemonkey:previous";
} else if (e.keyCode === 39) {
window.location.href = "feedthemonkey:next";
} else if(e.keyCode == 13) {
window.location.href = "feedthemonkey:open";
}
}
window.addEventListener("keydown", checkKey);
</script>
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no"> <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
</head> </head>
<body class=''> <body class=''>

73
html/content.js Normal file
View file

@ -0,0 +1,73 @@
/*
* This file is part of FeedTheMonkey.
*
* Copyright 2015 Jeena
*
* FeedTheMonkey 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 3 of the License, or
* (at your option) any later version.
*
* FeedTheMonkey 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 FeedTheMonkey. If not, see <http://www.gnu.org/licenses/>.
*/
function $(id) {
return document.getElementById(id);
}
function setArticle(article) {
window.scrollTo(0, 0);
$("date").innerHTML = "";
$("title").innerHTML = "";
$("title").href = "";
$("title").title = "";
$("feed_title").innerHTML = "";
$("author").innerHTML = "";
$("article").innerHTML = "";
if(article === "empty") {
$("article").innerHTML = "No unread articles to display.";
} else if(article === "loading") {
$("article").innerHTML = "Loading <blink>&hellip;</blink>";
} else if (article === "logout") {
} else if(article) {
$("date").innerHTML = (new Date(parseInt(article.updated, 10) * 1000));
$("title").innerHTML = article.title;
$("title").href = article.link;
$("title").title = article.link;
$("feed_title").innerHTML = article.feed_title;
$("title").className = article.marked ? "starred" : "";
$("author").innerHTML = "";
if(article.author && article.author.length > 0)
$("author").innerHTML = "&ndash; " + article.author
$("article").innerHTML = article.content;
var as = $("article").getElementsByTagName("a");
for(var i = 0; i < as.length; i++) {
as[i].target = "";
}
}
}
function setFont(font, size) {
document.body.style.fontFamily = font;
document.body.style.fontSize = size + "pt";
}
function setNightmode(nightmode) {
if(nightmode) document.body.className = "nightmode";
else document.body.className = "";
}

View file

@ -2,5 +2,6 @@
<qresource prefix="/html"> <qresource prefix="/html">
<file>content.css</file> <file>content.css</file>
<file>content.html</file> <file>content.html</file>
<file>content.js</file>
</qresource> </qresource>
</RCC> </RCC>

View file

@ -1,4 +1,5 @@
[Desktop Entry] [Desktop Entry]
Version=2.0.0
Comment=A desktop client for the TinyTinyRSS feed reader. Comment=A desktop client for the TinyTinyRSS feed reader.
Exec=feedthemonkey Exec=feedthemonkey
GenericName=Feed Reader GenericName=Feed Reader
@ -8,4 +9,4 @@ NoDisplay=false
StartupNotify=true StartupNotify=true
Terminal=false Terminal=false
Type=Application Type=Application
Categories=Network;Qt; Categories=Network;Qt

View file

@ -17,11 +17,12 @@
* along with FeedTheMonkey. If not, see <http://www.gnu.org/licenses/>. * along with FeedTheMonkey. If not, see <http://www.gnu.org/licenses/>.
*/ */
import QtWebEngine 1.8 import QtWebEngine 1.0
import QtQuick 2.0 import QtQuick 2.0
import QtQuick.Controls 1.3 import QtQuick.Controls 1.3
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.3 import QtQuick.Controls.Styles 1.3
import QtQuick.Controls 1.3
import TTRSS 1.0 import TTRSS 1.0
Item { Item {
@ -84,17 +85,9 @@ Item {
webView.runJavaScript("if(typeof setNightmode == \"function\") setNightmode(" + (content.nightmode ? "true" : "false") + ")") webView.runJavaScript("if(typeof setNightmode == \"function\") setNightmode(" + (content.nightmode ? "true" : "false") + ")")
} }
onNavigationRequested: { onNavigationRequested: {
if (request.url == "feedthemonkey:previous") { if (request.navigationType != WebEngineView.LinkClickedNavigation) {
request.action = WebEngineView.IgnoreRequest;
app.showPreviousPost();
} else if (request.url == "feedthemonkey:next") {
request.action = WebEngineView.IgnoreRequest;
app.showNextPost();
} else if (request.url == "feedthemonkey:open") {
request.action = WebEngineView.IgnoreRequest;
Qt.openUrlExternally(post.link)
} else if (request.navigationType !== WebEngineNavigationRequest.LinkClickedNavigation) {
request.action = WebEngineView.AcceptRequest; request.action = WebEngineView.AcceptRequest;
} else { } else {
request.action = WebEngineView.IgnoreRequest; request.action = WebEngineView.IgnoreRequest;

View file

@ -33,7 +33,7 @@ Item {
} }
id: item id: item
height: d.height + t.height + e.height + 2 height: d.height + t.height + e.height + 20
Item { Item {
anchors.fill: parent anchors.fill: parent
@ -81,7 +81,7 @@ Item {
Label { Label {
id: t id: t
text: title text: title
color: nightmode ? (read ? "#888" : "#ddd") : (read ? "gray" : "black") color: nightmode ? (read ? "#555" : "#aaa") : (read ? "gray" : "black")
font.pointSize: textFontSize font.pointSize: textFontSize
textFormat: Text.PlainText textFormat: Text.PlainText
wrapMode: Text.WrapAnywhere wrapMode: Text.WrapAnywhere

View file

@ -48,21 +48,6 @@ ScrollView {
} }
} }
onWidthChanged: {
// Hide sidebar if smaller than 200px wide
if(width < 200) {
width = 0;
}
}
Rectangle {
width: 1
color: app.nightmode ? "#111" : "lightgray"
anchors.right: parent.right
anchors.top: parent.top
height: parent.height
}
ListView { ListView {
id: listView id: listView
@ -82,12 +67,12 @@ ScrollView {
highlightFollowsCurrentItem: false highlightFollowsCurrentItem: false
highlight: Component { highlight: Component {
Rectangle { Rectangle {
width: listView.currentItem.width -1 width: listView.currentItem.width
height: listView.currentItem.height height: listView.currentItem.height
color: nightmode ? "#15539e" : "lightblue" color: nightmode ? "#444" : "lightblue"
opacity: 0.5
y: listView.currentItem.y y: listView.currentItem.y
} }
} }
onCurrentItemChanged: { onCurrentItemChanged: {
@ -100,6 +85,8 @@ ScrollView {
} }
item.content.post = server.posts[currentIndex] item.content.post = server.posts[currentIndex]
//content.flickableItem.contentY = 0
previousPost = item.content.post previousPost = item.content.post
} }
} }

View file

@ -35,11 +35,6 @@ MenuBar {
Menu { Menu {
visible: menuBar.visible visible: menuBar.visible
title: qsTr("File") title: qsTr("File")
MenuItem {
text: qsTr("Close &Window")
shortcut: "Ctrl+W"
onTriggered: Qt.quit()
}
MenuItem { MenuItem {
text: qsTr("Exit") text: qsTr("Exit")
shortcut: "Ctrl+Q" shortcut: "Ctrl+Q"
@ -137,7 +132,7 @@ MenuBar {
title: qsTr("Help") title: qsTr("Help")
MenuItem { MenuItem {
text: qsTr("About") text: qsTr("About")
onTriggered: Qt.openUrlExternally("http://jeena.net/feedthemonkey/index.html"); onTriggered: Qt.openUrlExternally("http://jabs.nu/feedthemonkey");
} }
} }

View file

@ -21,7 +21,6 @@ import QtQuick 2.3
import QtQuick.Controls 1.3 import QtQuick.Controls 1.3
import QtQuick.Window 2.0 import QtQuick.Window 2.0
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtQuick.Dialogs 1.1
import Qt.labs.settings 1.0 import Qt.labs.settings 1.0
import TTRSS 1.0 import TTRSS 1.0
@ -29,7 +28,7 @@ ApplicationWindow {
id: app id: app
title: "FeedTheMonkey" title: "FeedTheMonkey"
visible: true visible: true
color: nightmode ? "#2d2d2d" : "#eee" color: nightmode ? "#111" : "#eee"
minimumWidth: 480 minimumWidth: 480
minimumHeight: 320 minimumHeight: 320
@ -48,17 +47,6 @@ ApplicationWindow {
property int textFontSizeIndex: defaultTextFontSizeIndex property int textFontSizeIndex: defaultTextFontSizeIndex
property int textFontSize: fontSizes[textFontSizeIndex] property int textFontSize: fontSizes[textFontSizeIndex]
property bool nightmode: false property bool nightmode: false
property bool showMenuBar: false
menuBar: TheMenuBar {
id: menu
serverLogin: serverLogin
server: server
sidebar: sidebar
content: content
visible: app.showMenuBar
__contentItem.visible: visible
}
Settings { Settings {
id: settings id: settings
@ -72,6 +60,14 @@ ApplicationWindow {
property alias nightmode: app.nightmode property alias nightmode: app.nightmode
} }
property TheMenuBar menu: TheMenuBar {
id: menu
serverLogin: serverLogin
server: server
sidebar: sidebar
content: content
}
function loggedIn() { function loggedIn() {
if(serverLogin.loggedIn()) { if(serverLogin.loggedIn()) {
menu.loggedIn = true; menu.loggedIn = true;
@ -113,14 +109,6 @@ ApplicationWindow {
return forEscapingHTML.getText(0, forEscapingHTML.length) return forEscapingHTML.getText(0, forEscapingHTML.length)
} }
function showNextPost() {
sidebar.next()
}
function showPreviousPost() {
sidebar.previous()
}
function keyPressed(event) { function keyPressed(event) {
switch (event.key) { switch (event.key) {
case Qt.Key_Right: case Qt.Key_Right:
@ -159,6 +147,10 @@ ApplicationWindow {
case Qt.Key_Return: case Qt.Key_Return:
Qt.openUrlExternally(content.post.link) Qt.openUrlExternally(content.post.link)
break break
case Qt.Key_S: {
console.log(Qt.openUrlExternally("speaker:"+ removeHTML(content.post.content)))
break
}
default: default:
break break
} }
@ -180,6 +172,7 @@ ApplicationWindow {
content: content content: content
server: server server: server
Layout.minimumWidth: 200
implicitWidth: 300 implicitWidth: 300
textFontSize: app.textFontSize textFontSize: app.textFontSize
nightmode: app.nightmode nightmode: app.nightmode
@ -199,7 +192,7 @@ ApplicationWindow {
Keys.onReleased: { Keys.onReleased: {
switch (event.key) { switch (event.key) {
case Qt.Key_Alt: case Qt.Key_Alt:
app.showMenuBar = !app.showMenuBar app.menuBar = menu
break break
default: default:
break break
@ -213,27 +206,14 @@ ApplicationWindow {
visible: !serverLogin.loggedIn() visible: !serverLogin.loggedIn()
function login() { function login() {
console.log("FOO")
serverLogin.login(serverUrl, userName, password) serverLogin.login(serverUrl, userName, password)
} }
}
MessageDialog {
id: loginErrorAlert
title: "A login error occured"
text: serverLogin.loginError
onAccepted: visible = false
} }
ServerLogin { ServerLogin {
id: serverLogin id: serverLogin
onSessionIdChanged: app.loggedIn() onSessionIdChanged: app.loggedIn()
onLoginErrorChanged: {
console.log("loginError:", loginError)
if(loginError.length > 0) {
loginErrorAlert.visible = true
}
}
} }
Server { Server {

View file

@ -31,7 +31,6 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv); QGuiApplication app(argc, argv);
app.setOrganizationName("Jeena"); app.setOrganizationName("Jeena");
app.setOrganizationDomain("jeena.net"); app.setOrganizationDomain("jeena.net");

View file

@ -28,6 +28,33 @@ Post::Post(QObject *parent) : QObject(parent)
} }
Post::Post(QJsonObject post, QObject *parent) : QObject(parent) Post::Post(QJsonObject post, QObject *parent) : QObject(parent)
{
populateFromJson(post);
}
Post::Post(QJsonObject post, QNetworkAccessManager *networkManager, QObject *parent) : QObject(parent)
{
mNetworkManager = networkManager;
populateFromJson(post);
QObject::connect(this, &Post::contentChanged, [this]() {
QJsonObject obj = QJsonDocument::fromJson(mJsonString.toUtf8()).object();
obj["content"] = QJsonValue(mContent);
QJsonDocument doc(obj);
QString result(doc.toJson(QJsonDocument::Indented));
mJsonString = result;
emit jsonStringChanged(mJsonString);
});
cacheImgs();
}
Post::~Post()
{
}
void Post::populateFromJson(QJsonObject post)
{ {
mTitle = html2text(post.value("title").toString().trimmed()); mTitle = html2text(post.value("title").toString().trimmed());
mFeedTitle = html2text(post.value("feed_title").toString().trimmed()); mFeedTitle = html2text(post.value("feed_title").toString().trimmed());
@ -50,11 +77,6 @@ Post::Post(QJsonObject post, QObject *parent) : QObject(parent)
mJsonString = result; mJsonString = result;
} }
Post::~Post()
{
}
void Post::setRead(bool r) void Post::setRead(bool r)
{ {
if(mRead == r) return; if(mRead == r) return;
@ -77,3 +99,42 @@ QString Post::html2text(const QString htmlString)
doc.setHtml(htmlString); doc.setHtml(htmlString);
return doc.toPlainText(); return doc.toPlainText();
} }
void Post::cacheImgs()
{
QRegExp imgTagRegex("\\<img[^\\>]*src\\s*=\\s*\"([^\"]*)\"[^\\>]*\\>", Qt::CaseInsensitive);
imgTagRegex.setMinimal(true);
QStringList urlmatches;
int offset = 0;
while( (offset = imgTagRegex.indexIn(mContent, offset)) != -1){
offset += imgTagRegex.matchedLength();
urlmatches.append(imgTagRegex.cap(1)); // Should hold only src property
}
for(QString url : urlmatches) {
if(url.startsWith("http")) {
QNetworkRequest request(url);
QNetworkReply *reply = mNetworkManager->get(request);
connect(reply, &QNetworkReply::finished, [url, this, reply] () {
if (reply) {
if (reply->error() == QNetworkReply::NoError) {
QVariant mimeType(reply->header(QNetworkRequest::ContentTypeHeader));
QString imgString = QString("data:") + mimeType.toString() + QString(";base64,") + QString(reply->readAll().toBase64());
if(mimeType == "image/jpeg" || mimeType == "image/gif" || mimeType == "image/png")
{
mContent = mContent.replace(url, imgString);
emit contentChanged(mContent);
}
} else {
int httpStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
//do some error management
qWarning() << "HTTP error: " << httpStatus;
}
reply->deleteLater();
}
});
}
}
}

View file

@ -24,6 +24,7 @@
#include <QUrl> #include <QUrl>
#include <QDate> #include <QDate>
#include <QJsonObject> #include <QJsonObject>
#include <QNetworkReply>
class Post : public QObject class Post : public QObject
{ {
@ -35,16 +36,17 @@ class Post : public QObject
Q_PROPERTY(QString author READ author CONSTANT) Q_PROPERTY(QString author READ author CONSTANT)
Q_PROPERTY(QUrl link READ link CONSTANT) Q_PROPERTY(QUrl link READ link CONSTANT)
Q_PROPERTY(QDateTime date READ date CONSTANT) Q_PROPERTY(QDateTime date READ date CONSTANT)
Q_PROPERTY(QString content READ content CONSTANT) Q_PROPERTY(QString content READ content NOTIFY contentChanged)
Q_PROPERTY(QString excerpt READ excerpt CONSTANT) Q_PROPERTY(QString excerpt READ excerpt CONSTANT)
Q_PROPERTY(bool starred READ starred NOTIFY starredChanged) Q_PROPERTY(bool starred READ starred NOTIFY starredChanged)
Q_PROPERTY(bool read READ read WRITE setRead NOTIFY readChanged) Q_PROPERTY(bool read READ read WRITE setRead NOTIFY readChanged)
Q_PROPERTY(bool dontChangeRead READ dontChangeRead WRITE setDontChangeRead NOTIFY dontChangeReadChanged) Q_PROPERTY(bool dontChangeRead READ dontChangeRead WRITE setDontChangeRead NOTIFY dontChangeReadChanged)
Q_PROPERTY(QString jsonString READ jsonString CONSTANT) Q_PROPERTY(QString jsonString READ jsonString NOTIFY jsonStringChanged)
public: public:
Post(QObject *parent = 0); Post(QObject *parent = 0);
Post(QJsonObject post, QObject *parent = 0); Post(QJsonObject post, QObject *parent = 0);
Post(QJsonObject post, QNetworkAccessManager *networkManager, QObject *parent = 0);
~Post(); ~Post();
QString title() const { return mTitle; } QString title() const { return mTitle; }
QString feedTitle() const { return mFeedTitle; } QString feedTitle() const { return mFeedTitle; }
@ -63,9 +65,11 @@ public:
QString jsonString() const { return mJsonString; } QString jsonString() const { return mJsonString; }
signals: signals:
void contentChanged(QString);
void starredChanged(bool); void starredChanged(bool);
void readChanged(bool); void readChanged(bool);
void dontChangeReadChanged(bool); void dontChangeReadChanged(bool);
void jsonStringChanged(QString);
public slots: public slots:
@ -83,7 +87,11 @@ private:
bool mRead; bool mRead;
bool mDontChangeRead; bool mDontChangeRead;
QString mJsonString; QString mJsonString;
QString html2text(const QString htmlString); QString html2text(const QString htmlString);
void cacheImgs();
void populateFromJson(QJsonObject post);
QNetworkAccessManager *mNetworkManager;
}; };
#endif // POST_H #endif // POST_H

View file

@ -62,7 +62,7 @@ void TinyTinyRSS::reload()
for(int i = 0; i < posts.count(); i++) for(int i = 0; i < posts.count(); i++)
{ {
QJsonObject postJson = posts.at(i).toObject(); QJsonObject postJson = posts.at(i).toObject();
Post *post = new Post(postJson, this); Post *post = new Post(postJson, mNetworkManager, this);
connect(post, SIGNAL(readChanged(bool)), this, SLOT(onPostReadChanged(bool))); connect(post, SIGNAL(readChanged(bool)), this, SLOT(onPostReadChanged(bool)));
mPosts.append(post); mPosts.append(post);
} }

View file

@ -88,47 +88,23 @@ void TinyTinyRSSLogin::reply()
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender()); QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
if (reply) { if (reply) {
if (reply->error() == QNetworkReply::NoError) { if (reply->error() == QNetworkReply::NoError) {
QString jsonString = QString(reply->readAll()); QString jsonString = QString(reply->readAll());
QJsonDocument json = QJsonDocument::fromJson(jsonString.toUtf8()); QJsonDocument json = QJsonDocument::fromJson(jsonString.toUtf8());
if(json.object().value("content").toObject().value("error").toString().length() > 0) { mSessionId = json.object().value("content").toObject().value("session_id").toString();
mLoginError = json.object().value("content").toObject().value("error").toString(); emit sessionIdChanged(mSessionId);
qWarning() << mLoginError;
emit loginErrorChanged(mLoginError);
if(mLoginError == "NOT_LOGGED_IN") { QSettings settings;
mSessionId = nullptr; settings.setValue("sessionId", mSessionId);
mServerUrl = nullptr; settings.setValue("serverUrl", mServerUrl);
settings.sync();
QSettings settings;
settings.remove("sessionId");
settings.remove("serverUrl");
settings.sync();
emit sessionIdChanged(mSessionId);
}
} else {
mSessionId = json.object().value("content").toObject().value("session_id").toString();
emit sessionIdChanged(mSessionId);
QSettings settings;
settings.setValue("sessionId", mSessionId);
settings.setValue("serverUrl", mServerUrl);
settings.sync();
}
} else { } else {
mLoginError = "HTTP error: " int httpStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString() //do some error management
+ " :: " qWarning() << "HTTP error: " << httpStatus << " :: " << reply->error();
+ reply->errorString();
qWarning() << mLoginError;
emit loginErrorChanged(mLoginError);
} }
reply->deleteLater(); reply->deleteLater();
} }

View file

@ -30,14 +30,12 @@ class TinyTinyRSSLogin : public QObject
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString sessionId READ sessionId NOTIFY sessionIdChanged) Q_PROPERTY(QString sessionId READ sessionId NOTIFY sessionIdChanged)
Q_PROPERTY(QUrl serverUrl READ serverUrl) Q_PROPERTY(QUrl serverUrl READ serverUrl)
Q_PROPERTY(QString loginError READ loginError NOTIFY loginErrorChanged)
public: public:
TinyTinyRSSLogin(QObject *parent = 0); TinyTinyRSSLogin(QObject *parent = 0);
~TinyTinyRSSLogin(); ~TinyTinyRSSLogin();
QString sessionId() const { return mSessionId; } QString sessionId() const { return mSessionId; }
QUrl serverUrl() const { return mServerUrl; } QUrl serverUrl() const { return mServerUrl; }
QString loginError() const { return mLoginError; }
Q_INVOKABLE bool loggedIn(); Q_INVOKABLE bool loggedIn();
Q_INVOKABLE void login(const QString serverUrl, const QString user, const QString password); Q_INVOKABLE void login(const QString serverUrl, const QString user, const QString password);
@ -45,7 +43,6 @@ public:
signals: signals:
void sessionIdChanged(QString); void sessionIdChanged(QString);
void loginErrorChanged(QString);
private slots: private slots:
void reply(); void reply();
@ -53,7 +50,6 @@ private slots:
private: private:
QString mSessionId; QString mSessionId;
QUrl mServerUrl; QUrl mServerUrl;
QString mLoginError;
QNetworkAccessManager *mNetworkManager; QNetworkAccessManager *mNetworkManager;
}; };