From 867a51523b31788a7c77416275935dfee8f0f39f Mon Sep 17 00:00:00 2001 From: Yves Marcoz Date: Fri, 5 Nov 2010 08:02:27 -0700 Subject: [PATCH] 0.9beta * bug fixes * 1st iteration of QML interface --- Makefile | 9 ++ debian/changelog | 10 +- src/FeedingIt | 7 + src/FeedingIt-Web.py | 155 +++++++++++++++++++++ src/FeedingIt.py | 4 +- src/qml/ArticleDisplay.qml | 60 ++++++++ src/qml/Articles.qml | 73 ++++++++++ src/qml/Categories.qml | 51 +++++++ src/qml/FeedingIt.qml | 240 ++++++++++++++++++++++++++++++++ src/qml/FeedingitUI.qmlproject | 18 +++ src/qml/FeedingitUI.qmlproject.user | 50 +++++++ src/qml/Feeds.qml | 65 +++++++++ src/qml/TestWebview.qml | 66 +++++++++ src/qml/common/Button.qml | 38 +++++ src/qml/common/Config.qml | 6 + src/qml/common/ConfirmationMessage.qml | 50 +++++++ src/qml/common/Menu.qml | 121 ++++++++++++++++ src/qml/common/Slider.qml | 36 +++++ src/qml/common/Switch.qml | 76 ++++++++++ src/qml/common/ToolBar.qml | 86 ++++++++++++ src/qml/common/images/toolbutton.png | Bin 0 -> 2550 bytes src/qml/common/images/toolbutton.sci | 5 + src/qml/i18n/FeedingIt.ts | 12 ++ src/qml/i18n/qml_en.qm | Bin 0 -> 228 bytes src/qml/i18n/qml_en.ts | 29 ++++ src/qml/old-FeedingitUI.qml | 162 +++++++++++++++++++++ src/rss_sqlite.py | 12 +- 27 files changed, 1434 insertions(+), 7 deletions(-) create mode 100644 src/FeedingIt-Web.py create mode 100644 src/qml/ArticleDisplay.qml create mode 100644 src/qml/Articles.qml create mode 100644 src/qml/Categories.qml create mode 100644 src/qml/FeedingIt.qml create mode 100644 src/qml/FeedingitUI.qmlproject create mode 100644 src/qml/FeedingitUI.qmlproject.user create mode 100644 src/qml/Feeds.qml create mode 100644 src/qml/TestWebview.qml create mode 100644 src/qml/common/Button.qml create mode 100644 src/qml/common/Config.qml create mode 100644 src/qml/common/ConfirmationMessage.qml create mode 100644 src/qml/common/Menu.qml create mode 100644 src/qml/common/Slider.qml create mode 100644 src/qml/common/Switch.qml create mode 100644 src/qml/common/ToolBar.qml create mode 100644 src/qml/common/images/toolbutton.png create mode 100644 src/qml/common/images/toolbutton.sci create mode 100644 src/qml/debug.log create mode 100644 src/qml/i18n/FeedingIt.ts create mode 100644 src/qml/i18n/qml_en.qm create mode 100644 src/qml/i18n/qml_en.ts create mode 100644 src/qml/old-FeedingitUI.qml diff --git a/Makefile b/Makefile index 1302b7d..51337b9 100644 --- a/Makefile +++ b/Makefile @@ -8,12 +8,21 @@ install: install -d ${DESTDIR}/usr/bin install src/FeedingIt ${DESTDIR}/usr/bin install -d ${DESTDIR}/opt/FeedingIt + install -d ${DESTDIR}/opt/FeedingIt/qml/i18n + install -d ${DESTDIR}/opt/FeedingIt/qml/common + install -d ${DESTDIR}/opt/FeedingIt/qml/common/images + install -d ${DESTDIR}/opt/FeedingIt/qml + install src/qml/*.qml ${DESTDIR}/opt/FeedingIt/qml + install src/qml/i18n/*.qm ${DESTDIR}/opt/FeedingIt/qml/i18n + install src/qml/common/*.qml ${DESTDIR}/opt/FeedingIt/qml/common + install src/qml/common/images/*.{sci,png} ${DESTDIR}/opt/FeedingIt/qml/common/images install src/FeedingIt.py ${DESTDIR}/opt/FeedingIt install src/feedparser.py ${DESTDIR}/opt/FeedingIt install src/portrait.py ${DESTDIR}/opt/FeedingIt install src/rss.py ${DESTDIR}/opt/FeedingIt install src/opml.py ${DESTDIR}/opt/FeedingIt install src/config.py ${DESTDIR}/opt/FeedingIt + install src/FeedingIt-Web.py ${DESTDIR}/opt/FeedingIt #install src/feedingit_status.desktop ${DESTDIR}/opt/FeedingIt install src/update_feeds.py ${DESTDIR}/opt/FeedingIt install src/updatedbus.py ${DESTDIR}/opt/FeedingIt diff --git a/debian/changelog b/debian/changelog index 64d9319..6516e49 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,14 @@ +feedingit (0.9.0-0) unstable; urgency=low + + * Added QML interface + * Fixed the use of id as article identifier (#6473) + * Added categories + + -- Yves Sun, 31 Oct 2010 28:03:19 -0800 + feedingit (0.8.0-9) unstable; urgency=low - * Fixed date for articles without a date field + * Fixed date in feed shows as 1/1/1970 if no date field in rss feed is present (#6398) -- Yves Fri, 12 Sep 2010 10:54:19 -0800 diff --git a/src/FeedingIt b/src/FeedingIt index b6762e3..ebd4991 100644 --- a/src/FeedingIt +++ b/src/FeedingIt @@ -11,6 +11,13 @@ dbus) #cp feedingit_status.desktop /usr/share/applications/hildon-status-menu/ nice python2.5 update_feeds.py ;; +qml) + cd /opt/FeedingIt + python2.5 FeedingIt-Web.py 2>&1 >/dev/null & + pid=`pidof python2.5 FeedingIt-Web.py` + qmlviewer -fullscreen qml/FeedingIt.qml + kill $pid + ;; *) cd /opt/FeedingIt python2.5 FeedingIt.py diff --git a/src/FeedingIt-Web.py b/src/FeedingIt-Web.py new file mode 100644 index 0000000..9c79ad2 --- /dev/null +++ b/src/FeedingIt-Web.py @@ -0,0 +1,155 @@ +import BaseHTTPServer +import sys +from rss_sqlite import Listing +from xml import sax +from cgi import escape +from re import sub +from htmlentitydefs import name2codepoint + +CONFIGDIR = "/home/user/.feedingit/" + +def unescape(text): + def fixup(m): + text = m.group(0) + if text[:2] == "&#": + # character reference + try: + if text[:3] == "&#x": + return unichr(int(text[3:-1], 16)) + else: + return unichr(int(text[2:-1])) + except ValueError: + pass + else: + # named entity + try: + text = unichr(name2codepoint[text[1:-1]]) + except KeyError: + pass + return text # leave as is + return sub("&#?\w+;", fixup, text) + +class Handler(BaseHTTPServer.BaseHTTPRequestHandler): + + def openTaskSwitch(self): + import subprocess + subprocess.Popen("dbus-send /com/nokia/hildon_desktop com.nokia.hildon_desktop.exit_app_view", shell=True) + + def getConfigXml(self): + xml = "" + xml += "True" + xml += "True" + xml += "" + return xml + + def generateCategoryXml(self): + xml = "" + for cat in listing.getListOfCategories(): + xml += "" + xml += "%s" %listing.getCategoryTitle(cat) + xml += "%s" % cat + xml += "" + xml += "" + return xml + + def fix_title(self, title): + return escape(unescape(title).replace("","").replace("","").replace("","").replace("","").replace("","").replace("—","-")) + + def generateFeedsXml(self, catid): + xml = "" + for key in listing.getSortedListOfKeys("Manual", category=catid): + xml += "" + xml += "%s" %listing.getFeedTitle(key) + xml += "%s" %key + xml += "%s" %listing.getFeedNumberOfUnreadItems(key) + xml += "%s" %listing.getFeedUpdateTime(key) + xml += "%s" %listing.getFavicon(key) + xml += "" + xml += "" + return xml + + def generateArticlesXml(self, key, onlyUnread, markAllAsRead): + feed = listing.getFeed(key) + if markAllAsRead=="True": + feed.markAllAsRead() + listing.updateUnread(key) + xml = "" + if onlyUnread == "False": + onlyUnread = False + for id in feed.getIds(onlyUnread): + xml += "
" + xml += "%s" %self.fix_title(feed.getTitle(id)) + xml += "%s" %id + xml += "%s" %str(feed.isEntryRead(id)) + xml += "%s" %feed.getDateStamp(id) + xml += "%s" %feed.getContentLink(id) + xml += "
" + xml += "
" + return xml + + def do_GET(self): + (req, sep, arg) = self.path.partition("?") + request = req.split("/") + arguments = {} + if arg != "": + args = arg.split("&") + print args + for arg in args: + ele = arg.split("=") + print ele + #try: + arguments[ele[0]] = ele[1] + #except: + # pass + if request[1] == "categories": + xml = self.generateCategoryXml() + elif request[1] == "feeds": + catid = request[2] + xml = self.generateFeedsXml(catid) + elif request[1] == "articles": + key = request[2] + onlyUnread = arguments.get("onlyUnread","False") + markAllAsRead = arguments.get("markAllAsRead", "False") + xml = self.generateArticlesXml(key, onlyUnread, markAllAsRead) + elif request[1] == "html": + key = request[2] + article = request[3] + feed = listing.getFeed(key) + file = open(feed.getContentLink(article)) + feed.setEntryRead(article) + html = file.read().replace("body", "body bgcolor='#ffffff'", 1) + file.close() + self.send_response(200) + self.send_header("Content-type", "text/html") + self.end_headers() + self.wfile.write(html) + listing.updateUnread(key) + return + elif request[1] == "config": + xml = self.getConfigXml() + elif request[1] == "home": + file = open(self.path) + self.send_response(200) + self.send_header("Content-type", "text/html") + self.end_headers() + self.wfile.write(file.read()) + file.close() + return + elif request[1] == "task": + self.openTaskSwitch() + xml = "OK" + else: + self.send_error(404, "File not found") + return + self.send_response(200) + self.send_header("Content-type", "text/xml") + self.end_headers() + self.wfile.write(xml.encode("utf-8")) + +PORT = 8000 + +listing = Listing(CONFIGDIR) + +httpd = BaseHTTPServer.HTTPServer(("127.0.0.1", PORT), Handler) +print "serving at port", PORT +httpd.serve_forever() diff --git a/src/FeedingIt.py b/src/FeedingIt.py index e57689d..9ba9469 100644 --- a/src/FeedingIt.py +++ b/src/FeedingIt.py @@ -1130,9 +1130,9 @@ class FeedingIt: wizard = AddWidgetWizard(self.window, self.listing, urlIn, self.listing.getListOfCategories()) ret = wizard.run() if ret == 2: - (title, url) = wizard.getData() + (title, url, category) = wizard.getData() if (not title == '') and (not url == ''): - self.listing.addFeed(title, url) + self.listing.addFeed(title, url, category=category) wizard.destroy() self.displayListing() diff --git a/src/qml/ArticleDisplay.qml b/src/qml/ArticleDisplay.qml new file mode 100644 index 0000000..963f150 --- /dev/null +++ b/src/qml/ArticleDisplay.qml @@ -0,0 +1,60 @@ +import Qt 4.7 +import QtWebKit 1.0 +import "common" as Common + +Rectangle { + x: parent.width; /*height: parent.height;*/ + width: parent.width; + height: parent.height + property alias zoomEnabled: slider.visible; + property alias value: slider.value; + //anchors.top: parent.top; anchors.bottom: parent.bottom; + color: "white"; + + Flickable { + id: flickable + //anchors.fill: screen; + height: parent.height; + width: parent.width; + contentWidth: webView.width*webView.scale; //Math.max(screen.width,webView.width*webView.scale) + contentHeight: Math.max(screen.height,webView.height*webView.scale) + //contentWidth: childrenRect.width; contentHeight: childrenRect.height + + flickDeceleration: 1000; + + WebView { + id: webView + url: articleDisplay.url; + preferredWidth: flickable.width + preferredHeight: flickable.height + //scale: 1.25; + transformOrigin: Item.TopLeft + scale: slider.value; + settings.defaultFontSize: 24 + } + } + + Common.Slider { + id: slider; visible: false + minimum: 0.2; + maximum: 2; + property real prevScale: 1 + anchors { + bottom: parent.bottom; bottomMargin: 65 + left: parent.left; leftMargin: 25 + right: parent.right; rightMargin: 25 + } + onValueChanged: { + if (webView.width * value > flickable.width) { + var xoff = (flickable.width/2 + flickable.contentX) * value / prevScale; + flickable.contentX = xoff - flickable.width/2; + } + if (webView.height * value > flickable.height) { + var yoff = (flickable.height/2 + flickable.contentY) * value / prevScale; + flickable.contentY = yoff - flickable.height/2; + } + prevScale = value; + } + Component.onCompleted: {value=0; value=1; } + } +} diff --git a/src/qml/Articles.qml b/src/qml/Articles.qml new file mode 100644 index 0000000..9c2650d --- /dev/null +++ b/src/qml/Articles.qml @@ -0,0 +1,73 @@ +import Qt 4.7 + +Item { + //anchors.fill: parent; + width: parent.width; + property string feedid : "" + property alias count: articles.count + property alias url: articles.source + x: parent.width; height: parent.height; + anchors.top: parent.top; anchors.bottom: parent.bottom + + function getArticleid(index) { + return articles.get(index).articleid + } + + function reload() { + articles.reload() + } + + ListView { + id: articleList; model: articles; delegate: articleDelegate; z: 6 + width: parent.width; height: parent.height; /*x: 0;*/ + cacheBuffer: 100; + flickDeceleration: 1500 + } + + XmlListModel { + id: articles + + source: feedid == "" ? "" : "http://localhost:8000/articles/" + feedid + "?onlyUnread=" + hideReadArticles + query: "/xml/article" + + XmlRole { name: "title"; query: "title/string()" } + XmlRole { name: "articleid"; query: "articleid/string()"; isKey: true } + XmlRole { name: "path"; query: "path/string()" } + XmlRole { name: "unread"; query: "unread/string()"; isKey: true} + } + + Component { + id: articleDelegate + + Item { + id: wrapper; width: wrapper.ListView.view.width; height: 86 + Item { + id: moveMe + Rectangle { id: backRect; color: "black"; opacity: index % 2 ? 0.2 : 0.4; height: 84; width: wrapper.width; y: 1 } + Text { + anchors.fill: backRect + anchors.margins: 5 + verticalAlignment: Text.AlignVCenter; text: title; color: (unread=="True") ? "white" : "#7b97fd"; + width: wrapper.width; wrapMode: Text.WordWrap; font.bold: false; + } +// Rectangle { +// x: 3; y: 4; width: 77; height: 77; color: "#ff0000"; smooth: true + +// } + +// Column { +// x: 3; + +// width: wrapper.width - 3; y: 5; spacing: 2 +// height: parent.height; +// Text { Rectangle {anchors.fill: parent; color: "white"; opacity: 0.5;} +// verticalAlignment: Text.AlignVCenter; text: title; color: (unread=="True") ? "white" : "#7b97fd"; width: parent.width; wrapMode: Text.WordWrap; font.bold: false; /*elide: Text.ElideRight;*/ /*style: Text.Raised;*/ styleColor: "black"; } +// //Text { text: feedname; width: parent.width; elide: Text.ElideLeft; color: "#cccccc"; style: Text.Raised; styleColor: "black" } +// } + } + MouseArea { anchors.fill: wrapper; onClicked: { container.articleClicked(articleid, index) } } + } + + } + +} diff --git a/src/qml/Categories.qml b/src/qml/Categories.qml new file mode 100644 index 0000000..bce5f7b --- /dev/null +++ b/src/qml/Categories.qml @@ -0,0 +1,51 @@ +import Qt 4.7 + +Item { +// anchors.fill: parent; + width: parent.width; height: parent.height; + //anchors.top: parent.top; anchors.bottom: parent.bottom + + ListView { + id: categoryList; model: categories; delegate: categoryDelegate; z: 6; + cacheBuffer: 100; width: parent.width; height: parent.height; + } + + XmlListModel { + + id: categories + + //source: "http://api.flickr.com/services/feeds/photos_public.gne?"+(tags ? "tags="+tags+"&" : "")+"format=rss2" + //source: "/home/ymarcoz/feedlist.xml" + source: "http://localhost:8000/categories" + query: "/xml/category" + //namespaceDeclarations: "declare namespace media=\"http://search.yahoo.com/mrss/\";" + + XmlRole { name: "title"; query: "catname/string()" } + XmlRole { name: "catid"; query: "catid/string()"; isKey: true } + + } + + Component { + id: categoryDelegate + + Item { + + id: wrapper; width: wrapper.ListView.view.width; height: 86 + Item { + id: moveMe + height: parent.height + Rectangle { color: "black"; opacity: index % 2 ? 0.2 : 0.4; height: 84; width: wrapper.width; y: 1 } + Rectangle { + x: 6; y: 4; width: 77; height: parent.height - 9; color: "white"; smooth: true + + } + Column { + x: 92; width: wrapper.ListView.view.width - 95; y: 15; spacing: 2 + Text { text: title; color: "white"; width: parent.width; font.bold: true; elide: Text.ElideRight; style: Text.Raised; styleColor: "black" } + //Text { text: feedname; width: parent.width; elide: Text.ElideLeft; color: "#cccccc"; style: Text.Raised; styleColor: "black" } + } + } + MouseArea { anchors.fill: wrapper; onClicked: { container.categoryClicked(catid); } } + } + } +} diff --git a/src/qml/FeedingIt.qml b/src/qml/FeedingIt.qml new file mode 100644 index 0000000..bb2156e --- /dev/null +++ b/src/qml/FeedingIt.qml @@ -0,0 +1,240 @@ +import Qt 4.7 +import "common" as Common +// Depends on qt4-declarative-qmlviewer + +Item { + width: 640 + height: 480 + id: screen + + Rectangle { + id: container + anchors.fill: parent; color: "#343434"; + + function modulo(x,y) { + // Fixes modulo for negative numbers + return ((x%y)+y)%y; + } + + function categoryClicked(catid) { + feedsItem.catid = catid; + categoriesItem.isShown = false; + feedsItem.visible = true; + } + + function feedClicked(feedid) { + articlesItem.feedid = feedid; + articlesItem.visible = true; + } + + function articleClicked(articleid, index) { + // Assign the articleId for the current, next and previous article to the associated variables + // Note the modulo, so it goes around + articleDisplay.articleindex = modulo(index,articlesItem.count) + articleDisplay.nextArticle = articlesItem.getArticleid(modulo(index+1,articlesItem.count)) + articleDisplay.prevArticle = articlesItem.getArticleid(modulo(index-1,articlesItem.count)) + articleDisplay.articleid = articleid + articleDisplay.visible = true; + } + + function backClicked() { + if (articleDisplay.visible) { + // We're viewing an article, and going back to article listing + articleDisplay.visible = false; + articleDisplay.articleid = ""; + articleDisplay.value = 1; + articlesItem.reload() + return; + } + if (articlesItem.visible) { + // Viewing articles, going back to feeds + //articlesItem.feedid = ""; + feedsItem.reload(); + articlesItem.visible = false; + //articlesItem.reload(); + return; + } + if (feedsItem.visible) { + // Viewing feeds, going back to categories + //feedsItem.catid = ""; + feedsItem.visible = false; + //feedsItem.reload(); + categoriesItem.isShown = true; + return; + } + if (!feedsItem.visible) { + // Viewing categories, quitting + Qt.quit(); + } + } + + Common.Menu { + id: config + z: 5 + property string hideReadFeeds : "False" + property string hideReadArticles : "False" + + property bool isShown: false; + + //width: parent.width; height: parent.height; + + //height: 0 + states: State { + name: "shown"; when: config.isShown == true + PropertyChanges { target: config; y: 66 } + } + + transitions: Transition { + NumberAnimation { properties: "y"; duration: 300; easing.type: "InOutQuad" } + } + + } + + Common.ConfirmationMessage { + id: confirmationMessage; + visible: false + onOkClicked: { var doc = new XMLHttpRequest(); + console.log(articlesItem.url+"&markAllAsRead=True") + var url = articlesItem.url+"&markAllAsRead=True" + console.log(url) + doc.open("GET", url); + doc.send(); + var xmlDoc=doc.responseXML; + articlesItem.reload(); + feedsItem.reload() + visible=false + } + onCancelClicked: visible=false + } + + Common.ToolBar { + id: toolBar; z: 7 + height: 66; anchors.top: parent.top; width: parent.width; opacity: 0.9 + button1Label: qsTr("Config"); button2Label: qsTr("Back") + nextLabel: qsTr("Next"); prevLabel: qsTr("Previous") + markAllLabel: qsTr("Mark All As Read"); zoomLabel: qsTr("Zoom") + taskSwitcherLabel: qsTr("Task Switch") + onButton1Clicked: config.isShown = !config.isShown; + onButton2Clicked: container.backClicked() + onPrevClicked: container.articleClicked(articleDisplay.prevArticle, articleDisplay.articleindex-1) + onNextClicked: container.articleClicked(articleDisplay.nextArticle, articleDisplay.articleindex+1) + onMarkAllClicked: { + confirmationMessage.text = qsTr("Do you want to mark all items as read?"); + confirmationMessage.visible = true; + } + onZoomClicked: { articleDisplay.zoomEnabled = !articleDisplay.zoomEnabled; } + onTaskSwitcherClicked: { + var doc = new XMLHttpRequest(); + var url = "http://localhost:8000/task" + doc.open("GET", url); + doc.send(); + //var xmlDoc=doc.responseXML; + } + + states: [ State { + name: "navButtons"; when: articleDisplay.articleid != "" + PropertyChanges { target: toolBar; nextVisible: true; } + PropertyChanges { target: toolBar; prevVisible: true; } + PropertyChanges { target: toolBar; zoomVisible: true; } + }, + State { + name: "feedButtons"; when: (articleDisplay.articleid == "")&&(articlesItem.feedid!="") + PropertyChanges { target: toolBar; markAllVisible: true; } + } + ] + } + + Item { + id: views + //x: 2; + //y:66; + width: parent.width // - 4 + anchors.top: toolBar.bottom; anchors.bottom: parent.bottom + + Categories { + // Loads the categoryList view and delegate + id: categoriesItem + property bool isShown: true; + + states: State { + name: "shown"; when: categoriesItem.isShown == false + PropertyChanges { target: categoriesItem; x: -screen.width } + } + + transitions: Transition { + NumberAnimation { properties: "x"; duration: 300; easing.type: "InOutQuad" } + } + + } + + Feeds { + + // Loads the feedList view and delegate + id: feedsItem; + property string hideReadFeeds: config.hideReadFeeds + visible: false; + + states: [ + State { name: "articlesShown"; when: articlesItem.visible; PropertyChanges { target: feedsItem; x: -parent.width } }, + State { name: "shown"; when: feedsItem.visible; PropertyChanges { target: feedsItem; x: 0 } } + ] + + transitions: Transition { + NumberAnimation { properties: "x"; duration: 300; easing.type: "InOutQuad" } + } + + } + + Articles { + // Loads the articleLost view and delegate + id: articlesItem; + property string hideReadArticles: config.hideReadArticles + visible: false; + + states: [ + State { name: "shown"; when: articleDisplay.visible; PropertyChanges { target: articlesItem; x: -parent.width } + }, + State { name: "articleShown"; when: articlesItem.visible; PropertyChanges { target: articlesItem; x: 0 } + } + ] + + transitions: Transition { + NumberAnimation { properties: "x"; duration: 300; easing.type: "InOutQuad" } + } + } + + ArticleDisplay{ + // Loads the WebView + id: articleDisplay; + //anchors.top: toolBar.bottom; + //anchors.bottom: screen.bottom; + height: parent.height; + visible: false; + property string feedid: articlesItem.feedid; + property string articleid: ""; + property int articleindex: 0; + property string nextArticle: ""; + property string prevArticle: ""; + property string url: (articleid == "") ? "" : "http://localhost:8000/html/" + articleDisplay.feedid + "/" + articleDisplay.articleid; + + gradient: Gradient { + GradientStop { + position: 0.00; + color: "#ffffff"; + } + GradientStop { + position: 1.00; + color: "#ffffff"; + } + } + + states: State { name: "shown"; when: articleDisplay.visible; PropertyChanges { target: articleDisplay; x: 0 } + } + + transitions: Transition { + NumberAnimation { properties: "x"; duration: 300; easing.type: "InOutQuad" } + } + } + } + } +} diff --git a/src/qml/FeedingitUI.qmlproject b/src/qml/FeedingitUI.qmlproject new file mode 100644 index 0000000..53f5ecb --- /dev/null +++ b/src/qml/FeedingitUI.qmlproject @@ -0,0 +1,18 @@ +/* File generated by QtCreator */ + +import QmlProject 1.0 + +Project { + /* Include .qml, .js, and image files from current directory and subdirectories */ + QmlFiles { + directory: "." + } + JavaScriptFiles { + directory: "." + } + ImageFiles { + directory: "." + } + /* List of plugin directories passed to QML runtime */ + // importPaths: [ "../exampleplugin" ] +} diff --git a/src/qml/FeedingitUI.qmlproject.user b/src/qml/FeedingitUI.qmlproject.user new file mode 100644 index 0000000..cc55c6d --- /dev/null +++ b/src/qml/FeedingitUI.qmlproject.user @@ -0,0 +1,50 @@ + + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + Default + + + + ProjectExplorer.Project.Target.0 + + QML Viewer + QML Viewer + QmlProjectManager.QmlTarget + -1 + -1 + 0 + 0 + 0 + + + QML Viewer + QmlProjectManager.QmlRunConfiguration + CurrentFile + + 4 + 3768 + false + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.EnvironmentId + {6449687d-a4d3-4afc-95ac-89e1027ef47e} + + + ProjectExplorer.Project.Updater.FileVersion + 8 + + diff --git a/src/qml/Feeds.qml b/src/qml/Feeds.qml new file mode 100644 index 0000000..8683087 --- /dev/null +++ b/src/qml/Feeds.qml @@ -0,0 +1,65 @@ +import Qt 4.7 + +Item { + //anchors.fill: parent; + width: parent.width; + property string catid : "" + x: parent.width; height: parent.height; + anchors.top: parent.top; anchors.bottom: parent.bottom + + function reload() { + feeds.reload() + } + + //Component.onCompleted: { console.log(x + " /") } + + ListView { + id: feedList; model: feeds; delegate: feedDelegate; z: 6 + width: parent.width; height: parent.height; /*x: 0;*/ + cacheBuffer: 100; + flickDeceleration: 1500 + } + + XmlListModel { + + id: feeds + + source: catid == "" ? "" : "http://localhost:8000/feeds/" + catid //+ "?onlyUnread=" + parent.hideReadArticles + query: "/xml/feed" + + XmlRole { name: "title"; query: "feedname/string()" } + XmlRole { name: "feedid"; query: "feedid/string()"; isKey: true } + XmlRole { name: "unread"; query: "unread/string()"; isKey: true } + XmlRole { name: "updatedDate"; query: "updatedDate/string()" } + XmlRole { name: "icon"; query: "icon/string()" } + } + + Component { + id: feedDelegate + + Item { + id: wrapper; width: wrapper.ListView.view.width; + visible: (unread == "0" && feedsItem.hideReadFeeds=="True") ? false : true + height: (visible) ? 86 : 0 + + Item { + id: moveMe + Rectangle { color: "black"; opacity: index % 2 ? 0.2 : 0.4; height: 84; width: wrapper.width; y: 1 } + Rectangle { + x: 3; y: 4; width: 77; height: 77; color: "#000000"; smooth: true + Image { width:32; height: 32; anchors.verticalCenter: parent.verticalCenter; anchors.horizontalCenter: parent.horizontalCenter; source: (icon == "False") ? "" : icon } + } + + Column { + x: 92; width: wrapper.ListView.view.width - 95; y: 5; spacing: 2 + Text { text: title; color: "white"; width: parent.width; font.bold: true; elide: Text.ElideRight; style: Text.Raised; styleColor: "black" } + Text { text: updatedDate + " / " + qsTr("%1 unread items").arg(unread); color: (unread=="0") ? "white" : "#7b97fd"; width: parent.width; font.bold: false; elide: Text.ElideRight; style: Text.Raised; styleColor: "black" } + //Text { text: feedname; width: parent.width; elide: Text.ElideLeft; color: "#cccccc"; style: Text.Raised; styleColor: "black" } + } + } + MouseArea { anchors.fill: wrapper; onClicked: { container.feedClicked(feedid) } } + } + + } + +} diff --git a/src/qml/TestWebview.qml b/src/qml/TestWebview.qml new file mode 100644 index 0000000..79e05fc --- /dev/null +++ b/src/qml/TestWebview.qml @@ -0,0 +1,66 @@ +import Qt 4.7 +import QtWebKit 1.0 +import "common" as Common + +Rectangle { + width: 380 + height: 480 + + //anchors.top: parent.top; anchors.bottom: parent.bottom; + color: "white"; + + property string url: ""; + Flickable { + id: flickable + //anchors.fill: screen; + height: parent.height; + width: parent.width; + contentWidth: webView.width*scale; //Math.max(screen.width,webView.width*webView.scale) + contentHeight: Math.max(parent.height,webView.height*webView.scale) + + WebView { + id: webView + url: "http://www.google.com"; + //url: "/home/user/.feedingit/640fb167aca8bf5318ed721c5162f5eb.d/56a86b6b1675716ab54db83b1a78ab4c.html" + preferredWidth: flickable.width + preferredHeight: flickable.height + settings.defaultFontSize: 32 + scale: slider.value; + //smooth: false + //width: 200 + //width: parent.width; height: parent.height; +// Rectangle { +// color: "#10000000" +// anchors.fill: parent +// } + //onLoadFinished: {console.log("Hello"); url="javascript:void(document.body.style.background='red');" } + onLoadFinished: {console.log(url);/* url="javascript:(function() { " + + "document.getElementsByTagName('body')[0].style.background = 'red'; " + + "})()"; console.log(url);*/ /*heuristicZoom(0,0,100)*/ } + } + } + Common.Slider { + id: slider; visible: true + minimum: 0.2; + maximum: 2; + value: 1 + property real prevScale: 1 + anchors { + bottom: parent.bottom; bottomMargin: 65 + left: parent.left; leftMargin: 25 + right: parent.right; rightMargin: 25 + } + onValueChanged: { + if (webView.width * value > flickable.width) { + var xoff = (flickable.width/2 + flickable.contentX) * value / prevScale; + flickable.contentX = xoff - flickable.width/2; + } + if (webView.height * value > flickable.height) { + var yoff = (flickable.height/2 + flickable.contentY) * value / prevScale; + flickable.contentY = yoff - flickable.height/2; + } + prevScale = value; + } + Component.onCompleted: { value=0; value=1; } + } +} diff --git a/src/qml/common/Button.qml b/src/qml/common/Button.qml new file mode 100644 index 0000000..74b5aea --- /dev/null +++ b/src/qml/common/Button.qml @@ -0,0 +1,38 @@ +import Qt 4.7 + +Item { + id: container + + signal clicked + + property string text + + BorderImage { + id: buttonImage + source: "images/toolbutton.sci" + width: container.width; height: container.height + } + BorderImage { + id: pressed + opacity: 0 + source: "images/toolbutton.sci" + width: container.width; height: container.height + } + MouseArea { + id: mouseRegion + anchors.fill: buttonImage + onClicked: { container.clicked(); } + } + Text { + color: "white" + anchors.centerIn: buttonImage; font.bold: true + text: container.text; style: Text.Raised; styleColor: "black" + } + states: [ + State { + name: "Pressed" + when: mouseRegion.pressed == true + PropertyChanges { target: pressed; opacity: 1 } + } + ] +} diff --git a/src/qml/common/Config.qml b/src/qml/common/Config.qml new file mode 100644 index 0000000..a99ada0 --- /dev/null +++ b/src/qml/common/Config.qml @@ -0,0 +1,6 @@ +import Qt 4.7 + +Rectangle { + width: 640 + height: 480 +} diff --git a/src/qml/common/ConfirmationMessage.qml b/src/qml/common/ConfirmationMessage.qml new file mode 100644 index 0000000..1a5f1f8 --- /dev/null +++ b/src/qml/common/ConfirmationMessage.qml @@ -0,0 +1,50 @@ +import Qt 4.7 + +Rectangle { + id: confirmationMessage + signal okClicked + signal cancelClicked + + property alias text: question.text + + border.color: "black"; + border.width : 4; + radius: 10; + color: "white" + height: 160; + width: 160; + z: 10; + anchors.fill: parent + + Text { + id: question + text: qsTr("Are you sure?") + width: parent.width; height: 80 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + anchors.top: parent.top + //anchors.bottom: parent.bottom + anchors.margins: 10; + //anchors.verticalCenter: parent.verticalCenter + } + + Button { + id: ok + text: qsTr("OK") + anchors.left: parent.left; anchors.margins: 5; y: 3; width: 80; height: 60 + anchors.top: question.bottom + //anchors.bottom: parent.bottom + onClicked: confirmationMessage.okClicked() + } + + Button { + id: cancel + text: qsTr("Cancel") + anchors.right: parent.right; anchors.margins: 5; y: 3; width: 80; height: 60 + anchors.top: question.bottom + //anchors.bottom: parent.bottom + anchors.left: ok.right + onClicked: confirmationMessage.cancelClicked() + } + +} diff --git a/src/qml/common/Menu.qml b/src/qml/common/Menu.qml new file mode 100644 index 0000000..ec31242 --- /dev/null +++ b/src/qml/common/Menu.qml @@ -0,0 +1,121 @@ +import Qt 4.7 + +Item { +// anchors.fill: parent; + width: 300; //height: 0; + //anchors.top: parent.top; anchors.bottom: parent.bottom + y: -parent.height + + function getConfig() { + //console.log("XX\n") + var doc = new XMLHttpRequest(); + doc.onreadystatechange = function() { + if (doc.readyState == XMLHttpRequest.DONE) { + var a = doc.responseXML.documentElement; + //for (var ii = 0; ii < a.childNodes.length; ++ii) { + // console.log(ii+ " " + a.childNodes[ii].firstChild.nodeValue); + //} + + //console.log("node: " + a.childNodes[0].nodeValue) + config.hideReadFeeds = a.childNodes[0].firstChild.nodeValue; + config.hideReadArticles = a.childNodes[1].firstChild.nodeValue; + //console.log("feed " + hideReadFeeds + "\n") + //console.log("Articles " + hideReadArticles + "\n") +// showRequestInfo("Headers -->"); +// showRequestInfo(doc.getAllResponseHeaders ()); +// showRequestInfo("Last modified -->"); +// showRequestInfo(doc.getResponseHeader ("Last-Modified")); + } + } + + doc.open("GET", "http://localhost:8000/config"); + doc.send(); + + } + + Switch { + id: hideReadFeedsSwitch; + text: "Hide Read Feeds"; + value: config.hideReadFeeds + onClicked: config.hideReadFeeds = (config.hideReadFeeds == "False") ? "True" : "False" + } + + Switch { + id: hideReadArticlesSwitch; + text: "Hide Read Articles"; + value: config.hideReadArticles + onClicked: config.hideReadArticles = (config.hideReadArticles == "False") ? "True" : "False" + anchors.top: hideReadFeedsSwitch.bottom + } + + Rectangle { + id: closeButton + height: 50; + gradient: Gradient { + GradientStop { + position: 0.00; + color: "#343434"; + } + GradientStop { + position: 1.00; + color: "#ffffff"; + } + } + radius: 10; + width: parent.width + anchors.top: hideReadArticlesSwitch.bottom + + MouseArea { + id: mouseRegion + anchors.fill: closeButton + onClicked: { config.isShown = false } + } + } + +// ListView { +// id: configList; model: configs; delegate: configDelegate; z: 6; +// cacheBuffer: 100; width: parent.width; height: parent.height; +// } + +// XmlListModel { + +// id: configs + +// //source: "http://api.flickr.com/services/feeds/photos_public.gne?"+(tags ? "tags="+tags+"&" : "")+"format=rss2" +// //source: "/home/ymarcoz/feedlist.xml" +// source: "http://localhost:8000/config" +// query: "/xml/config" +// //namespaceDeclarations: "declare namespace media=\"http://search.yahoo.com/mrss/\";" + +// XmlRole { name: "hideReadFeeds"; query: "hideReadFeeds/string()" } +// XmlRole { name: "hideReadArticles"; query: "hideReadArticles/string()" } +// //XmlRole { name: "catid"; query: "catid/string()"; isKey: true } + +// } + +// Component { +// id: configDelegate + +// Item { + +// id: wrapper; width: wrapper.ListView.view.width; height: 86 +// Item { +// id: moveMe +// height: parent.height +// Rectangle { color: "black"; opacity: index % 2 ? 0.2 : 0.4; height: 84; width: wrapper.width; y: 1 } +// Rectangle { +// x: 6; y: 4; width: 77; height: parent.height - 9; color: "white"; smooth: true + +// } +// Column { +// x: 92; width: wrapper.ListView.view.width - 95; y: 15; spacing: 2 +// Text { text: title; color: "white"; width: parent.width; font.bold: true; elide: Text.ElideRight; style: Text.Raised; styleColor: "black" } +// //Text { text: feedname; width: parent.width; elide: Text.ElideLeft; color: "#cccccc"; style: Text.Raised; styleColor: "black" } +// } +// } +// MouseArea { anchors.fill: wrapper; onClicked: { container.categoryClicked(catid); } } +// } +// } + + Component.onCompleted: getConfig(); +} diff --git a/src/qml/common/Slider.qml b/src/qml/common/Slider.qml new file mode 100644 index 0000000..c210196 --- /dev/null +++ b/src/qml/common/Slider.qml @@ -0,0 +1,36 @@ +import Qt 4.7 + +Item { + id: slider; width: 340; height: 48 + + // value is read/write. + property real value + onValueChanged: { handle.x = 2 + (value - minimum) * slider.xMax / (maximum - minimum); } + property real maximum: 1 + property real minimum: 1 + property int xMax: slider.width - handle.width - 4 + + Rectangle { + anchors.fill: parent + border.color: "white"; border.width: 0; radius: 8 + gradient: Gradient { + GradientStop { position: 0.0; color: "#66343434" } + GradientStop { position: 1.0; color: "#66000000" } + } + } + + Rectangle { + id: handle; smooth: true + x: slider.width / 2 - handle.width / 2; y: 2; width: 30; height: slider.height-4; radius: 6 + gradient: Gradient { + GradientStop { position: 0.0; color: "lightgray" } + GradientStop { position: 1.0; color: "gray" } + } + + MouseArea { + anchors.fill: parent; drag.target: parent + drag.axis: "XAxis"; drag.minimumX: 2; drag.maximumX: slider.xMax+2 + onPositionChanged: { value = (maximum - minimum) * (handle.x-2) / slider.xMax + minimum; } + } + } +} diff --git a/src/qml/common/Switch.qml b/src/qml/common/Switch.qml new file mode 100644 index 0000000..4c10deb --- /dev/null +++ b/src/qml/common/Switch.qml @@ -0,0 +1,76 @@ +import Qt 4.7 + +Item { + id: container + + signal clicked + + property string text + property string value + + width: parent.width; + height: 86; + //anchors.fill: parent; + +// BorderImage { +// id: buttonImage +// source: "images/toolbutton.sci" +// width: container.width; height: container.height +// } +// BorderImage { +// id: pressed +// opacity: 0 +// source: "images/toolbutton.sci" +// width: container.width; height: container.height +// } + + Rectangle { + id: back + width: parent.width; + height: 82; + color: "#343434"; + border.width : 4; + border.color: "black"; + radius: 10; + } + + Rectangle { + id: valueSwitch + color: (value=="False") ? "red" : "green"; + border.width : 4; + border.color: "black"; + radius: 10; + height: 40; + width: 40; + anchors.verticalCenter: back.verticalCenter + //anchors.verticalCenter: parent.verticalCenter + anchors.margins: 10; + anchors.right: back.right; + Text { + color: "white" + anchors.centerIn: valueSwitch; font.bold: true + text: (container.value == "False") ? "OFF" : "ON"; style: Text.Raised; styleColor: "black" + } + } + + MouseArea { + id: mouseRegion + anchors.fill: back + onClicked: { container.clicked(); } + } + Text { + color: "white" + /*anchors.centerIn: back;*/ font.bold: true + anchors.left: parent.left; + anchors.margins: 10 + anchors.verticalCenter: back.verticalCenter + text: container.text; style: Text.Raised; styleColor: "black" + } +// states: [ +// State { +// name: "Pressed" +// when: mouseRegion.pressed == true +// PropertyChanges { target: pressed; opacity: 1 } +// } +// ] +} diff --git a/src/qml/common/ToolBar.qml b/src/qml/common/ToolBar.qml new file mode 100644 index 0000000..d557112 --- /dev/null +++ b/src/qml/common/ToolBar.qml @@ -0,0 +1,86 @@ +import Qt 4.7 + +Item { + id: toolbar + + property alias button1Label: button1.text + property alias button2Label: button2.text + property alias prevLabel: prevButton.text + property alias nextLabel: nextButton.text + property alias markAllLabel: markAllButton.text + property alias zoomLabel: zoomButton.text + property alias taskSwitcherLabel: taskSwitcherButton.text + property alias nextVisible: nextButton.visible + property alias prevVisible: prevButton.visible + property alias markAllVisible: markAllButton.visible + property alias zoomVisible: zoomButton.visible + signal button1Clicked + signal button2Clicked + signal prevClicked + signal nextClicked + signal markAllClicked + signal zoomClicked + signal taskSwitcherClicked + + //BorderImage { source: "images/titlebar.sci"; width: parent.width; height: parent.height + 14; y: -7 } + Rectangle { + anchors.fill: parent; color: "#343434"; + border.color: "black" + gradient: Gradient { + GradientStop { + position: 0.00; + color: "#343434"; + } + GradientStop { + position: 1.00; + color: "#ffffff"; + } + } + + Button { + id: taskSwitcherButton + anchors.left: parent.left; anchors.leftMargin: 5; y: 3; width: 160; height: 60 + onClicked: toolbar.taskSwitcherClicked() + } + + Button { + id: button1 + anchors.left: taskSwitcherButton.right; anchors.leftMargin: 5; y: 3; width: 160; height: 60 + onClicked: toolbar.button1Clicked() + } + + Button { + id: button2 + anchors.right: parent.right; anchors.rightMargin: 5; y: 3; width: 160; height: 60 + onClicked: toolbar.button2Clicked() + } + + Button { + id: markAllButton + visible: false + anchors.left: button1.right; anchors.rightMargin: 5; y: 3; width: 240; height: 60 + onClicked: toolbar.markAllClicked() + } + + Button { + id: prevButton + visible: false + anchors.left: button1.right; anchors.rightMargin: 5; y: 3; width: 120; height: 60 + onClicked: toolbar.prevClicked() + } + + Button { + id: nextButton + visible: false + anchors.right: button2.left; anchors.rightMargin: 5; y: 3; width: 120; height: 60 + onClicked: toolbar.nextClicked() + } + + Button { + id: zoomButton + visible: false + anchors.right: nextButton.left; anchors.rightMargin: 5; y: 3; width: 80; height: 60 + onClicked: toolbar.zoomClicked() + } + } +} diff --git a/src/qml/common/images/toolbutton.png b/src/qml/common/images/toolbutton.png new file mode 100644 index 0000000000000000000000000000000000000000..11310013eedc808ca278e3068d7779e708422726 GIT binary patch literal 2550 zcmVe zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00~}6L_t(&-kn;@Ze&RjJrQ}U z%I)@yx>vMhM)Vd??@(_*@_Yb7zz49M58wmf14gXj57@F~Rl)u9qI_Ld^LrWu%xs>-#eH7mxJ+t3r+Iu8>W-a$yaW&t9&L`W+wBlS zfLl#pt~TpGtyZfqA$po-jn!)P$DjWACx19QJHykbPjPf~R4mp`GJ`_tnt(B$NSb8* zzQ_XH0$@3QS~Nt>JtdI!X60wP2}Fdu54Tva*SNgA#6MqugMWPW6^@UOzjlnD5dfT= zoc#X9ix;2&_Se6`#l;1#uCB2Ehi68#3$>GQ&EiUM!f+9^cl;4}c5EU-m|w1^6+#F& zK0e0jCqKliSFiB*FTTLXA3grv1OS`O=JT_&Gn}8F-8ETgyHgg=*R!L*lAJU z{d}G_7_K?rx!~xVyW<`}gnh^5si>^ZGTuyS(`M1OQK- zJi%tO!GCt&#n|)yL5pugLm^OmbDx@NlF)fEk><<7FboZW0t6@k(*1ymcxVtz(*#lg z>~M2)joaHB{OI{7`1arb`fLJ#^?IFS*aF2~Q>LCE71Q5IL$F-wUE-g~UqYuw-8W91xn+bx`P@ZMvZCNMK50N8G~P*pH9 zL^DqZ&ENt)LYaKi!;NQmGju%+0H$cKFZvjcX1 z3lfFb0OuH6e~;a63r9c*Ap$T>6TJ5j5$txmIfa;AP=S|S+yPBAj$oxZdvWW^Iga8uDf^wmPB@BB2s9<3e0NHtnC{zg|fO9SapsENVl)F#7d{_lx z-pvfaKzx?e2qF=uH4{adCkVLNp4_%?~t) zssKzS1E{~dcBd==y(}PTb9-<6EPnMkiUV1u74Wpq1j3YavSEM~xjDL{X3rBWDBq-> z<#R!#$?=6sL)*oQ4jItoebN65fQA9dSR|Tcb;siL5&)1=rR%hnCY8XlW7Txs2S9yq z0>A>#1BT^|;r6*U%nJZ|3@{&s&I^ZKU`=15OjQd~&kxk8G&4!G%Nngd3jkWw5uHpE zTE8-6K)Mh@i0G<9c`0x*wPo3Hi)5_megz#P>d zGxL=RL<$L!9Z94{MURcu-u1mZwpfV5?^^&0uOC9kjvofVUN1CY7d*fO<_XGa!O?dX zf~O3E191T9VoOx!Qh2aqDbFv(5YJLB(Cq5i_6u~3_ zwbCyDnC{Q~z#ImH9Be7Nq`|V2l%*Shs$cX-%JG%P28av*JeS*c9o7gn09Yqz84w3| zb2gJQ?adRETCugS_ytATwLZdBc$unVohIe{UT2{?1jH|FOJI8M;l1ytLGS$x0D06;<&KZf=^ zKY%!<#cH>~WXj~R2rdiYS@o08_Vcb{k)!l zS%IomIEvfYl$2q$^oEvSqYJt8Ub;xAvQZ7f=$f^{T^~S1nApJ)gE(4Rs=Ri5z0j3J zn$D49XHcjugx68ww7}X05jM&teE*hOT_2dK$1M0UOh0GN9i%v`kmmx6Dg0nD7!gpI3_$P_2Y zXj^4Hpb~@jABRyBv#xkv7@Q)ZX^GWhn9R`BTRahgC%42QakQgUs;|?9;zFSmM@zL% zV}$49@j^}607?MEnUtDLmgEhg>NvdsL1X{l?miLb6QL>F?fCeFO zsI4~A0h=mq2wEVgUjNPZ_SA?HcRhSr0ghPFZG_VDS?VlMl^)zw?WNM5^V=(e&bbVP zRz3Tk4%(EbBtv=*8={Q8u2YKVQik-7Z#x$-NEQ+htR;Wx&Yp9`fu<B652VFZWs1RLPz+Io`c{_x1PR z|MypJ{*KUJFE1~D@&5Yy`QyirvDs{LOy>%5{%%hECFmYHFNM)una#u=iB$nYl{xCd z>`+x%o@f%LY03<`ySu}iH*fIv?OUwZ>tEj9e)yIE;PmwL*>=1AaDTV`n{)0{=Nx!) z-Lt<3#d3W%kV<5&zUl_us};i&=sgCA%~?Pyr_&~;w%^s&Ri4EE09*nYhh&1)L;wH) M07*qoM6N<$g3{N*E&u=k literal 0 HcmV?d00001 diff --git a/src/qml/common/images/toolbutton.sci b/src/qml/common/images/toolbutton.sci new file mode 100644 index 0000000..9e4f965 --- /dev/null +++ b/src/qml/common/images/toolbutton.sci @@ -0,0 +1,5 @@ +border.left: 15 +border.top: 4 +border.bottom: 4 +border.right: 15 +source: toolbutton.png diff --git a/src/qml/debug.log b/src/qml/debug.log new file mode 100644 index 0000000..e69de29 diff --git a/src/qml/i18n/FeedingIt.ts b/src/qml/i18n/FeedingIt.ts new file mode 100644 index 0000000..0351c1a --- /dev/null +++ b/src/qml/i18n/FeedingIt.ts @@ -0,0 +1,12 @@ + + + + + FeedingItUI2 + + + Back + Back 2 + + + diff --git a/src/qml/i18n/qml_en.qm b/src/qml/i18n/qml_en.qm new file mode 100644 index 0000000000000000000000000000000000000000..a284e5c4bd89581a9db5f0d81e39de0ef508310e GIT binary patch literal 228 zcmcE7ks@*G{hX<16=n7(EZlq7iGhJZf`O%dHjrju+{(!eq*7Rx`Fsb`hM7QOHAsYq z!HFS}A(7*rVyf##P2wG}a>0_{ry@-i7pfb3j`Vz?pvs)h=sc}1y-DGHe- Usky}<(^x?cC}!*cGMN||0iSCujQ{`u literal 0 HcmV?d00001 diff --git a/src/qml/i18n/qml_en.ts b/src/qml/i18n/qml_en.ts new file mode 100644 index 0000000..5d6e957 --- /dev/null +++ b/src/qml/i18n/qml_en.ts @@ -0,0 +1,29 @@ + + + + + FeedingItUI2 + + + Back + Back 2 + + + + Config + Config + + + + Feeds + + unreadItems + %1 unread items + + + + %1 unread items + %1 unread items + + + diff --git a/src/qml/old-FeedingitUI.qml b/src/qml/old-FeedingitUI.qml new file mode 100644 index 0000000..c978a50 --- /dev/null +++ b/src/qml/old-FeedingitUI.qml @@ -0,0 +1,162 @@ +import Qt 4.7 + +Item { + id: screen; width: 800; height: 480; +// property bool inListView : false; + Rectangle { + id: background + anchors.fill: parent; color: "#343434"; + + Text { + text: "Hello World" + anchors.centerIn: parent + MouseArea { + id: mouseRegion + anchors.fill: parent + onClicked: { screen.inListView = true; } + } + } + } +// states: State { +// name: "ListView"; when: screen.inListView == true +// PropertyChanges { target: feedList; x: 0 } +// //PropertyChanges { target: photoGridView; x: -(parent.width * 1.5) } +// } + + transitions: Transition { + NumberAnimation { properties: "x"; duration: 500; easing.type: "InOutQuad" } + } + + ListView { + id: categoryList; model: categories; delegate: categoryDelegate; z: 6 + property string shownCategory : "" + /*height: parent.height;*/ x: 0 /*-(parent.width * 1.5)*/; cacheBuffer: 100; width: parent.width; +// states: State { +// name: "showOneCategory"; when: categoryList.shownCategory != "" +// PropertyChanges { target: categories; query: "/xml/category[catid=[\"" + categoryList.shownCategory + "\"]" } +// } + } + + ListView { + id: feedList; model: feeds; delegate: feedDelegate; z: 6 + width: parent.width; height: parent.height; x: parent.width; + cacheBuffer: 100; +// opacity: 0; + //anchors.top: categoryList.bottom + } + + XmlListModel { + + id: categories + + //source: "http://api.flickr.com/services/feeds/photos_public.gne?"+(tags ? "tags="+tags+"&" : "")+"format=rss2" + source: "/home/ymarcoz/feedlist.xml" + query: "/xml/category" + //namespaceDeclarations: "declare namespace media=\"http://search.yahoo.com/mrss/\";" + + XmlRole { name: "title"; query: "catname/string()" } + XmlRole { name: "catid"; query: "catid/string()"; isKey: true } + + } + + XmlListModel { + property string catid : "" + id: feeds + + //source: "http://api.flickr.com/services/feeds/photos_public.gne?"+(tags ? "tags="+tags+"&" : "")+"format=rss2" + source: "/home/ymarcoz/feedlist.xml" + query: "/xml/category/feed" + //namespaceDeclarations: "declare namespace media=\"http://search.yahoo.com/mrss/\";" + + XmlRole { name: "title"; query: "feedname/string()" } + XmlRole { name: "feedid"; query: "feedid/string()" } + } + + Component { + id: categoryDelegate + + Item { + + function categoryClicked() { +// if (categoryList.shownCategory == catid) +// { + categoryList.shownCategory = "" +// categories.query="/xml/category" +// feedList.opacity = 0; +// } else { +// categoryList.shownCategory = catid; +// categories.query="/xml/category[catid=\"" + catid + "\"]"; + feeds.query = "/xml/category[catid=\"" + catid +"\"]/feed" + feedList.x = 0 + //feeds.reload() +// feedList.opacity = 100 +// } + + //feedList.model = feeds; + } + id: wrapper; width: wrapper.ListView.view.width; height: 86 + Item { + id: moveMe + height: parent.height + Rectangle { color: "black"; opacity: index % 2 ? 0.2 : 0.4; height: 84; width: wrapper.width; y: 1 } + Rectangle { + x: 6; y: 4; width: 77; height: parent.height - 9; color: "white"; smooth: true + + } + Column { + x: 92; width: wrapper.ListView.view.width - 95; y: 15; spacing: 2 + Text { text: title; color: "white"; width: parent.width; font.bold: true; elide: Text.ElideRight; style: Text.Raised; styleColor: "black" } + //Text { text: feedname; width: parent.width; elide: Text.ElideLeft; color: "#cccccc"; style: Text.Raised; styleColor: "black" } + } + } + MouseArea { anchors.fill: wrapper; onClicked: { categoryClicked() } } + + // Animate adding and removing of items: + +// ListView.onAdd: SequentialAnimation { +// PropertyAction { target: wrapper; property: "height"; value: 0 } +// NumberAnimation { target: wrapper; property: "height"; to: 86; duration: 250; easing.type: Easing.InOutQuad } +// } + +// ListView.onRemove: SequentialAnimation { +// PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: true } +// NumberAnimation { target: wrapper; property: "height"; to: 0; duration: 250; easing.type: Easing.InOutQuad } + +// // Make sure delayRemove is set back to false so that the item can be destroyed +// PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: false } +// } + + } + + } + + Component { + id: feedDelegate + + Item { + + function feedClicked() { + //feeds.query = "/xml/category[catid=\"" + catid +"\"]/feed" + //feeds.reload() + //feedList.model = feeds; + } + id: wrapper; width: wrapper.ListView.view.width; height: 86 + Item { + id: moveMe + Rectangle { color: "black"; opacity: index % 2 ? 0.2 : 0.4; height: 84; width: wrapper.width; y: 1 } + Rectangle { + x: 6; y: 4; width: 77; height: 77; color: "#ff0000"; smooth: true + + } + Column { + x: 92; width: wrapper.ListView.view.width - 95; y: 15; spacing: 2 + Text { text: title; color: "white"; width: parent.width; font.bold: true; elide: Text.ElideRight; style: Text.Raised; styleColor: "black" } + //Text { text: feedname; width: parent.width; elide: Text.ElideLeft; color: "#cccccc"; style: Text.Raised; styleColor: "black" } + } + } + MouseArea { anchors.fill: wrapper; onClicked: { feedClicked() } } + } + + } + +} diff --git a/src/rss_sqlite.py b/src/rss_sqlite.py index 7f3c2b1..2befd61 100644 --- a/src/rss_sqlite.py +++ b/src/rss_sqlite.py @@ -126,8 +126,10 @@ class Feed: entry["author"] except: entry["author"] = None + if(not(entry.has_key("id"))): + entry["id"] = None tmpEntry = {"title":entry["title"], "content":self.extractContent(entry), - "date":date, "link":entry["link"], "author":entry["author"]} + "date":date, "link":entry["link"], "author":entry["author"], "id":entry["id"]} id = self.generateUniqueId(tmpEntry) #articleTime = time.mktime(self.entries[id]["dateTuple"]) @@ -240,7 +242,10 @@ class Feed: return self.db.execute("SELECT date FROM feed WHERE id=?;", (id,) ).fetchone()[0] def generateUniqueId(self, entry): - return getId(str(entry["date"]) + str(entry["title"])) + if(entry["id"] != None): + return getId(str(entry["id"])) + else: + return getId(str(entry["date"]) + str(entry["title"])) def getIds(self, onlyUnread=False): if onlyUnread: @@ -285,7 +290,7 @@ class Feed: text += "" + title + "" text += '\n' #text += '' - text += '
' + title + "" + text += '
' + title + "" if author != None: text += "
Author: " + author + "" text += "
Date: " + date + "
" @@ -528,7 +533,6 @@ class Listing: return keys def getCategoryTitle(self, id): - print id row = self.db.execute("SELECT title FROM categories WHERE id=?;", (id, )).fetchone() return row[0] -- 1.7.9.5