added Feeds List view
This commit is contained in:
parent
8d32d2a33b
commit
42835577ca
2 changed files with 354 additions and 16 deletions
257
qml/ttrss/Feeds.qml
Normal file
257
qml/ttrss/Feeds.qml
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
//Copyright Hauke Schade, 2012
|
||||
//
|
||||
//This file is part of TTRss.
|
||||
//
|
||||
//TTRss is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the
|
||||
//Free Software Foundation, either version 2 of the License, or (at your option) any later version.
|
||||
//TTRss 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 TTRss (on a Maemo/Meego system there is a copy
|
||||
//in /usr/share/common-licenses. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
import QtQuick 1.1
|
||||
import com.nokia.meego 1.0
|
||||
|
||||
Page {
|
||||
id: feedsPage
|
||||
tools: feedsTools
|
||||
property int categoryId: 0
|
||||
property int numStatusUpdates
|
||||
property bool loading: false
|
||||
property string pageTitle: ""
|
||||
|
||||
anchors.margins: rootWindow.pageMargin
|
||||
|
||||
ListModel {
|
||||
id: feedsModel
|
||||
}
|
||||
|
||||
Component {
|
||||
id: listHeading
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 60
|
||||
radius: 10
|
||||
color: "orange"
|
||||
visible: pageTitle !== ""
|
||||
Text {
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
text: pageTitle
|
||||
font.weight: Font.Bold
|
||||
font.pixelSize: 26
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
anchors.fill: parent
|
||||
model: feedsModel
|
||||
header: listHeading
|
||||
|
||||
delegate: Item {
|
||||
id: listItem
|
||||
height: 88
|
||||
width: parent.width
|
||||
|
||||
BorderImage {
|
||||
id: background
|
||||
anchors.fill: parent
|
||||
// Fill page borders
|
||||
anchors.leftMargin: -feedsPage.anchors.leftMargin
|
||||
anchors.rightMargin: -feedsPage.anchors.rightMargin
|
||||
visible: mouseArea.pressed
|
||||
source: "image://theme/meegotouch-list-background-pressed-center"
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.right: drilldownarrow.left
|
||||
clip: true
|
||||
|
||||
Column {
|
||||
clip: true
|
||||
|
||||
Label {
|
||||
id: mainText
|
||||
text: model.title
|
||||
font.weight: Font.Bold
|
||||
font.pixelSize: 26
|
||||
color: (model.unreadcount > 0) ? "#000033" : "#888888";
|
||||
|
||||
}
|
||||
|
||||
Label {
|
||||
id: subText
|
||||
text: model.subtitle
|
||||
font.weight: Font.Light
|
||||
font.pixelSize: 22
|
||||
color: (model.unreadcount > 0) ? "#cc6633" : "#888888"
|
||||
|
||||
visible: text != ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: drilldownarrow
|
||||
source: "image://theme/icon-m-common-drilldown-arrow" + (theme.inverted ? "-inverse" : "")
|
||||
anchors.right: parent.right;
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: (model.feedId !== null)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: background
|
||||
onClicked: {
|
||||
showFeed(model.feedId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ScrollDecorator {
|
||||
flickableItem: listView
|
||||
}
|
||||
|
||||
function showFeeds() {
|
||||
var ttrss = rootWindow.getTTRSS();
|
||||
var feeds = ttrss.getFeeds(categoryId);
|
||||
var showAll = ttrss.getShowAll();
|
||||
feedsModel.clear();
|
||||
|
||||
if(feeds && categoryId) {
|
||||
var emptyList = feeds.length;
|
||||
var unreadcount;
|
||||
console.log("showing feeds for category: "+categoryId+"\n");
|
||||
|
||||
//First add feed with unread items
|
||||
for(var feed in feeds) {
|
||||
unreadcount = feeds[feed].unread;
|
||||
if( unreadcount && (unreadcount > 0)) {
|
||||
emptyList = false;
|
||||
|
||||
feedsModel.append({
|
||||
title: ttrss.html_entity_decode(feeds[feed].title, 'ENT_QUOTES'),
|
||||
subtitle: "Unread: " + unreadcount,
|
||||
unreadcount: unreadcount,
|
||||
feedId: feeds[feed].id,
|
||||
});
|
||||
}
|
||||
}
|
||||
//If we're showing all feeds, add the ones with no unread items
|
||||
if(showAll) {
|
||||
for(var feed in feeds) {
|
||||
unreadcount = feeds[feed].unread;
|
||||
if(unreadcount === 0) {
|
||||
feedsModel.append({
|
||||
title: ttrss.html_entity_decode(feeds[feed].title,'ENT_QUOTES'),
|
||||
subtitle: "Unread: " + unreadcount,
|
||||
unreadcount: unreadcount,
|
||||
feedId: feeds[feed].id,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(emptyList) {
|
||||
if(showAll ||(feeds.length === 0) ) {
|
||||
feedsModel.append({
|
||||
title: qsTr("No feeds in category"),
|
||||
subtitle: "",
|
||||
feedId: null,
|
||||
unreadCount: 0,
|
||||
});
|
||||
} else {
|
||||
feedsModel.append({
|
||||
title: qsTr("Category has no unread items"),
|
||||
subtitle: "",
|
||||
feedId: null,
|
||||
unreadCount: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onCategoryIdChanged: {
|
||||
var ttrss = rootWindow.getTTRSS();
|
||||
numStatusUpdates = ttrss.getNumStatusUpdates();
|
||||
ttrss.updateFeeds(categoryId, showFeeds);
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
var ttrss = rootWindow.getTTRSS();
|
||||
numStatusUpdates = ttrss.getNumStatusUpdates();
|
||||
ttrss.updateFeeds(categoryId, showFeeds);
|
||||
}
|
||||
onStatusChanged: {
|
||||
var ttrss = rootWindow.getTTRSS();
|
||||
if(status === PageStatus.Deactivating)
|
||||
numStatusUpdates = ttrss.getNumStatusUpdates();
|
||||
else if (status === PageStatus.Activating) {
|
||||
if(ttrss.getNumStatusUpdates() > numStatusUpdates) {
|
||||
numStatusUpdates = ttrss.getNumStatusUpdates();
|
||||
ttrss.updateFeeds(categoryId, showFeeds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showFeed(feedId) {
|
||||
if(feedId !== null) {
|
||||
console.log("Loading items for "+feedId+"\n");
|
||||
var component = Qt.createComponent("ItemList.qml");
|
||||
if (component.status === Component.Ready)
|
||||
pageStack.push(component, { feedId: feedId });
|
||||
else
|
||||
console.log("Error loading component:", component.errorString());
|
||||
}
|
||||
}
|
||||
|
||||
ToolBarLayout {
|
||||
id: feedsTools
|
||||
|
||||
ToolIcon { iconId: "toolbar-back"; onClicked: { feedsMenu.close(); pageStack.pop(); } }
|
||||
ToolIcon {
|
||||
iconId: "toolbar-refresh";
|
||||
visible: !loading;
|
||||
onClicked: { rootWindow.getTTRSS().updateFeeds(categoryId, showFeeds); }
|
||||
}
|
||||
BusyIndicator {
|
||||
visible: loading
|
||||
running: loading
|
||||
platformStyle: BusyIndicatorStyle { size: 'medium' }
|
||||
}
|
||||
ToolIcon { iconId: "toolbar-view-menu" ; onClicked: (feedsMenu.status === DialogStatus.Closed) ? feedsMenu.open() : feedsMenu.close() }
|
||||
}
|
||||
|
||||
Menu {
|
||||
id: feedsMenu
|
||||
visualParent: pageStack
|
||||
|
||||
MenuLayout {
|
||||
MenuItem {
|
||||
id: toggleUnread
|
||||
text: qsTr("Toggle Unread Only")
|
||||
onClicked: {
|
||||
var ttrss = rootWindow.getTTRSS();
|
||||
var oldval = ttrss.getShowAll();
|
||||
var newval = !oldval;
|
||||
ttrss.setShowAll(newval);
|
||||
|
||||
//console.log("Updating categories with showAll: "+newval+"\n");
|
||||
ttrss.updateFeeds(categoryId, showFeeds);
|
||||
}
|
||||
}
|
||||
MenuItem {
|
||||
text: qsTr("About")
|
||||
onClicked: {
|
||||
rootWindow.openFile("About.qml");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,24 +20,26 @@ var state={
|
|||
'password': null,
|
||||
'token': null,
|
||||
'apilevel': 0,
|
||||
// 'categoryunread': null, //category unread counts (created by updateUnread() )
|
||||
// 'feedtree': null, //feeds arranged by category including unread count (created by makeFeedTree() )
|
||||
// 'feedlist': null, //feeds arranged in an associative array (key = id)
|
||||
'numStatusUpdates': 0, //each time the state updates such that the app might want to redisplay we update this (get via getNumStatusUpdates)
|
||||
'showall': false, //boolean should all items be shown (or only those with unread stuff?)
|
||||
'closeIfEmpty': false, //Should pages close if they have no content to display
|
||||
// 'feedcache': {}, //as feed items are retrieved they are stored here for re-use
|
||||
'tracelevel': 4, //1 = errors, 2 = key info, 3 = network traffic, 4 info, 5 high detail
|
||||
|
||||
'categories': {},
|
||||
'feeds': {},
|
||||
'lastcategoryid': null,
|
||||
};
|
||||
|
||||
var requestsPending={
|
||||
'token' : false,
|
||||
'categories' : false,
|
||||
'feeds' : false,
|
||||
};
|
||||
|
||||
var responsesPending={
|
||||
'token' : false,
|
||||
'categories' : false,
|
||||
'feeds' : false,
|
||||
};
|
||||
|
||||
var constants={
|
||||
|
|
@ -157,7 +159,7 @@ function updateCategories(callback) {
|
|||
var params = {
|
||||
'op': 'getCategories',
|
||||
'sid': state['token'],
|
||||
'unread_only': false
|
||||
'unread_only': state['showAll']
|
||||
}
|
||||
|
||||
var http = new XMLHttpRequest();
|
||||
|
|
@ -184,16 +186,8 @@ function process_updateCategories(callback, httpreq) {
|
|||
state['categories'] = {};
|
||||
|
||||
for(var i = 0; i < responseObject.content.length; i++) {
|
||||
if (responseObject.content[i].order_id) {
|
||||
var feedid = responseObject.content[i].order_id;
|
||||
trace(4, "Setting feedlist key:"+feedid);
|
||||
state['categories'][feedid] = responseObject.content[i];
|
||||
}
|
||||
else {
|
||||
// special categories
|
||||
var feedid = responseObject.content[i].id;
|
||||
state['categories'][feedid] = responseObject.content[i];
|
||||
}
|
||||
var feedid = responseObject.content[i].id;
|
||||
state['categories'][feedid] = responseObject.content[i];
|
||||
}
|
||||
// TODO sort
|
||||
}
|
||||
|
|
@ -219,6 +213,78 @@ function process_updateCategories(callback, httpreq) {
|
|||
callback(0);
|
||||
}
|
||||
|
||||
function updateFeeds(catId, callback) {
|
||||
if(responsesPending['feeds'])
|
||||
return;
|
||||
|
||||
// needs to be logged in
|
||||
if(!state['token']) {
|
||||
requestsPending['feeds'] = true;
|
||||
state['lastcategoryid'] = catId;
|
||||
processPendingRequests(callback);
|
||||
return;
|
||||
}
|
||||
|
||||
responsesPending['feeds'] = true;
|
||||
|
||||
var params = {
|
||||
'op': 'getFeeds',
|
||||
'sid': state['token'],
|
||||
'cat_id': catId,
|
||||
'unread_only': state['showAll']
|
||||
}
|
||||
|
||||
var http = new XMLHttpRequest();
|
||||
http.open("POST", state['url'], true);
|
||||
http.setRequestHeader('Content-type','application/json; charset=utf-8');
|
||||
http.onreadystatechange = function() {
|
||||
if (http.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
|
||||
trace(3, "Response Headers -->");
|
||||
trace(3, http.getAllResponseHeaders());
|
||||
}
|
||||
else if (http.readyState === XMLHttpRequest.DONE)
|
||||
process_updateFeeds(catId, callback, http);
|
||||
}
|
||||
http.send(JSON.stringify(params));
|
||||
}
|
||||
|
||||
function process_updateFeeds(catId, callback, httpreq) {
|
||||
trace(3, "readystate: "+httpreq.readyState+" status: "+httpreq.status);
|
||||
trace(3, "response: "+httpreq.responseText);
|
||||
|
||||
if(httpreq.status === 200) {
|
||||
var responseObject=JSON.parse(httpreq.responseText);
|
||||
trace(1,dump(responseObject))
|
||||
if (responseObject.status === 0) {
|
||||
state['feeds'][catId] = [];
|
||||
|
||||
for(var i = 0; i < responseObject.content.length; i++) {
|
||||
var feedid = responseObject.content[i].id;
|
||||
state['feeds'][catId][feedid] = responseObject.content[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(responseObject.content.error)
|
||||
errorText = "Update Feeds failed: "+responseObject.content.error;
|
||||
else
|
||||
errorText = "Update Feeds failed (received http code: "+http.status+")";
|
||||
}
|
||||
}
|
||||
else {
|
||||
trace(1, "Update Feeds Error: received http code: "+httpreq.status+" full text: "+httpreq.responseText);
|
||||
if(callback)
|
||||
callback(40, "Update Feeds Error: received http code: "+httpreq.status+" full text: "+httpreq.responseText);
|
||||
}
|
||||
|
||||
responsesPending['feeds'] = false;
|
||||
|
||||
if(state['feeds'][catId])
|
||||
if(!processPendingRequests(callback))
|
||||
//This action is complete (as there's no other requests to do, fire callback saying all ok
|
||||
if(callback)
|
||||
callback(0);
|
||||
}
|
||||
|
||||
function processPendingRequests(callback) {
|
||||
trace(4, 'In pPR');
|
||||
var foundWork = false;
|
||||
|
|
@ -242,6 +308,17 @@ function processPendingRequests(callback) {
|
|||
else
|
||||
updateCategories(callback);
|
||||
}
|
||||
else if (requestsPending['feeds']) {
|
||||
trace(4, 'feeds request pending');
|
||||
foundWork = true;
|
||||
if(responsesPending['feeds'])
|
||||
return foundWork;
|
||||
if(!state['token'])
|
||||
//Get the auth token
|
||||
login(callback);
|
||||
else
|
||||
updateFeeds(state['lastcategoryid'], callback);
|
||||
}
|
||||
|
||||
return foundWork;
|
||||
}
|
||||
|
|
@ -253,7 +330,7 @@ function getShowAll() {
|
|||
|
||||
//Sets whether only unread items should be shown
|
||||
function setShowAll(showAll) {
|
||||
state['showall'] = showAll;
|
||||
state['showall'] = !!showAll;
|
||||
state['numStatusUpdates']++;
|
||||
}
|
||||
|
||||
|
|
@ -272,3 +349,7 @@ function getNumStatusUpdates() {
|
|||
function getCategories() {
|
||||
return state['categories'];
|
||||
}
|
||||
|
||||
function getFeeds(catId) {
|
||||
return state['feeds'][catId];
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue