...
 
Commits (38)
[main]
host = https://www.transifex.com
[harbour-SailHN.harbour-sailhnts]
file_filter = translations/harbour-sailhn-<lang>.ts
source_file = translations/harbour-sailhn.ts
source_lang = en
type = QT
# harbour-SailHN
# SailHN
An [Hacker News](https://news.ycombinator.com/) unofficial client for [Sailfish OS](https://sailfishos.org).
[![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=ascarpino&url=https://gitlab.com/ascarpino/harbour-SailHN&title=harbour-SailHN&language=&tags=jolla&category=software)
[Build status](https://build.merproject.org/package/live_build_log/home:ilpianista/harbour-sailhn/sailfish_latest_armv7hl/armv8el)
Translations via [Transifex](https://www.transifex.com/organization/ascarpino-harbour/dashboard/harbour-SailHN), thank you!
## Translations
[Build status](https://build.merproject.org/package/live_build_log/home:ilpianista/harbour-sailhn/sailfish_latest_armv7hl/armv8el)
[![Translation status](https://hosted.weblate.org/widgets/harbour-sailhn/-/svg-badge.svg)](https://hosted.weblate.org/engage/harbour-sailhn/?utm_source=widget)
Translations via [Weblate](https://hosted.weblate.org/projects/harbour-sailhn/), thank you!
## Donate
Donations via [Liberapay](https://liberapay.com/ilpianista) or Bitcoin (1Ph3hFEoQaD4PK6MhL3kBNNh9FZFBfisEH) are always welcomed, _thank you_!
## License
MIT
......@@ -4,6 +4,7 @@ CONFIG += sailfishapp
SOURCES += \
src/main.cpp \
src/cookiejar.cpp \
src/hackernewsapi.cpp \
src/hnmanager.cpp \
src/item.cpp \
......@@ -11,6 +12,7 @@ SOURCES += \
src/user.cpp
HEADERS += \
src/cookiejar.h \
src/hackernewsapi.h \
src/hnmanager.h \
src/item.h \
......@@ -24,7 +26,9 @@ OTHER_FILES += \
qml/SailHN.qml \
qml/pages/CommentsPage.qml \
qml/pages/ItemDelegate.qml \
qml/pages/ItemWebView.qml \
qml/pages/AskStoriesPage.qml \
qml/pages/BestStoriesPage.qml \
qml/pages/JobStoriesPage.qml \
qml/pages/NewStoriesPage.qml \
qml/pages/RepliesPage.qml \
......@@ -43,5 +47,8 @@ OTHER_FILES += \
CONFIG += sailfishapp_i18n
TRANSLATIONS += translations/harbour-sailhn-it.ts \
TRANSLATIONS += translations/harbour-sailhn-de.ts \
translations/harbour-sailhn-it.ts \
translations/harbour-sailhn-nl.ts \
translations/harbour-sailhn-sr.ts \
translations/harbour-sailhn-tr.ts
......@@ -45,8 +45,8 @@ Page {
if (!storiesLoadedOnce) {
loadStories();
}
listView.submitEnabled = manager.isAuthenticated();
} else if (status === PageStatus.Active) {
listView.submitEnabled = manager.isAuthenticated();
pageStack.pushAttached(Qt.resolvedUrl("JobStoriesPage.qml"));
} else if (status === PageStatus.Deactivating) {
storiesLoadedOnce = true;
......
/*
The MIT License (MIT)
Copyright (c) 2016 Andrea Scarpino <me@andreascarpino.it>
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.
*/
import QtQuick 2.0
import Sailfish.Silica 1.0
import harbour.sailhn 1.0
Page {
property bool storiesLoadedOnce: false
allowedOrientations: Orientation.All
StoriesListView {
id: listView
anchors.fill: parent
pageTitle: "Best"
onRefreshClicked: loadStories()
}
onStatusChanged: {
if (status === PageStatus.Activating) {
if (!storiesLoadedOnce) {
loadStories();
}
} else if (status === PageStatus.Active) {
listView.submitEnabled = manager.isAuthenticated();
} else if (status === PageStatus.Deactivating) {
storiesLoadedOnce = true;
}
}
function loadStories() {
listView.stories.loadBestStories();
}
}
......@@ -47,6 +47,13 @@ Page {
contentHeight: column.height
PullDownMenu {
MenuItem {
text: qsTr("Copy external url")
onClicked: {
Clipboard.text = url;
}
}
MenuItem {
id: reply
......@@ -163,6 +170,14 @@ Page {
reply.enabled = manager.isAuthenticated();
}
onStatusChanged: {
if (status == PageStatus.Active) {
if (url && !(/^\s*$/.test(url))) {
pageStack.pushAttached(Qt.resolvedUrl("ItemWebView.qml"), { itemUrl: url });
}
}
}
function loadComments() {
model.loadComments(kids);
}
......
......@@ -27,9 +27,10 @@ import Sailfish.Silica 1.0
ListItem {
width: ListView.view.width
menu: menu
height: col.height
Column {
id: col
x: Theme.horizontalPageMargin
width: parent.width - Theme.horizontalPageMargin * 2
......@@ -39,6 +40,8 @@ ListItem {
text: title
font.pixelSize: Theme.fontSizeMedium
truncationMode: TruncationMode.Fade
maximumLineCount: 2
wrapMode: Text.WordWrap
}
Label {
......@@ -81,18 +84,4 @@ ListItem {
url: url
});
}
ContextMenu {
id: menu
MenuItem {
text: qsTr("Open external url")
enabled: (url && !(/^\s*$/.test(url)))
onClicked: {
console.log("Opening external browser: " + url);
Qt.openUrlExternally(url);
}
}
}
}
/*
The MIT License (MIT)
Copyright (c) 2016 Andrea Scarpino <me@andreascarpino.it>
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.
*/
import QtQuick 2.0
import Sailfish.Silica 1.0
Page {
property var itemUrl
allowedOrientations: Orientation.All
SilicaWebView {
anchors.fill: parent
url: itemUrl
}
}
......@@ -45,7 +45,9 @@ Page {
if (!storiesLoadedOnce) {
loadStories();
}
} else if (status === PageStatus.Active) {
listView.submitEnabled = manager.isAuthenticated();
pageStack.pushAttached(Qt.resolvedUrl("BestStoriesPage.qml"));
} else if (status === PageStatus.Deactivating) {
storiesLoadedOnce = true;
}
......
......@@ -45,8 +45,8 @@ Page {
if (!storiesLoadedOnce) {
loadStories();
}
listView.submitEnabled = manager.isAuthenticated();
} else if (status === PageStatus.Active) {
listView.submitEnabled = manager.isAuthenticated();
pageStack.pushAttached(Qt.resolvedUrl("ShowStoriesPage.qml"));
} else if (status === PageStatus.Deactivating) {
storiesLoadedOnce = true;
......
......@@ -79,8 +79,9 @@ Page {
TextField {
id: username
width: parent.width
focus: true
placeholderText: qsTr("Username")
onTextChanged: login.enabled = (text.length > 0 && password.text.length > 0)
}
TextField {
......@@ -88,20 +89,21 @@ Page {
width: parent.width
placeholderText: qsTr("Password")
echoMode: TextInput.Password
onTextChanged: login.enabled = (text.length > 0 && username.text.length > 0)
}
Button {
id: login
text: qsTr("Login");
anchors.horizontalCenter: parent.horizontalCenter
enabled: false
onClicked: {
if (username.text.length > 0 && password.text.length > 0) {
manager.authenticate(username.text, password.text);
login.enabled = false;
busy.visible = busy.running = true;
msg.visible = false;
}
manager.authenticate(username.text.trim(), password.text.trim());
login.enabled = false;
busy.visible = busy.running = true;
msg.visible = false;
}
}
......@@ -160,6 +162,12 @@ Page {
}
Component.onCompleted: {
username.text = manager.getUsername();
if (username.text.length > 0) {
password.forceActiveFocus();
}
var isAuth = manager.isAuthenticated();
isAuthenticated(isAuth);
......@@ -169,7 +177,7 @@ Page {
}
function isAuthenticated(isAuth) {
username.enabled = password.enabled = login.enabled = !isAuth;
username.enabled = password.enabled = !isAuth;
logout.enabled = isAuth;
if (isAuth) {
......@@ -177,14 +185,12 @@ Page {
} else {
login.text = qsTr("Login");
details.visible = false;
username.text = "";
password.text = "";
}
}
function updateDetails() {
var user = manager.loggedUser();
username.text = user.id;
details.visible = true;
created.value = Qt.formatDateTime(user.created);
karma.value = user.karma;
......
......@@ -45,8 +45,8 @@ Page {
if (!storiesLoadedOnce) {
loadStories();
}
listView.submitEnabled = manager.isAuthenticated();
} else if (status === PageStatus.Active) {
listView.submitEnabled = manager.isAuthenticated();
pageStack.pushAttached(Qt.resolvedUrl("AskStoriesPage.qml"));
} else if (status === PageStatus.Deactivating) {
storiesLoadedOnce = true;
......
......@@ -30,11 +30,19 @@ SilicaListView {
id: listView
property string pageTitle
property bool submitEnabled
property alias submitEnabled: submit.enabled
property alias stories: model
signal refreshClicked
Connections {
target: manager
onLoggedUserFetched: {
submit.enabled = true;
}
}
PullDownMenu {
MenuItem {
......@@ -44,8 +52,9 @@ SilicaListView {
}
MenuItem {
id: submit
text: qsTr("Submit")
enabled: submitEnabled
enabled: false
onClicked: pageStack.push(Qt.resolvedUrl("Submit.qml"))
}
......
......@@ -65,12 +65,16 @@ Page {
width: parent.width
focus: true
placeholderText: qsTr("Title")
onTextChanged: submit.enabled = (text.length > 0 && (url.text.length > 0 || itemText.text.length > 0))
}
TextField {
id: url
width: parent.width
placeholderText: qsTr("Url")
onTextChanged: submit.enabled = (title.text.length > 0 && (text.length > 0 || itemText.text.length > 0))
}
Label {
......@@ -80,23 +84,24 @@ Page {
}
TextArea {
id: text
id: itemText
width: parent.width
placeholderText: qsTr("Text")
onTextChanged: submit.enabled = (title.text.length > 0 && (url.text.length > 0 || text.length > 0))
}
Button {
id: submit
text: qsTr("Submit");
anchors.horizontalCenter: parent.horizontalCenter
enabled: false
onClicked: {
if (title.text.length > 0 && (url.text.length > 0 || text.text.length > 0)) {
manager.submit(title.text, url.text, text.text);
submit.enabled = false;
busy.visible = busy.running = true;
msg.visible = false;
}
manager.submit(title.text, url.text, itemText.text);
submit.enabled = false;
busy.visible = busy.running = true;
msg.visible = false;
}
}
......
......@@ -45,8 +45,8 @@ Page {
if (!storiesLoadedOnce) {
loadStories();
}
listView.submitEnabled = manager.isAuthenticated();
} else if (status === PageStatus.Active) {
listView.submitEnabled = manager.isAuthenticated();
pageStack.pushAttached(Qt.resolvedUrl("NewStoriesPage.qml"));
} else if (status === PageStatus.Deactivating) {
storiesLoadedOnce = true;
......
* Thu Mar 04 2016 Andrea Scarpino <me@andreascarpino.it> 0.8.1-1
* Sat Oct 29 2016 Andrea Scarpino <me@andreascarpino.it> 0.8.4-1
- Add 'Copy external url' menu item
- Drop 'Open external url' menu item
* Wed Jul 13 2016 Andrea Scarpino <me@andreascarpino.it> 0.8.3-1
- Add Serbian and Dutch translations
* Fri Jun 22 2016 Andrea Scarpino <me@andreascarpino.it> 0.8.2-1
- Add 'quick browser view' from item
* Fri Jun 03 2016 Andrea Scarpino <me@andreascarpino.it> 0.8.1-1
- Add the capability to post comments
- Fix new comments non visible when refreshing
- Show logged user details in the settings
- Save the username
- Support Best stories
* Thu Mar 03 2016 Andrea Scarpino <me@andreascarpino.it> 0.8-1
- Implement authentication
......
......@@ -13,7 +13,7 @@ Name: harbour-sailhn
%{!?qtc_make:%define qtc_make make}
%{?qtc_builddir:%define _builddir %qtc_builddir}
Summary: Unofficial Hacker News client
Version: 0.8
Version: 0.8.4
Release: 1
Group: Qt/Qt
License: MIT
......
Name: harbour-sailhn
Summary: Unofficial Hacker News client
Version: 0.8
Version: 0.8.4
Release: 1
# The contents of the Group field should be one of the groups listed here:
# http://gitorious.org/meego-developer-tools/spectacle/blobs/master/data/GROUPS
......@@ -32,7 +32,7 @@ PkgConfigBR:
# Runtime dependencies which are not automatically detected
Requires:
- sailfishsilica-qt5 >= 0.10.9
- sailfishsilica-qt5 >= 0.10.9
# All installed files
Files:
......
/**
* The MIT License (MIT)
*
* Copyright (c) 2015 Nathan Osman
* 2016 Andrea Scarpino <me@andreascarpino.it>
*
* 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.
**/
#include "cookiejar.h"
#include <QCoreApplication>
#include <QNetworkCookie>
#include <QSettings>
#include <QVariantList>
CookieJar::CookieJar(QObject *parent) :
QNetworkCookieJar(parent)
{
// Load the list of cookies
m_settings = new QSettings(QCoreApplication::applicationName(), QCoreApplication::applicationName(), this);
// Read and parse each of the cookies
QList<QNetworkCookie> cookies;
Q_FOREACH (const QVariant cookie, m_settings->value("Cookies").toList()) {
cookies.append(QNetworkCookie::parseCookies(cookie.toByteArray()));
}
// Set the list
setAllCookies(cookies);
}
CookieJar::~CookieJar()
{
// Build a list of all cookies
QVariantList cookies;
Q_FOREACH (const QNetworkCookie cookie, allCookies()) {
cookies.append(cookie.toRawForm());
}
// Store the list
m_settings->setValue("Cookies", cookies);
m_settings->deleteLater();
}
/**
* The MIT License (MIT)
*
* Copyright (c) 2015 Nathan Osman
* 2016 Andrea Scarpino <me@andreascarpino.it>
*
* 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.
**/
#ifndef COOKIEJAR_H
#define COOKIEJAR_H
#include <QNetworkCookieJar>
class QSettings;
class CookieJar : public QNetworkCookieJar
{
Q_OBJECT
public:
explicit CookieJar(QObject *parent);
virtual ~CookieJar();
private:
QSettings *m_settings;
};
#endif // COOKIEJAR_H
......@@ -77,6 +77,7 @@ void HackerNewsAPI::getStories(Stories kind)
QString path;
switch (kind) {
case Ask: path = QStringLiteral("/askstories.json"); break;
case Best: path = QStringLiteral("/beststories.json"); break;
case Job: path = QStringLiteral("/jobstories.json"); break;
case New: path = QStringLiteral("/newstories.json"); break;
case Show: path = QStringLiteral("/showstories.json"); break;
......@@ -210,7 +211,7 @@ void HackerNewsAPI::onStoriesResult()
} else {
QJsonDocument json = QJsonDocument::fromJson(reply->readAll());
if (!json.isNull()) {
qDebug() << "There are" << json.array().size() << "items";
//qDebug() << "There are" << json.array().size() << "items";
QList<int> ids;
Q_FOREACH (const QJsonValue id, json.array()) {
......
......@@ -37,7 +37,7 @@ class HackerNewsAPI : public QObject
Q_OBJECT
public:
enum Stories {
New, Top, Show, Ask, Job
New, Top, Show, Ask, Job, Best
};
explicit HackerNewsAPI(QObject *parent = 0);
......
......@@ -24,16 +24,19 @@
#include "hnmanager.h"
#include <QCoreApplication>
#include <QDebug>
#include <QEventLoop>
#include <QNetworkAccessManager>
#include <QNetworkCookieJar>
#include <QNetworkCookie>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
#include <QSettings>
#include <QUrlQuery>
#include "cookiejar.h"
#include "hackernewsapi.h"
const static QString BASE_URL = QStringLiteral("https://news.ycombinator.com");
......@@ -43,9 +46,17 @@ HNManager::HNManager(QObject *parent) :
, api(new HackerNewsAPI(this))
, network(new QNetworkAccessManager(this))
, m_loggedUser(0)
, m_loggedUsername(QString())
{
network->setCookieJar(new QNetworkCookieJar(this));
m_settings = new QSettings(QCoreApplication::applicationName(), QCoreApplication::applicationName(), this);
setUsername(m_settings->value("Username").toString());
network->setCookieJar(new CookieJar(this));
if (!network->cookieJar()->cookiesForUrl(QUrl(BASE_URL + "/")).isEmpty()) {
api->getUser(getUsername());
connect(api, &HackerNewsAPI::userFetched, this, &HNManager::onLoggedUserFetched);
}
}
HNManager::~HNManager()
......@@ -53,12 +64,13 @@ HNManager::~HNManager()
delete api;
delete network;
delete m_loggedUser;
delete m_settings;
}
void HNManager::authenticate(const QString &username, const QString &password)
{
qDebug() << "Log in with username" << username;
m_loggedUsername = username;
setUsername(username);
QNetworkRequest req(QUrl(BASE_URL + QLatin1String("/login")));
req.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/x-www-form-urlencoded"));
......@@ -104,9 +116,20 @@ void HNManager::onLoggedUserFetched(User *user)
bool HNManager::isAuthenticated() const
{
//qDebug() << "Is authenticated as:" << m_loggedUsername;
//qDebug() << "Is authenticated as:" << m_loggedUser;
return !m_loggedUsername.isEmpty();
return m_loggedUser != 0;
}
void HNManager::setUsername(const QString &username)
{
m_loggedUsername = username;
m_settings->setValue("Username", username);
}
QString HNManager::getUsername() const
{
return m_loggedUsername;
}
User* HNManager::loggedUser()
......@@ -116,11 +139,14 @@ User* HNManager::loggedUser()
void HNManager::logout()
{
m_loggedUsername.clear();
setUsername(QString());
m_loggedUser = 0;
// FIXME: is there a better way?
network->cookieJar()->deleteLater();
network->setCookieJar(new QNetworkCookieJar(this));
QNetworkCookieJar* cookieJar = network->cookieJar();
Q_FOREACH (const QNetworkCookie cookie, cookieJar->cookiesForUrl(QUrl(BASE_URL + "/"))) {
cookieJar->deleteCookie(cookie);
}
m_settings->setValue("Cookies", QVariantList());
}
void HNManager::submit(const QString &title, const QString &url, const QString &text)
......
......@@ -34,6 +34,7 @@ class HackerNewsAPI;
class QNetworkAccessManager;
class QNetworkReply;
class QRegularExpression;
class QSettings;
class HNManager : public QObject
{
......@@ -46,6 +47,7 @@ public:
Q_INVOKABLE void authenticate(const QString &username, const QString &password);
Q_INVOKABLE bool isAuthenticated() const;
Q_INVOKABLE User* loggedUser();
Q_INVOKABLE QString getUsername() const;
Q_INVOKABLE void logout();
Q_INVOKABLE void submit(const QString &title, const QString &url, const QString &text);
Q_INVOKABLE void comment(const int parentId, const QString &text);
......@@ -65,11 +67,13 @@ private:
QString getSubmitCSRF() const;
QString getCommentCSRF(const int itemId) const;
QString getCSRF(QNetworkReply *reply, const QRegularExpression &regexp) const;
void setUsername(const QString &username);
HackerNewsAPI *api;
QNetworkAccessManager *network;
User *m_loggedUser;
QString m_loggedUsername;
QSettings *m_settings;
};
#endif // HNMANAGER_H
......@@ -35,6 +35,9 @@ int main(int argc, char *argv[])
QScopedPointer<QGuiApplication> app(SailfishApp::application(argc, argv));
QScopedPointer<QQuickView> view(SailfishApp::createView());
QCoreApplication::setApplicationName(QStringLiteral("harbour-sailhn"));
QCoreApplication::setOrganizationDomain(QStringLiteral("andreascarpino.it"));
qmlRegisterType<NewsModel>("harbour.sailhn", 1, 0, "NewsModel");
qmlRegisterType<User>("harbour.sailhn", 1, 0, "User");
......
......@@ -73,6 +73,13 @@ void NewsModel::loadAskStories()
api->getStories(HackerNewsAPI::Ask);
}
void NewsModel::loadBestStories()
{
reset();
api->getStories(HackerNewsAPI::Best);
}
void NewsModel::loadNewStories()
{
reset();
......
......@@ -57,6 +57,7 @@ public:
QHash<int, QByteArray> roleNames() const;
Q_INVOKABLE void loadAskStories();
Q_INVOKABLE void loadBestStories();
Q_INVOKABLE void loadNewStories();
Q_INVOKABLE void loadJobStories();
Q_INVOKABLE void loadShowStories();
......
<?xml version="1.0" ?><!DOCTYPE TS><TS language="de" version="2.1">
<context>
<name>CommentsPage</name>
<message>
<location filename="../qml/pages/CommentsPage.qml" line="51"/>
<source>Copy external url</source>
<translation>Externe URL kopieren</translation>
</message>
<message>
<location filename="../qml/pages/CommentsPage.qml" line="60"/>
<source>Reply</source>
<translation>Antworten</translation>
</message>
<message>
<location filename="../qml/pages/CommentsPage.qml" line="67"/>
<source>Refresh</source>
<translation>Aktualisieren</translation>
</message>
<message>
<location filename="../qml/pages/CommentsPage.qml" line="80"/>
<source>Load more</source>
<translation>Mehr laden</translation>
</message>
<message>
<location filename="../qml/pages/CommentsPage.qml" line="96"/>
<source>Comments</source>
<translation>Kommentare</translation>
</message>
</context>
<context>
<name>ItemDelegate</name>
<message>
<location filename="../qml/pages/ItemDelegate.qml" line="52"/>
<source>point</source>
<translation>Punkt</translation>
</message>
<message>
<location filename="../qml/pages/ItemDelegate.qml" line="54"/>
<source>points</source>
<translation>Punkte</translation>
</message>
<message>
<location filename="../qml/pages/ItemDelegate.qml" line="60"/>
<source>comment</source>
<translation>Kommentar</translation>
</message>
<message>
<location filename="../qml/pages/ItemDelegate.qml" line="62"/>
<source>comments</source>
<translation>Kommentare</translation>
</message>
</context>
<context>
<name>RepliesPage</name>
<message>
<location filename="../qml/pages/RepliesPage.qml" line="48"/>
<source>Reply</source>
<translation>Antworten</translation>
</message>
<message>
<location filename="../qml/pages/RepliesPage.qml" line="55"/>
<source>Refresh</source>
<translation>Aktualisieren</translation>
</message>
<message>
<location filename="../qml/pages/RepliesPage.qml" line="68"/>
<source>Load more</source>
<translation>Mehr laden</translation>
</message>
<message>
<location filename="../qml/pages/RepliesPage.qml" line="84"/>
<source>Replies</source>
<translation>Antworten</translation>
</message>
</context>
<context>
<name>Reply</name>
<message>
<location filename="../qml/pages/Reply.qml" line="44"/>
<source>Error when sending</source>
<translation>Fehler beim Absenden</translation>
</message>
<message>
<location filename="../qml/pages/Reply.qml" line="46"/>
<source>Commented!</source>
<translation>Kommentar abgeschickt!</translation>
</message>
<message>
<location filename="../qml/pages/Reply.qml" line="61"/>
<source>Reply</source>
<translation>Antworten</translation>
</message>
<message>
<location filename="../qml/pages/Reply.qml" line="68"/>
<source>Text</source>
<translation>Text</translation>
</message>
<message>
<location filename="../qml/pages/Reply.qml" line="73"/>
<source>Add Comment</source>
<translation>Kommentar hinzufügen</translation>
</message>
</context>
<context>
<name>ReplyDelegate</name>
<message>
<location filename="../qml/pages/ReplyDelegate.qml" line="59"/>
<source>reply</source>
<translation>Antwort</translation>
</message>
<message>
<location filename="../qml/pages/ReplyDelegate.qml" line="61"/>
<source>replies</source>
<translation>Antworten</translation>
</message>
</context>
<context>
<name>Settings</name>
<message>
<location filename="../qml/pages/Settings.qml" line="61"/>
<source>Logout</source>
<translation>Abmelden</translation>
</message>
<message>
<location filename="../qml/pages/Settings.qml" line="113"/>
<source>Login failed</source>
<translation>Anmeldung fehlgeschlagen</translation>
</message>
<message>
<location filename="../qml/pages/Settings.qml" line="76"/>
<source>Settings</source>
<translation>Einstellungen</translation>
</message>
<message>
<location filename="../qml/pages/Settings.qml" line="82"/>
<source>Username</source>
<translation>Benutzername</translation>
</message>
<message>
<location filename="../qml/pages/Settings.qml" line="90"/>
<source>Password</source>
<translation>Passwort</translation>
</message>
<message>
<location filename="../qml/pages/Settings.qml" line="98"/>
<location filename="../qml/pages/Settings.qml" line="186"/>
<source>Login</source>
<translation>Anmelden</translation>
</message>
<message>
<location filename="../qml/pages/Settings.qml" line="130"/>
<source>User details</source>
<translation>Nutzerdetails</translation>
</message>
<message>
<location filename="../qml/pages/Settings.qml" line="136"/>
<source>created</source>
<translation>erstellt</translation>
</message>
<message>
<location filename="../qml/pages/Settings.qml" line="142"/>
<source>karma</source>
<translation>Karma</translation>
</message>
<message>
<location filename="../qml/pages/Settings.qml" line="148"/>
<source>About</source>
<translation>Über</translation>
</message>
<message>
<location filename="../qml/pages/Settings.qml" line="184"/>
<source>Logged</source>
<translation>Angemeldet</translation>
</message>
</context>
<context>
<name>StoriesListView</name>
<message>
<location filename="../qml/pages/StoriesListView.qml" line="49"/>
<source>Settings</source>
<translation>Einstellungen</translation>
</message>
<message>
<location filename="../qml/pages/StoriesListView.qml" line="56"/>
<source>Submit</source>
<translation>Absenden</translation>
</message>
<message>
<location filename="../qml/pages/StoriesListView.qml" line="63"/>
<source>Refresh</source>
<translation>Aktualisieren</translation>
</message>
<message>
<location filename="../qml/pages/StoriesListView.qml" line="72"/>
<source>Load more</source>
<translation>Mehr laden</translation>
</message>
</context>
<context>
<name>Submit</name>
<message>
<location filename="../qml/pages/Submit.qml" line="45"/>
<source>Submitted!</source>
<translation>Abgesendet!</translation>
</message>
<message>
<location filename="../qml/pages/Submit.qml" line="60"/>
<location filename="../qml/pages/Submit.qml" line="96"/>
<source>Submit</source>
<translation>Absenden</translation>
</message>
<message>
<location filename="../qml/pages/Submit.qml" line="67"/>
<source>Title</source>
<translation>Titel</translation>
</message>
<message>
<location filename="../qml/pages/Submit.qml" line="75"/>
<source>Url</source>
<translation>Url</translation>
</message>
<message>
<location filename="../qml/pages/Submit.qml" line="81"/>
<source>or</source>
<translation>oder</translation>
</message>
<message>
<location filename="../qml/pages/Submit.qml" line="89"/>
<source>Text</source>
<translation>Text</translation>
</message>
<message>
<location filename="../qml/pages/Submit.qml" line="43"/>
<source>Error during submission</source>
<translation>Fehler beim Senden</translation>
</message>
</context>
</TS>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="et">
<context>
<name>CommentsPage</name>
<message>
<location filename="../qml/pages/CommentsPage.qml" line="51"/>
<source>Copy external url</source>
<translation>Kopeeri väline URL</translation>
</message>
<message>
<location filename="../qml/pages/CommentsPage.qml" line="60"/>
<source>Reply</source>
<translation>Vasta</translation>
</message>
<message>
<location filename="../qml/pages/CommentsPage.qml" line="67"/>
<source>Refresh</source>
<translation>Uuenda</translation>
</message>
<message>
<location filename="../qml/pages/CommentsPage.qml" line="80"/>
<source>Load more</source>
<translation>Laadi veel</translation>
</message>
<message>
<location filename="../qml/pages/CommentsPage.qml" line="96"/>
<source>Comments</source>
<translation>Kommentaarid</translation>
</message>
</context>
<context>
<name>ItemDelegate</name>
<message>
<location filename="../qml/pages/ItemDelegate.qml" line="52"/>
<source>point</source>
<translation>punkt</translation>
</message>
<message>
<location filename="../qml/pages/ItemDelegate.qml" line="54"/>
<source>points</source>
<translation>punktid</translation>
</message>
<message>
<location filename="../qml/pages/ItemDelegate.qml" line="60"/>
<source>comment</source>
<translation>kommentaar</translation>
</message>
<message>
<location filename="../qml/pages/ItemDelegate.qml" line="62"/>
<source>comments</source>
<translation>kommentaarid</translation>
</message>
</context>
<context>
<name>RepliesPage</name>
<message>
<location filename="../qml/pages/RepliesPage.qml" line="48"/>
<source>Reply</source>
<translation>Vasta</translation>
</message>
<message>
<location filename="../qml/pages/RepliesPage.qml" line="55"/>
<source>Refresh</source>
<translation>Uuenda</translation>
</message>
<message>
<location filename="../qml/pages/RepliesPage.qml" line="68"/>
<source>Load more</source>
<translation>Laadi veel</translation>
</message>
<message>
<location filename="../qml/pages/RepliesPage.qml" line="84"/>
<source>Replies</source>
<translation>Vastused</translation>
</message>
</context>
<context>
<name>Reply</name>
<message>
<location filename="../qml/pages/Reply.qml" line="44"/>
<source>Error when sending</source>
<translation>Viga saatmisel</translation>
</message>
<message>
<location filename="../qml/pages/Reply.qml" line="46"/>
<source>Commented!</source>
<translation>Kommenteeritud!</translation>
</message>
<message>
<location filename="../qml/pages/Reply.qml" line="61"/>
<source>Reply</source>
<translation>Vasta</translation>
</message>
<message>
<location filename="../qml/pages/Reply.qml" line="68"/>
<source>Text</source>
<translation>Tekst</translation>
</message>
<message>
<location filename="../qml/pages/Reply.qml" line="73"/>
<source>Add Comment</source>
<translation>Lisa kommentaar</translation>
</message>
</context>
<context>
<name>ReplyDelegate</name>
<message>
<location filename="../qml/pages/ReplyDelegate.qml" line="59"/>
<source>reply</source>
<translation>vastus</translation>
</message>
<message>
<location filename="../qml/pages/ReplyDelegate.qml" line="61"/>
<source>replies</source>
<translation>vastused</translation>
</message>
</context>
<context>
<name>Settings</name>
<message>
<location filename="../qml/pages/Settings.qml" line="61"/>
<source>Logout</source>
<translation>Logi välja</translation>
</message>
<message>
<location filename="../qml/pages/Settings.qml" line="113"/>
<source>Login failed</source>
<translation>Sisselogimine nurjus</translation>
</message>
<message>
<location filename="../qml/pages/Settings.qml" line="76"/>
<source>Settings</source>
<translation>Seaded</translation>
</message>
<message>
<location filename="../qml/pages/Settings.qml" line="82"/>
<source>Username</source>
<translation>Kasutajanimi</translation>
</message>
<message>
<location filename="../qml/pages/Settings.qml" line="90"/>
<source>Password</source>
<translation>Parool</translation>
</message>
<message>
<location filename="../qml/pages/Settings.qml" line="98"/>
<location filename="../qml/pages/Settings.qml" line="186"/>
<source>Login</source>
<translation>Logi sisse</translation>
</message>
<message>
<location filename="../qml/pages/Settings.qml" line="130"/>
<source>User details</source>
<translation>Kasutaja andmed</translation>
</message>
<message>
<location filename="../qml/pages/Settings.qml" line="136"/>
<source>created</source>
<translation>loodud</translation>
</message>
<message>
<location filename="../qml/pages/Settings.qml" line="142"/>
<source>karma</source>
<translation></translation>
</message>
<message>
<location filename="../qml/pages/Settings.qml" line="148"/>
<source>About</source>
<translation>Teave</translation>
</message>
<message>
<location filename="../qml/pages/Settings.qml" line="184"/>
<source>Logged</source>
<translation>Sisse logitud</translation>
</message>
</context>
<context>
<name>StoriesListView</name>
<message>
<location filename="../qml/pages/StoriesListView.qml" line="49"/>
<source>Settings</source>
<translation>Seaded</translation>
</message>
<message>
<location filename="../qml/pages/StoriesListView.qml" line="56"/>
<source>Submit</source>
<translation>Saada</translation>
</message>
<message>
<location filename="../qml/pages/StoriesListView.qml" line="63"/>
<source>Refresh</source>
<translation>Uuenda</translation>
</message>
<message>
<location filename="../qml/pages/StoriesListView.qml" line="72"/>
<source>Load more</source>
<translation>Laadi veel</translation>
</message>
</context>
<context>
<name>Submit</name>
<message>
<location filename="../qml/pages/Submit.qml" line="45"/>
<source>Submitted!</source>
<translation>Saadetud!</translation>
</message>
<message>
<location filename="../qml/pages/Submit.qml" line="60"/>
<location filename="../qml/pages/Submit.qml" line="96"/>
<source>Submit</source>
<translation>Saada</translation>
</message>
<message>
<location filename="../qml/pages/Submit.qml" line="67"/>
<source>Title</source>
<translation>Pealkiri</translation>
</message>
<message>
<location filename="../qml/pages/Submit.qml" line="75"/>
<source>Url</source>
<translation></translation>
</message>
<message>
<location filename="../qml/pages/Submit.qml" line="81"/>
<source>or</source>
<translation>või</translation>
</message>
<message>
<location filename="../qml/pages/Submit.qml" line="89"/>
<source>Text</source>
<translation>Tekst</translation>
</message>
<message>
<location filename="../qml/pages/Submit.qml" line="43"/>
<source>Error during submission</source>
<translation>Viga saatmisel</translation>
</message>
</context>
</TS>
This diff is collapsed.
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="nb_NO">
<context>
<name>CommentsPage</name>
<message>
<location filename="../qml/pages/CommentsPage.qml" line="51"/>
<source>Copy external url</source>
<translation>Kopier ekstern nettadresse</translation>
</message>
<message>
<location filename="../qml/pages/CommentsPage.qml" line="60"/>
<source>Reply</source>
<translation>Svar</translation>
</message>
<message>
<location filename="../qml/pages/CommentsPage.qml" line="67"/>
<source>Refresh</source>
<translation>Gjenoppfrisk</translation>
</message>
<message>
<location filename="../qml/pages/CommentsPage.qml" line="80"/>
<source>Load more</source>
<translation>Last inn flere</translation>
</message>
<message>
<location filename="../qml/pages/CommentsPage.qml" line="96"/>
<source>Comments</source>
<translation>Kommentarer</translation>
</message>
</context>
<context>
<name>ItemDelegate</name>
<message>
<location filename="../qml/pages/ItemDelegate.qml" line="52"/>
<source>point</source>
<translation></translation>
</message>
<message>
<location filename="../qml/pages/ItemDelegate.qml" line="54"/>
<source>points</source>
<translation>poeng</translation>
</message>
<message>
<location filename="../qml/pages/ItemDelegate.qml" line="60"/>
<source>comment</source>
<translation>kommentar</translation>
</message>
<message>
<location filename="../qml/pages/ItemDelegate.qml" line="62"/>
<source>comments</source>
<translation>kommentarer</translation>
</message>
</context>
<context>
<name>RepliesPage</name>
<message>
<location filename="../qml/pages/RepliesPage.qml" line="48"/>
<source>Reply</source>
<translation>Svar</translation>
</message>
<message>
<location filename="../qml/pages/RepliesPage.qml" line="55"/>
<source>Refresh</source>
<translation>Gjenoppfrisk</translation>
</message>
<message>
<location filename="../qml/pages/RepliesPage.qml" line="68"/>
<source>Load more</source>
<translation>Last inn flere</translation>
</message>
<message>
<location filename="../qml/pages/RepliesPage.qml" line="84"/>
<source>Replies</source>
<translation>Svar</translation>
</message>
</context>
<context>
<name>Reply</name>
<message>
<location filename="../qml/pages/Reply.qml" line="44"/>
<source>Error when sending</source>
<translation>Feil under forsendelse</translation>
</message>
<message>
<location filename="../qml/pages/Reply.qml" line="46"/>
<source>Commented!</source>
<translation>Kommenterte!</translation>
</message>
<message>
<location filename="../qml/pages/Reply.qml" line="61"/>
<source>Reply</source>
<translation>Svar</translation>
</message>
<message>
<location filename="../qml/pages/Reply.qml" line="68"/>
<source>Text</source>
<translation></translation>
</message>
<message>