Merge branch 'michael-k-labels'
Conflicts: qml/ttrss/models/FeedItemModel.qml
This commit is contained in:
commit
9ef6d8d796
6 changed files with 383 additions and 9 deletions
|
|
@ -29,7 +29,7 @@ Rectangle {
|
|||
|
||||
width: text.width + MyTheme.paddingSmall + MyTheme.paddingSmall
|
||||
height: text.height + MyTheme.paddingSmall
|
||||
color: root.label.bgcolor
|
||||
color: root.label.bg_color
|
||||
radius: MyTheme.paddingSmall
|
||||
anchors.margins: MyTheme.paddingSmall
|
||||
Text {
|
||||
|
|
@ -38,8 +38,8 @@ Rectangle {
|
|||
horizontalCenter: root.horizontalCenter
|
||||
}
|
||||
id: text
|
||||
text: root.label.text
|
||||
color: root.label.fgcolor
|
||||
text: root.label.caption
|
||||
color: root.label.fg_color
|
||||
font.pixelSize: MyTheme.fontSizeExtraSmall
|
||||
}
|
||||
MouseArea {
|
||||
|
|
|
|||
|
|
@ -92,9 +92,9 @@ ListModel {
|
|||
for (var l = 0; l < labelcount; l++) {
|
||||
labels[l] = {
|
||||
'id': parseInt(feeditems[feeditem].labels[l][0]),
|
||||
'fgcolor': (feeditems[feeditem].labels[l][2] == "" ? "black" : feeditems[feeditem].labels[l][2]),
|
||||
'bgcolor': (feeditems[feeditem].labels[l][3] == "" ? "white" : feeditems[feeditem].labels[l][3]),
|
||||
'text': feeditems[feeditem].labels[l][1]
|
||||
'caption': feeditems[feeditem].labels[l][1],
|
||||
'fg_color': (feeditems[feeditem].labels[l][2] === "" ? "black" : feeditems[feeditem].labels[l][2]),
|
||||
'bg_color': (feeditems[feeditem].labels[l][3] === "" ? "white" : feeditems[feeditem].labels[l][3])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -246,6 +246,80 @@ ListModel {
|
|||
})
|
||||
}
|
||||
|
||||
function getLabels(callback) {
|
||||
var ttrss = rootWindow.getTTRSS()
|
||||
var item = getSelectedItem()
|
||||
|
||||
ttrss.getLabels(item.id, function(successful, errorMessage, labels) {
|
||||
if (!successful) {
|
||||
callback(false, errorMessage)
|
||||
return
|
||||
}
|
||||
if (!labels || labels.length === 0) {
|
||||
callback(true, "", [])
|
||||
return
|
||||
}
|
||||
|
||||
var i
|
||||
var j
|
||||
|
||||
// This is in O(nm) where n is the number of labels defined and
|
||||
// m the number of labels checked. It's unefficient, but it should
|
||||
// be fast enough for us.
|
||||
for (i = 0; i < labels.length; ++i) {
|
||||
labels[i].checked = false
|
||||
|
||||
for (j = 0; j < item.labels.count; ++j) {
|
||||
if(labels[i].id === item.labels.get(j).id) {
|
||||
labels[i].checked = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
callback(true, "", labels)
|
||||
})
|
||||
}
|
||||
|
||||
function setLabel(labelId, assign, callback) {
|
||||
var ttrss = rootWindow.getTTRSS()
|
||||
var item = getSelectedItem()
|
||||
|
||||
ttrss.setLabel(item.id, labelId, assign,
|
||||
function(successful, errorMessage) {
|
||||
callback(successful, errorMessage);
|
||||
})
|
||||
}
|
||||
|
||||
function updateLabels(callback) {
|
||||
var ttrss = rootWindow.getTTRSS()
|
||||
var item = getSelectedItem()
|
||||
|
||||
ttrss.updateLabels(item.id, function(successful, errorMessage, labels) {
|
||||
if (!successful) {
|
||||
callback(false, errorMessage)
|
||||
return
|
||||
}
|
||||
|
||||
item.labels.clear()
|
||||
|
||||
for (var i = 0; i < labels.length; ++i) {
|
||||
if (!labels[i].checked) {
|
||||
continue
|
||||
}
|
||||
|
||||
item.labels.append({
|
||||
'id': parseInt(labels[i].id),
|
||||
'caption': labels[i].caption,
|
||||
'fg_color': (labels[i].fg_color === "" ? "black" : labels[i].fg_color),
|
||||
'bg_color': (labels[i].bg_color === "" ? "white" : labels[i].bg_color)
|
||||
})
|
||||
}
|
||||
|
||||
callback(true, "", item.labels)
|
||||
})
|
||||
}
|
||||
|
||||
function catchUp() {
|
||||
var ttrss = rootWindow.getTTRSS()
|
||||
ttrss.catchUp(feed.feedId, feed.isCat, function(successful, errorMessage) {
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ function initState() {
|
|||
'lastfeeditem': { 'feedId': null, 'articleId': null },
|
||||
'lastfeeditemunread':{ 'feedId': null, 'articleId': null },
|
||||
'lastfeeditemrss': { 'feedId': null, 'articleId': null },
|
||||
'labelscache': null,
|
||||
};
|
||||
|
||||
requestsPending = {
|
||||
|
|
@ -912,6 +913,136 @@ function process_updateFeedUnread(callback, httpreq) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of configured labels.
|
||||
* @param {int} The id of an arbitrary article.
|
||||
* @param {function} A callback function with parameters boolean (indicating
|
||||
* success), string (an optional error message), and array (the labels as
|
||||
* objects).
|
||||
*/
|
||||
function getLabels(articleId, callback) {
|
||||
if (state['labelscache']) {
|
||||
callback(true, "", state['labelscache'])
|
||||
return
|
||||
}
|
||||
|
||||
updateLabels(articleId, callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of configured labels with a flag if a label is assigned to a
|
||||
* specific article.
|
||||
* @param {int} The id of the article.
|
||||
* @param {function} A callback function with parameters boolean (indicating
|
||||
* success), string (an optional error message), and array (the labels as
|
||||
* objects).
|
||||
*/
|
||||
function updateLabels(articleId, callback) {
|
||||
if(responsesPending['getlabel'])
|
||||
return;
|
||||
|
||||
if(!state['token']) {
|
||||
requestsPending['getlabel'] = true;
|
||||
processPendingRequests(callback)
|
||||
return;
|
||||
}
|
||||
|
||||
if (state['apilevel'] < 1) {
|
||||
callback(false, "Retrieving labels isn't supported by API");
|
||||
return;
|
||||
}
|
||||
|
||||
responsesPending['getlabel'] = true
|
||||
|
||||
var params = {
|
||||
'op': 'getLabels',
|
||||
'sid': state['token'],
|
||||
'article_id': articleId
|
||||
}
|
||||
|
||||
networkCall(params, function(http) { process_updateLabels(callback, http) });
|
||||
}
|
||||
|
||||
/** @private */
|
||||
function process_updateLabels(callback, httpreq) {
|
||||
var response = process_readyState(httpreq);
|
||||
|
||||
responsesPending['getlabel'] = false;
|
||||
|
||||
if (!response.successful) {
|
||||
trace(1, "Get labels: " + response.errorMessage);
|
||||
if (callback) {
|
||||
callback(false, response.errorMessage);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
state['labelscache'] = response.content
|
||||
|
||||
if(!processPendingRequests(callback) && callback) {
|
||||
// This action is complete (as there's no other requests to do)
|
||||
// Fire callback saying all ok
|
||||
callback(true, "", response.content);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign an article to a label or remove article from it.
|
||||
* @param {int} The id of the article.
|
||||
* @param {int} The id of the label.
|
||||
* @param {boolean} Assign to or remove from label.
|
||||
* @param {function} A callback function with parameters boolean (indicating
|
||||
* success) and string (an optional error message).
|
||||
*/
|
||||
function setLabel(articleId, labelId, assign, callback) {
|
||||
if(responsesPending['setlabel'])
|
||||
return;
|
||||
|
||||
if(!state['token']) {
|
||||
requestsPending['setlabel'] = true;
|
||||
processPendingRequests(callback)
|
||||
return;
|
||||
}
|
||||
|
||||
if (state['apilevel'] < 1) {
|
||||
callback(false, "Assigning labels isn't supported by API");
|
||||
return;
|
||||
}
|
||||
|
||||
responsesPending['setlabel'] = true
|
||||
|
||||
var params = {
|
||||
'op': 'setArticleLabel',
|
||||
'sid': state['token'],
|
||||
'article_ids': articleId,
|
||||
'label_id': labelId,
|
||||
'assign': assign
|
||||
}
|
||||
|
||||
networkCall(params, function(http) { process_setLabel(callback, http) });
|
||||
}
|
||||
|
||||
/** @private */
|
||||
function process_setLabel(callback, httpreq) {
|
||||
var response = process_readyState(httpreq);
|
||||
|
||||
responsesPending['setlabel'] = false;
|
||||
|
||||
if (!response.successful) {
|
||||
trace(1, "Set label: " + response.errorMessage);
|
||||
if (callback) {
|
||||
callback(false, response.errorMessage);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(!processPendingRequests(callback) && callback) {
|
||||
// This action is complete (as there's no other requests to do)
|
||||
// Fire callback saying all ok
|
||||
callback(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {boolean} Whether some pending stuff was found.
|
||||
|
|
|
|||
|
|
@ -61,6 +61,27 @@ Page {
|
|||
enabled: !panel.moving
|
||||
onClicked: panel.open ? panel.hide() : panel.show()
|
||||
}
|
||||
MenuItem {
|
||||
text: qsTr("Assign Labels")
|
||||
|
||||
enabled: !network.loading
|
||||
onClicked: {
|
||||
feedItemModel.getLabels(function(successful, errorMessage,
|
||||
labels) {
|
||||
if (successful) {
|
||||
var params = {
|
||||
labels: labels,
|
||||
headline: root.pageTitle,
|
||||
feedItemPage: root
|
||||
}
|
||||
pageStack.push(Qt.resolvedUrl("LabelUpdater.qml"),
|
||||
params);
|
||||
}
|
||||
|
||||
// TODO make use of errorMessage
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
|
|
@ -148,6 +169,8 @@ Page {
|
|||
Grid {
|
||||
spacing: Theme.paddingMedium
|
||||
width: parent.width
|
||||
visible: labels !== null && labels.count > 0
|
||||
|
||||
Repeater {
|
||||
model: labels.count
|
||||
LabelLabel {
|
||||
|
|
@ -344,6 +367,16 @@ Page {
|
|||
}
|
||||
}
|
||||
|
||||
function updateLabels() {
|
||||
feedItemModel.updateLabels(function(successful, errorMessage, labels) {
|
||||
if (successful) {
|
||||
root.labels = labels
|
||||
}
|
||||
|
||||
// TODO make use of errorMessage
|
||||
})
|
||||
}
|
||||
|
||||
Binding {
|
||||
target: itemView
|
||||
property: "fontSize"
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ Rectangle {
|
|||
|
||||
width: text.width + 2*Theme.paddingSmall
|
||||
height: text.height
|
||||
color: label !== null ? label.bgcolor : Theme.secondaryColor
|
||||
color: label !== null ? label.bg_color : Theme.secondaryColor
|
||||
radius: Theme.paddingSmall
|
||||
|
||||
Text {
|
||||
|
|
@ -38,8 +38,8 @@ Rectangle {
|
|||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
id: text
|
||||
text: label !== null ? label.text : ""
|
||||
color: label !== null ? label.fgcolor : Theme.highlightColor
|
||||
text: label !== null ? label.caption : ""
|
||||
color: label !== null ? label.fg_color : Theme.highlightColor
|
||||
font.pixelSize: Theme.fontSizeExtraSmall
|
||||
}
|
||||
}
|
||||
|
|
|
|||
136
qml/ttrss/sailfish/pages/LabelUpdater.qml
Normal file
136
qml/ttrss/sailfish/pages/LabelUpdater.qml
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* This file is part of TTRss, a Tiny Tiny RSS Reader App
|
||||
* for MeeGo Harmattan and Sailfish OS.
|
||||
* Copyright (C) 2012–2014 Hauke Schade
|
||||
*
|
||||
* 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; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or see
|
||||
* http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
|
||||
Page {
|
||||
id: page
|
||||
|
||||
property string headline
|
||||
property var labels
|
||||
property var feedItemPage
|
||||
|
||||
property bool initialization: true
|
||||
property bool labelsChanged: false
|
||||
|
||||
SilicaListView {
|
||||
id: listView
|
||||
anchors.fill: page
|
||||
anchors.leftMargin: Theme.paddingMedium
|
||||
anchors.rightMargin: Theme.paddingMedium
|
||||
model: page.labels
|
||||
|
||||
|
||||
header: Column {
|
||||
width: listView.width
|
||||
height: header.height + info.height
|
||||
PageHeader {
|
||||
id: header
|
||||
width: page.width
|
||||
title: qsTr("Update Labels")
|
||||
}
|
||||
Label {
|
||||
id: info
|
||||
text: page.headline !== null ? page.headline : ""
|
||||
width: parent.width
|
||||
font.weight: Font.Bold
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
visible: page.headline !== null && page.headline !== ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
delegate: ListItem {
|
||||
id: item
|
||||
width: parent.width
|
||||
|
||||
property var label: page.labels[index]
|
||||
|
||||
Switch {
|
||||
id: checkbox
|
||||
checked: item.label.checked
|
||||
enabled: !network.loading
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
property bool noAPIcall: false
|
||||
|
||||
onCheckedChanged: {
|
||||
if (page.initialization) {
|
||||
return
|
||||
}
|
||||
if (checkbox.noAPIcall) {
|
||||
checkbox.noAPIcall = false
|
||||
return
|
||||
}
|
||||
|
||||
page.labelsChanged = true
|
||||
checkbox.busy = true
|
||||
|
||||
feedItemModel.setLabel(item.label.id, checkbox.checked,
|
||||
function(successful, errorMessage) {
|
||||
checkbox.busy = false
|
||||
if (!successful) {
|
||||
checkbox.noAPIcall = true
|
||||
checkbox.checked = !checkbox.checked
|
||||
// TODO display errorMessage
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
LabelLabel {
|
||||
label: item.label
|
||||
anchors {
|
||||
left: checkbox.right
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ViewPlaceholder {
|
||||
enabled: listView.count === 0
|
||||
text: network.loading ?
|
||||
qsTr("Loading") :
|
||||
qsTr("You have no label defined. You can create them in the webview.")
|
||||
}
|
||||
}
|
||||
|
||||
BusyIndicator {
|
||||
visible: network.loading
|
||||
running: visible
|
||||
anchors {
|
||||
horizontalCenter: page.horizontalCenter
|
||||
verticalCenter: page.verticalCenter
|
||||
}
|
||||
size: BusyIndicatorSize.Large
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
page.initialization = false
|
||||
}
|
||||
|
||||
onStatusChanged: {
|
||||
if (page.status === PageStatus.Deactivating && page.labelsChanged) {
|
||||
feedItemPage.updateLabels()
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue