psa: improved add feed/categories dialog
authorYves Marcoz <yves@marcoz.org>
Tue, 8 Nov 2011 05:34:24 +0000 (21:34 -0800)
committerYves Marcoz <yves@marcoz.org>
Tue, 8 Nov 2011 05:34:24 +0000 (21:34 -0800)
black/white theme support
delete categories/feeds support

43 files changed:
psa_harmattan/feedingit/build-deb.log
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/changelog
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/control
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/DEBIAN/control
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/DEBIAN/md5sums
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/usr/share/doc/feedingit/changelog.Debian.gz
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/usr/share/feedingit/XmlHandler.py
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/usr/share/feedingit/debugging.py
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/usr/share/feedingit/feedingit.py
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/usr/share/feedingit/qml/ArticleViewer.qml
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/usr/share/feedingit/qml/Categories.qml
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/usr/share/feedingit/qml/Feeds.qml
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/usr/share/feedingit/qml/TestWebview.qml
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/usr/share/feedingit/qml/main.qml
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/usr/share/feedingit/rss_sqlite.py
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/usr/share/pyshared/feedingit-0.1.0.egg-info
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/rules
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/feedingit.longdesc
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/pysrc/XmlHandler.py
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/pysrc/debugging.py
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/pysrc/feedingit.py
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/pysrc/rss_sqlite.py
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/qml/ArticleViewer.qml
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/qml/Categories.qml
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/qml/Feeds.qml
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/qml/TestWebview.qml
psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/qml/main.qml
psa_harmattan/feedingit/deb_dist/feedingit_0.1.0-1.debian.tar.gz
psa_harmattan/feedingit/deb_dist/feedingit_0.1.0-1.dsc
psa_harmattan/feedingit/deb_dist/feedingit_0.1.0-1_all.deb
psa_harmattan/feedingit/deb_dist/feedingit_0.1.0-1_i386.changes
psa_harmattan/feedingit/deb_dist/feedingit_0.1.0.orig.tar.gz
psa_harmattan/feedingit/feedingit.longdesc
psa_harmattan/feedingit/pysrc/XmlHandler.py
psa_harmattan/feedingit/pysrc/feedingit.py
psa_harmattan/feedingit/pysrc/rss_sqlite.py
psa_harmattan/feedingit/qml/AddFeed.qml
psa_harmattan/feedingit/qml/ArticleViewer.qml
psa_harmattan/feedingit/qml/Categories.qml
psa_harmattan/feedingit/qml/Feeds.qml
psa_harmattan/feedingit/qml/Settings.qml [new file with mode: 0644]
psa_harmattan/feedingit/qml/main.qml
src/rss_sqlite.py

index 71a7529..ffed24a 100644 (file)
@@ -74,6 +74,7 @@ copying qml/TextInputClear.qml -> /scratchbox/users/ymarcoz/home/ymarcoz/workspa
 copying qml/ArticleViewer.qml -> /scratchbox/users/ymarcoz/home/ymarcoz/workspace/feedingit/psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/usr/share/feedingit/qml
 copying qml/MainPage.qml -> /scratchbox/users/ymarcoz/home/ymarcoz/workspace/feedingit/psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/usr/share/feedingit/qml
 copying qml/main.qml -> /scratchbox/users/ymarcoz/home/ymarcoz/workspace/feedingit/psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/usr/share/feedingit/qml
+copying qml/Settings.qml -> /scratchbox/users/ymarcoz/home/ymarcoz/workspace/feedingit/psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/usr/share/feedingit/qml
 copying qml/ArticleDisplay.qml -> /scratchbox/users/ymarcoz/home/ymarcoz/workspace/feedingit/psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/usr/share/feedingit/qml
 copying qml/AddFeed.qml -> /scratchbox/users/ymarcoz/home/ymarcoz/workspace/feedingit/psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/usr/share/feedingit/qml
 copying qml/feedSearch.js -> /scratchbox/users/ymarcoz/home/ymarcoz/workspace/feedingit/psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/usr/share/feedingit/qml
index 1603ef9..88ed358 100644 (file)
@@ -2,4 +2,4 @@ feedingit (0.1.0-1) unstable; urgency=low
 
   * source package automatically created by stdeb 0.6.0+git
 
- -- Yves <yves@marcoz.org>  Sun, 06 Nov 2011 21:13:19 -0800
+ -- Yves <yves@marcoz.org>  Mon, 07 Nov 2011 21:25:40 -0800
index 7fc9752..4414804 100644 (file)
@@ -11,8 +11,9 @@ Architecture: all
 Depends: ${misc:Depends}, python-pyside.qtgui, python-pyside.qtopengl, python-pyside.qtdeclarative, python-dbus, python-gconf
 Breaks: ${python:Breaks}
 Description: FeedingIt - RSS Reader
- This file should contain a writeup describing what your application does,
- and how to use it. The content of this file goes into the long_description
- field of setup.py, which in turn becomes the long version of the Description
- field in the debian/control file of the project.
+ FeedingIt is an easy to use RSS feed reader with portrait mode support and 
+ automatic feed updates. You can swipe left and right to move between articles.
+ Import and export of subscription lists is supported for OPML files.
+ Images can be cached during the feed update, so you can view images in the
+ downloaded articles while offline.
  .
index 037b0fa..4ad45af 100644 (file)
@@ -2,13 +2,14 @@ Package: feedingit
 Version: 0.1.0-1
 Architecture: all
 Maintainer: Yves <yves@marcoz.org>
-Installed-Size: 756
+Installed-Size: 764
 Depends: python-pyside.qtgui, python-pyside.qtopengl, python-pyside.qtdeclarative, python-dbus, python-gconf
 Breaks: python (<< 2.6)
 Section: user/development
 Priority: optional
 Description: FeedingIt - RSS Reader
- This file should contain a writeup describing what your application does,
- and how to use it. The content of this file goes into the long_description
- field of setup.py, which in turn becomes the long version of the Description
- field in the debian/control file of the project.
+ FeedingIt is an easy to use RSS feed reader with portrait mode support and
+ automatic feed updates. You can swipe left and right to move between articles.
+ Import and export of subscription lists is supported for OPML files.
+ Images can be cached during the feed update, so you can view images in the
+ downloaded articles while offline.
index 6649503..a74cf8d 100644 (file)
@@ -1,28 +1,29 @@
 4420c31f88de68fe6e1b7637abb06196  usr/bin/feedingit
 6a42e9aebedfd157062bd5a9616dc935  usr/share/applications/feedingit.desktop
 eda8cc6ffe8d842d6dfe0244b01b3042  usr/share/dbus-1/services/feedingit_status.service
-8a3883bbf4914140ca72678bfdac9230  usr/share/doc/feedingit/changelog.Debian.gz
+f0e50a0975405a76169cc01da42cdcff  usr/share/doc/feedingit/changelog.Debian.gz
 bac2be6ae9673ee5096e20e8b714c9cd  usr/share/feedingit/BeautifulSoup.py
-fa5490f2022424a091b36e75f21e6596  usr/share/feedingit/XmlHandler.py
+8f6e980f2e1154103a90763be6c00dc4  usr/share/feedingit/XmlHandler.py
 d41d8cd98f00b204e9800998ecf8427e  usr/share/feedingit/__init__.py
 6b5296119ef6bc859c3e3a8706fa7f0d  usr/share/feedingit/config.py
-4724920e64b0f5d2828c1c245502a115  usr/share/feedingit/debugging.py
+9cf859c8297e4b0e8466cb5861eb75e7  usr/share/feedingit/debugging.py
 fae02e730b76761d43a626fe19828d5e  usr/share/feedingit/download.py
-b9b632032e30e584115aecab8c809f88  usr/share/feedingit/feedingit.py
+42786634079070f54f06838e922a1307  usr/share/feedingit/feedingit.py
 afa4f462892136f59beaf96b6bf1cf96  usr/share/feedingit/feedparser.py
 c1a0c0a9ccefd64d1e27bddb817c72a3  usr/share/feedingit/httpprogresshandler.py
 f1e9ba0f44786f513659a7fa3111fc8a  usr/share/feedingit/jobmanager.py
 0201faa30d34c58d71f36ab42a7a8233  usr/share/feedingit/mainthread.py
 d9c0665dfdd5cf19f1529ce88af95134  usr/share/feedingit/opml.py
-37230c16aad0865afbec03d8105dd491  usr/share/feedingit/qml/AddFeed.qml
+31d26f7ae14940f99ec8d47c7035fd04  usr/share/feedingit/qml/AddFeed.qml
 af27062fdba0bc7a3df92116e8340d19  usr/share/feedingit/qml/ArticleDisplay.qml
-594c82729b9e53bd9ca143006e088893  usr/share/feedingit/qml/ArticleViewer.qml
+80858d581189fcf00ab1c6192be87e27  usr/share/feedingit/qml/ArticleViewer.qml
 15083e9a1fac05c8efaaa085dfabcbcb  usr/share/feedingit/qml/Articles.qml
-555d070ba1db23b7b553628c9ae4ce72  usr/share/feedingit/qml/Categories.qml
+8f480702a2107a8017fdd94226b9b7d4  usr/share/feedingit/qml/Categories.qml
 cd30f5eaec0885358261d7a96bfaf8cd  usr/share/feedingit/qml/FeedingIt.qml
-29e9f5811d5e5bb9b4078fb2fb8d5b17  usr/share/feedingit/qml/Feeds.qml
+02784496485eb5547a1ad48c043bb2a9  usr/share/feedingit/qml/Feeds.qml
 bec5fe4599a3ad5799ed96d7ed81fb5f  usr/share/feedingit/qml/MainPage.qml
-aa3fc0a4edbd17d93a9dc5c39c433c3d  usr/share/feedingit/qml/TestWebview.qml
+1c500d41d190f8f8c6d478fda117bb28  usr/share/feedingit/qml/Settings.qml
+53595350196421039e3adefac380d21f  usr/share/feedingit/qml/TestWebview.qml
 508fde19c7bb7bc4892bd6642fbcb7d3  usr/share/feedingit/qml/TextInputClear.qml
 cef5ae4af926a759f4a233336c00f017  usr/share/feedingit/qml/common/AddCat.qml
 c39cde168ef8d608670c81be7c808701  usr/share/feedingit/qml/common/AddFeed.qml
@@ -56,11 +57,11 @@ af11b73b195513d08c17723b41db0b04  usr/share/feedingit/qml/common/images/wmBackIc
 1c7751b124aa1bdf4b89ec76cdf815a2  usr/share/feedingit/qml/i18n/FeedingIt.ts
 7790a99425dd7c1046e6ae3b1ee72a03  usr/share/feedingit/qml/i18n/qml_en.qm
 1674fcce45bcf3319e61d19a9adf4fdd  usr/share/feedingit/qml/i18n/qml_en.ts
-c94a3937f0104446e0ceed1eb4aacf78  usr/share/feedingit/qml/main.qml
-7def699001828ea16976de3d5835dd3c  usr/share/feedingit/rss_sqlite.py
+0ede84085fc61707b6ee27f72ef2808c  usr/share/feedingit/qml/main.qml
+da4cc789664ec1980300d1df080c6d90  usr/share/feedingit/rss_sqlite.py
 721777a26cd2a5b8466ce2aa2b99fad7  usr/share/feedingit/update_feeds.py
 6ccf12dc4379e91800ae8505b2e86082  usr/share/feedingit/updatedbus.py
 833ff79caab7c1fa89d6ff4a2f3bb3fd  usr/share/feedingit/wc.py
 8d49c002ad8bb98837e2a642eec86fc5  usr/share/icons/hicolor/64x64/apps/feedingit.png
-035a8a90300ae10602a25bd24a8121c7  usr/share/pyshared/feedingit-0.1.0.egg-info
+7f4a829935d2f4cfede75830a4dd61c7  usr/share/pyshared/feedingit-0.1.0.egg-info
 1ce7b7194658769bb4173134a725d1ce  usr/share/python/runtime.d/feedingit.rtupdate
index 2b6e9a9..79c27ea 100644 (file)
Binary files a/psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/usr/share/doc/feedingit/changelog.Debian.gz and b/psa_harmattan/feedingit/deb_dist/feedingit-0.1.0/debian/feedingit/usr/share/doc/feedingit/changelog.Debian.gz differ
index 8acdb75..41167cb 100644 (file)
@@ -49,9 +49,11 @@ class XmlHandler():
     def generateCategoryXml(self):
         xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><xml>"
         for cat in self.listing.getListOfCategories():
+            print cat
             xml += "<category>"
             xml += "<catname>%s</catname>" %sanitize(self.listing.getCategoryTitle(cat))
             xml += "<catid>%s</catid>" % cat
+            xml += "<unread>%s</unread>" % self.listing.getCategoryUnread(cat)
             xml += "</category>"
         xml += "</xml>"
         return xml
index 91be2b4..7330871 100644 (file)
@@ -35,7 +35,6 @@ def my_excepthook(exctype, value, tb):
     original_excepthook(exctype, value, tb)
 
 def init(dot_directory, debug=False, max_logfiles=1, program_name=None):
-    debug = True
     if not os.path.isabs(dot_directory):
         dot_directory = os.path.join(os.path.expanduser("~"), dot_directory)
 
index 209c021..10d08b9 100644 (file)
@@ -7,6 +7,7 @@ from PySide import QtDeclarative
 import os
 from os import mkdir, remove, stat, environ
 from os.path import isfile, isdir, exists
+import codecs
 
 # Comment the line below if you don't want to use OpenGL for QML rendering or if it is not supported
 from PySide import QtOpenGL,  QtCore
@@ -35,11 +36,11 @@ class Controller(QtCore.QObject):
     def getArticle(self, key, article):
        feed = listing.getFeed(key)
        try:
-          file = open(feed.getContentLink(article))
+          file = codecs.open(feed.getContentLink(article), "r", "utf-8")
           html = file.read().replace("body", "body bgcolor='#ffffff'", 1)
           file.close()
        except:
-          html = "<html><body>Error retrieving article</body></html>"
+          html = u"<html><body>Error retrieving article</body></html>"
        return html
     
     @QtCore.Slot(str, result=str)
@@ -67,9 +68,15 @@ class Controller(QtCore.QObject):
         
     @QtCore.Slot()
     def updateAll(self):
-        for feed in listing.getSortedListOfKeys("Manual"):
-            listing.updateFeed(feed)
-            
+        for catid in listing.getListOfCategories():
+            for feed in listing.getSortedListOfKeys("Manual", category=catid):
+                listing.updateFeed(feed)
+
+    @QtCore.Slot(str)
+    def updateCategory(self, catid):
+        for feed in listing.getSortedListOfKeys("Manual", category=catid):
+            listing.updateFeed(feed)           
+
     @QtCore.Slot(str,str,str)
     def addFeed(self, title, url, catid):
         listing.addFeed(title,url, category=catid)
@@ -79,6 +86,14 @@ class Controller(QtCore.QObject):
         listing.addCategory(name)
 
     @QtCore.Slot(str)
+    def removeFeed(self, key):
+        listing.removeFeed(key)
+
+    @QtCore.Slot(str)
+    def removeCategory(self, catid):
+        listing.removeCategory(catid)
+
+    @QtCore.Slot(str)
     def markAllAsRead(self, key):
         feed = listing.getFeed(key)
         feed.markAllAsRead()
index 83898b4..ac31e0b 100644 (file)
@@ -108,16 +108,24 @@ Item {
             id: listing;
 
             Item {
-                width: articleViewer.width; height: 86
+                width: articleViewer.width; height: backRect.height + 3
                 id: listItem
-                Rectangle { id: backRect; color: "#dddddd"; opacity: index % 2 ? 0.2 : 0.4; height: 84; width: listItem.width; y: 1 }
+                Rectangle {
+                    id: backRect; color: settings.backColour; opacity: index % 2 ? 0.2 : 0.4;
+                    height: articleText.height + 22; width: listItem.width;
+                    y: 1
+                }
                 Text {
-                    anchors.fill: backRect
+                    id: articleText
+                    anchors.verticalCenter: backRect.verticalCenter
+                    x: 3
+                    width: listItem.width - 6;
+
                     anchors.margins: 5
                     verticalAlignment: Text.AlignVCenter; text: title;
-                    color: (unread=="True") ? "white" : "#7b97fd";
+                    color: (unread=="True") ? settings.mainTextColour : settings.secondaryTextColour;
 
-                    width: listItem.width; wrapMode: Text.WordWrap; font.bold: false;
+                     wrapMode: Text.WordWrap; font.bold: false;
                     font.pointSize: 18
                 }
                 MouseArea { anchors.fill: listItem;
index 5a97370..4469ba1 100644 (file)
@@ -8,7 +8,9 @@ Item {
     signal categoryClicked(string cat)
 
     function reload() {
-        categories.reload();
+        //categories.reload();
+        categories.xml = controller.getCategoryXml()
+        //console.log(controller.getCategoryXml())
     }
 
     ListView {
@@ -25,6 +27,7 @@ Item {
 
         XmlRole { name: "title"; query: "catname/string()" }
         XmlRole { name: "catid"; query: "catid/string()"; isKey: true }
+        XmlRole { name: "unread"; query: "unread/string()" }
     }
 
     Component {
@@ -36,46 +39,68 @@ Item {
             Item {
                 id: moveMe
                 height: parent.height
-                Rectangle { color: "#eeeeee"; opacity: index % 2 ? 0.2 : 0.4; height: 84; width: wrapper.width; y: 1 }
+                Rectangle { color: settings.backColour; 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: 15;
-                    width: wrapper.ListView.view.width /*- 95; y: 15*/; spacing: 2
+                    width: wrapper.ListView.view.width /*- 95;*/
+                    y: 15; spacing: 2
                     anchors.margins: 5
                     height: parent.height
 
-                    Text { text: title; color: "white"; width: parent.width; font.bold: true;
-                        height: parent.height
-                        elide: Text.ElideRight; style: Text.Raised; styleColor: "black"; font.pointSize: 20
+                    Text { text: title; color: settings.mainTextColour; width: parent.width; font.bold: true;
+                        //height: parent.height
+                        elide: Text.ElideRight; style: Text.Raised;
+                        styleColor: settings.mainShadowColour;
+                        font.pointSize: settings.mainTextSize
                         verticalAlignment: Text.AlignVCenter;
                     }
+                    Text {
+                        text: qsTr("%1 unread items").arg(unread);
+                        color: (unread=="0") ? settings.mainTextColour : settings.secondaryTextColour;
+                        width: parent.width; font.bold: false;
+                        elide: Text.ElideRight;
+                        //style: Text.Raised; styleColor: settings.mainShadowColour;
+                        font.pointSize: settings.secondaryTextSize
+                    }
                     //Text { text: feedname; width: parent.width; elide: Text.ElideLeft; color: "#cccccc"; style: Text.Raised; styleColor: "black" }
                 }
-                Item {
-                    x: wrapper.ListView.view.width - 128; y: 12
-                    height: 58; width: 58;
-                    //anchors.horizontalCenter: parent.horizontalCenter;
-                    Image { source: "common/images/wmEditIcon.png" }
-                    MouseArea {
-                        anchors.fill: parent; onClicked: { container.categoryEdit(catname, catid); }
-                    }
-                    visible: inEditMode
+//                Item {
+//                    x: wrapper.ListView.view.width - 128; y: 12
+//                    height: 58; width: 58;
+//                    //anchors.horizontalCenter: parent.horizontalCenter;
+//                    Image { source: "common/images/wmEditIcon.png" }
+//                    MouseArea {
+//                        anchors.fill: parent; onClicked: { container.categoryEdit(catname, catid); }
+//                    }
+//                    visible: inEditMode
+//                }
+//                Item {
+//                    x: wrapper.ListView.view.width - 64; y: 12
+//                    height: 58; width: 58;
+//                    //anchors.horizontalCenter: parent.horizontalCenter;
+//                    Image { source: "common/images/delete.png" }
+//                    MouseArea {
+//                        anchors.fill: parent; onClicked: { container.categoryDeleted(catid); }
+//                    }
+//                    visible: inEditMode
+//                }
+            }
+            MouseArea {
+                enabled: !inEditMode; anchors.fill: wrapper;
+                onClicked: { categoryClicked(catid); }
+                onPressAndHold: {
+                    window.longPressCategory(catid)
                 }
-                Item {
-                    x: wrapper.ListView.view.width - 64; y: 12
-                    height: 58; width: 58;
-                    //anchors.horizontalCenter: parent.horizontalCenter;
-                    Image { source: "common/images/delete.png" }
-                    MouseArea {
-                        anchors.fill: parent; onClicked: { container.categoryDeleted(catid); }
-                    }
-                    visible: inEditMode
+            }
+            Component.onCompleted: {
+                if (categories.count == 1) {
+                    categoryClicked(catid)
                 }
             }
-            MouseArea { enabled: !inEditMode; anchors.fill: wrapper; onClicked: { categoryClicked(catid); } }
         }
     }
 }
index 32b5919..5131cbc 100644 (file)
@@ -56,21 +56,34 @@ Item {
 
             Item {
                 id: moveMe
-                Rectangle { color: "#dddddd"; opacity: index % 2 ? 0.2 : 0.4; height: 84; width: wrapper.width; y: 1 }
+                Rectangle { color: settings.backColour; 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: (updating=="True")? "common/images/loading.png" : (icon == "False") ? "common/images/feedingit.png" : icon;
-                        NumberAnimation on rotation {
-                            from: 0; to: 360; running: (updating=="True"); loops: Animation.Infinite; duration: 900
-                        }
+                    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") ? "common/images/feedingit.png" : icon
+                            // (updating=="True")? "common/images/loading.png" : (icon == "False") ? "common/images/feedingit.png" : icon;
+//                        NumberAnimation on rotation {
+//                            from: 0; to: 360; running: (updating=="True"); loops: Animation.Infinite; duration: 900
+//                        }
                     }
                 }
 
                 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"; font.pointSize: 18 }
-                    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"; font.pointSize: 12 }
+                    Text { text: title; color: settings.mainTextColour;
+                        width: parent.width;
+                        font.bold: true; elide: Text.ElideRight; style: Text.Raised; styleColor: settings.mainShadowColour;
+                        font.pointSize: settings.mainTextSize
+                    }
+                    Text {
+                        text: updatedDate + " / " + qsTr("%1 unread items").arg(unread);
+                        color: (unread=="0") ? settings.mainTextColour : settings.secondaryTextColour;
+                        width: parent.width; font.bold: false; elide: Text.ElideRight;
+                        //style: Text.Raised; styleColor: settings.mainShadowColour;
+                        font.pointSize: settings.secondaryTextSize
+                    }
                     //Text { text: feedname; width: parent.width; elide: Text.ElideLeft; color: "#cccccc"; style: Text.Raised; styleColor: "black" }
                 }
 ////                Item {
@@ -101,6 +114,9 @@ Item {
                     feedClicked(feedid)
                     
                 }
+                onPressAndHold: {
+                    window.longPressFeed(feedid)
+                }
             }
 
         }
index 79e05fc..e992e1e 100644 (file)
@@ -20,8 +20,9 @@ Rectangle {
 
         WebView {
             id: webView
-            url: "http://www.google.com";
-            //url: "/home/user/.feedingit/640fb167aca8bf5318ed721c5162f5eb.d/56a86b6b1675716ab54db83b1a78ab4c.html"
+            //url: "http://www.google.com";
+            //url: "http://www.viedemerde.fr/inclassable/5873986?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+viedemerde+%28Vie+de+merde%29"
+            url: "/home/ymarcoz/.feedingit/361f6abe590be9c681b5489e5d48331c.d/1b1033c75378fb19a8a70151d764cd33.html"
             preferredWidth: flickable.width
             preferredHeight: flickable.height
             settings.defaultFontSize: 32
index e38c12a..2fda083 100644 (file)
@@ -6,12 +6,25 @@ PageStackWindow {
     id: window
     initialPage: categoryPage
 
-    signal articleClosed()
+    signal longPressCategory(string catid)
+    signal longPressFeed(string key)
+    signal categoryReloadRequest()
+    signal feedReloadRequest()
     property string feedid
     property string catid
 
     Component.onCompleted: theme.inverted= true
 
+    onLongPressFeed: {
+        unsubscribeFeedMenu.key = key
+        unsubscribeFeedMenu.open()
+    }
+
+    onLongPressCategory: {
+        unsubscribeCategoryMenu.catid = catid
+        unsubscribeCategoryMenu.open()
+    }
+
     ToolBarLayout {
         id: commonTools
         visible: false
@@ -29,6 +42,7 @@ PageStackWindow {
         visualParent: pageStack
         MenuLayout {
             MenuItem { text: qsTr("Settings"); onClicked: {}  }
+            MenuItem { text: qsTr("Invert Theme"); onClicked: { theme.inverted = !theme.inverted }  }
             MenuItem { text: qsTr("Add Feeds"); onClicked: { pageStack.push(addFeedPage)  } }
             MenuItem { text: qsTr("Update All Categories"); onClicked: controller.updateAll(); }
             MenuItem { text: qsTr("About FeedingIt"); onClicked: query.open(); }
@@ -39,8 +53,8 @@ PageStackWindow {
         id: myFeedsMenu
         visualParent: pageStack
         MenuLayout {
-            MenuItem { text: qsTr("Update All Feeds"); onClicked: controller.updateAll(); }
-            MenuItem { text: qsTr("About FeedingIt"); onClicked: query.open(); }
+            MenuItem { text: qsTr("Update All Feeds"); onClicked: controller.updateCategory(catid); }
+            //MenuItem { text: qsTr("About FeedingIt"); onClicked: query.open(); }
         }
     }
 
@@ -50,7 +64,61 @@ PageStackWindow {
         MenuLayout {
             MenuItem { text: qsTr("Mark All As Read"); onClicked: controller.markAllAsRead(feedid); }
             MenuItem { text: qsTr("Update Feed"); onClicked: controller.updateFeed(feedid); }
-            MenuItem { text: qsTr("About FeedingIt"); onClicked: query.open(); }
+            //MenuItem { text: qsTr("About FeedingIt"); onClicked: query.open(); }
+        }
+    }
+
+    Menu {
+        id: unsubscribeFeedMenu
+        visualParent: pageStack
+        property string key
+        MenuLayout {
+            //MenuItem { text: qsTr("Update"); onClicked: controller.updateFeed(parent.feedid); }
+            MenuItem { text: qsTr("Delete");
+                onClicked: {
+                    feedConfirm.open()
+                    unsubscribeFeedMenu.close()
+                }
+            }
+        }
+        QueryDialog {
+            id: feedConfirm
+            //icon: "common/images/feedingit.png"
+            //titleText: "Delete Feed?"
+            message: "Delete this feed?"
+            acceptButtonText: "OK"
+            rejectButtonText: "Cancel"
+            onAccepted: {
+                controller.removeFeed(unsubscribeFeedMenu.key);
+                window.feedReloadRequest()
+            }
+        }
+    }
+
+    Menu {
+        id: unsubscribeCategoryMenu
+        visualParent: pageStack
+        property string catid
+        MenuLayout {
+            //MenuItem { text: qsTr("Update"); onClicked: controller.updateFeed(parent.feedid); }
+            MenuItem { text: qsTr("Delete");
+                onClicked: {
+                    categoryConfirm.open()
+                    unsubscribeFeedMenu.close()
+                }
+            }
+        }
+        QueryDialog {
+            id: categoryConfirm
+            //icon: "common/images/feedingit.png"
+            //titleText: "Delete Feed?"
+            message: "Delete this category?"
+            acceptButtonText: "OK"
+            rejectButtonText: "Cancel"
+            onAccepted: {
+                controller.removeCategory(unsubscribeCategoryMenu.catid);
+                window.categoryReloadRequest()
+            }
         }
     }
 
@@ -65,23 +133,24 @@ PageStackWindow {
         acceptButtonText: "OK"
     }
 
-//    Page{
-//        id: mainPage
-//        Component.onCompleted: {
-//            var main = Qt.createComponent("FeedingIt.qml");
-//            main.createObject(mainPage);
-//        }
-//    }
-
     Component {
         id: categoryPage
         Page {
             tools: commonTools
             Categories {
+                id: categoriesItem
                 onCategoryClicked: {
                     window.catid = cat
                     pageStack.push(feedsPage)
                 }
+
+            }
+            Connections {
+                target: window
+                onCategoryReloadRequest: {
+                    console.log("category reloaded")
+                    categoriesItem.reload()
+                }
             }
         }
     }
@@ -99,6 +168,7 @@ PageStackWindow {
                     window.feedid = feedid
                     pageStack.push(articlesPage)
                 }
+
             }
             ToolBarLayout {
                 id: feedsTools
@@ -117,7 +187,7 @@ PageStackWindow {
             }
             Connections {
                  target: window
-                 onArticleClosed: feedsItem.reload()
+                 onFeedReloadRequest: feedsItem.reload()
              }
         }
     }
@@ -141,7 +211,7 @@ PageStackWindow {
                             flipper.articleShown = false;
                             flipper.reload()
                         } else {
-                            window.articleClosed();
+                            window.feedReloadRequest();
                             pageStack.pop();
                         }
                     }
@@ -174,4 +244,8 @@ PageStackWindow {
         id: addFeedPage
         AddFeed {}
     }
+
+    Settings {
+        id: settings
+    }
 }
index 4b4d276..68797cd 100644 (file)
@@ -1211,6 +1211,15 @@ class Listing(BaseObject):
     
     def getCategoryTitle(self, id):
         return self.lookup('categories', 'title', id)
+
+    def getCategoryUnread(self, id):
+        count = 0
+        for key in self.getListOfFeeds(category=id):
+            try: 
+                count = count + self.getFeedNumberOfUnreadItems(key)
+            except:
+                pass
+        return count
     
     def getSortedListOfKeys(self, order, onlyUnread=False, category=1):
         if   order == "Most unread":
@@ -1286,6 +1295,7 @@ class Listing(BaseObject):
             id=1
         self.db.execute("INSERT INTO categories (id, title, unread, rank) VALUES (?, ?, 0, ?)", (id, title, rank))
         self.db.commit()
+        self.cache_invalidate('categories')
     
     def removeFeed(self, key):
         if wc().available ():
@@ -1301,6 +1311,7 @@ class Listing(BaseObject):
 
         if isdir(self.configdir+key+".d/"):
            rmtree(self.configdir+key+".d/")
+        self.cache_invalidate('feeds')
            
     def removeCategory(self, key):
         if self.db.execute("SELECT count(*) FROM categories;").fetchone()[0] > 1:
@@ -1309,6 +1320,7 @@ class Listing(BaseObject):
             self.db.execute("UPDATE categories SET rank=rank-1 WHERE rank>?;", (rank,) )
             self.db.execute("UPDATE feeds SET category=1 WHERE category=?;", (key,) )
             self.db.commit()
+            self.cache_invalidate('categories')
         
     #def saveConfig(self):
     #    self.listOfFeeds["feedingit-order"] = self.sortedKeys
index 9b6014d..5d71c02 100644 (file)
@@ -6,9 +6,10 @@ Home-page: UNKNOWN
 Author: Yves
 Author-email: yves@marcoz.org
 License: UNKNOWN
-Description: This file should contain a writeup describing what your application does,
-        and how to use it. The content of this file goes into the long_description
-        field of setup.py, which in turn becomes the long version of the Description
-        field in the debian/control file of the project.
+Description: FeedingIt is an easy to use RSS feed reader with portrait mode support and 
+        automatic feed updates. You can swipe left and right to move between articles.
+        Import and export of subscription lists is supported for OPML files.
+        Images can be cached during the feed update, so you can view images in the
+        downloaded articles while offline.
         
 Platform: UNKNOWN
index 2b2c6df..5d5a425 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/make -f
 
 # This file was automatically generated by stdeb 0.6.0+git at
-# Sun, 06 Nov 2011 21:13:19 -0800
+# Mon, 07 Nov 2011 21:25:40 -0800
 
 %:
        dh $@ --with python2 --buildsystem=python_distutils
index 47e9f38..a606943 100644 (file)
@@ -1,4 +1,5 @@
-This file should contain a writeup describing what your application does,
-and how to use it. The content of this file goes into the long_description
-field of setup.py, which in turn becomes the long version of the Description
-field in the debian/control file of the project.
+FeedingIt is an easy to use RSS feed reader with portrait mode support and 
+automatic feed updates. You can swipe left and right to move between articles.
+Import and export of subscription lists is supported for OPML files.
+Images can be cached during the feed update, so you can view images in the
+downloaded articles while offline.
index 8acdb75..41167cb 100644 (file)
@@ -49,9 +49,11 @@ class XmlHandler():
     def generateCategoryXml(self):
         xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><xml>"
         for cat in self.listing.getListOfCategories():
+            print cat
             xml += "<category>"
             xml += "<catname>%s</catname>" %sanitize(self.listing.getCategoryTitle(cat))
             xml += "<catid>%s</catid>" % cat
+            xml += "<unread>%s</unread>" % self.listing.getCategoryUnread(cat)
             xml += "</category>"
         xml += "</xml>"
         return xml
index 91be2b4..7330871 100644 (file)
@@ -35,7 +35,6 @@ def my_excepthook(exctype, value, tb):
     original_excepthook(exctype, value, tb)
 
 def init(dot_directory, debug=False, max_logfiles=1, program_name=None):
-    debug = True
     if not os.path.isabs(dot_directory):
         dot_directory = os.path.join(os.path.expanduser("~"), dot_directory)
 
index 209c021..10d08b9 100644 (file)
@@ -7,6 +7,7 @@ from PySide import QtDeclarative
 import os
 from os import mkdir, remove, stat, environ
 from os.path import isfile, isdir, exists
+import codecs
 
 # Comment the line below if you don't want to use OpenGL for QML rendering or if it is not supported
 from PySide import QtOpenGL,  QtCore
@@ -35,11 +36,11 @@ class Controller(QtCore.QObject):
     def getArticle(self, key, article):
        feed = listing.getFeed(key)
        try:
-          file = open(feed.getContentLink(article))
+          file = codecs.open(feed.getContentLink(article), "r", "utf-8")
           html = file.read().replace("body", "body bgcolor='#ffffff'", 1)
           file.close()
        except:
-          html = "<html><body>Error retrieving article</body></html>"
+          html = u"<html><body>Error retrieving article</body></html>"
        return html
     
     @QtCore.Slot(str, result=str)
@@ -67,9 +68,15 @@ class Controller(QtCore.QObject):
         
     @QtCore.Slot()
     def updateAll(self):
-        for feed in listing.getSortedListOfKeys("Manual"):
-            listing.updateFeed(feed)
-            
+        for catid in listing.getListOfCategories():
+            for feed in listing.getSortedListOfKeys("Manual", category=catid):
+                listing.updateFeed(feed)
+
+    @QtCore.Slot(str)
+    def updateCategory(self, catid):
+        for feed in listing.getSortedListOfKeys("Manual", category=catid):
+            listing.updateFeed(feed)           
+
     @QtCore.Slot(str,str,str)
     def addFeed(self, title, url, catid):
         listing.addFeed(title,url, category=catid)
@@ -79,6 +86,14 @@ class Controller(QtCore.QObject):
         listing.addCategory(name)
 
     @QtCore.Slot(str)
+    def removeFeed(self, key):
+        listing.removeFeed(key)
+
+    @QtCore.Slot(str)
+    def removeCategory(self, catid):
+        listing.removeCategory(catid)
+
+    @QtCore.Slot(str)
     def markAllAsRead(self, key):
         feed = listing.getFeed(key)
         feed.markAllAsRead()
index 4b4d276..68797cd 100644 (file)
@@ -1211,6 +1211,15 @@ class Listing(BaseObject):
     
     def getCategoryTitle(self, id):
         return self.lookup('categories', 'title', id)
+
+    def getCategoryUnread(self, id):
+        count = 0
+        for key in self.getListOfFeeds(category=id):
+            try: 
+                count = count + self.getFeedNumberOfUnreadItems(key)
+            except:
+                pass
+        return count
     
     def getSortedListOfKeys(self, order, onlyUnread=False, category=1):
         if   order == "Most unread":
@@ -1286,6 +1295,7 @@ class Listing(BaseObject):
             id=1
         self.db.execute("INSERT INTO categories (id, title, unread, rank) VALUES (?, ?, 0, ?)", (id, title, rank))
         self.db.commit()
+        self.cache_invalidate('categories')
     
     def removeFeed(self, key):
         if wc().available ():
@@ -1301,6 +1311,7 @@ class Listing(BaseObject):
 
         if isdir(self.configdir+key+".d/"):
            rmtree(self.configdir+key+".d/")
+        self.cache_invalidate('feeds')
            
     def removeCategory(self, key):
         if self.db.execute("SELECT count(*) FROM categories;").fetchone()[0] > 1:
@@ -1309,6 +1320,7 @@ class Listing(BaseObject):
             self.db.execute("UPDATE categories SET rank=rank-1 WHERE rank>?;", (rank,) )
             self.db.execute("UPDATE feeds SET category=1 WHERE category=?;", (key,) )
             self.db.commit()
+            self.cache_invalidate('categories')
         
     #def saveConfig(self):
     #    self.listOfFeeds["feedingit-order"] = self.sortedKeys
index 83898b4..ac31e0b 100644 (file)
@@ -108,16 +108,24 @@ Item {
             id: listing;
 
             Item {
-                width: articleViewer.width; height: 86
+                width: articleViewer.width; height: backRect.height + 3
                 id: listItem
-                Rectangle { id: backRect; color: "#dddddd"; opacity: index % 2 ? 0.2 : 0.4; height: 84; width: listItem.width; y: 1 }
+                Rectangle {
+                    id: backRect; color: settings.backColour; opacity: index % 2 ? 0.2 : 0.4;
+                    height: articleText.height + 22; width: listItem.width;
+                    y: 1
+                }
                 Text {
-                    anchors.fill: backRect
+                    id: articleText
+                    anchors.verticalCenter: backRect.verticalCenter
+                    x: 3
+                    width: listItem.width - 6;
+
                     anchors.margins: 5
                     verticalAlignment: Text.AlignVCenter; text: title;
-                    color: (unread=="True") ? "white" : "#7b97fd";
+                    color: (unread=="True") ? settings.mainTextColour : settings.secondaryTextColour;
 
-                    width: listItem.width; wrapMode: Text.WordWrap; font.bold: false;
+                     wrapMode: Text.WordWrap; font.bold: false;
                     font.pointSize: 18
                 }
                 MouseArea { anchors.fill: listItem;
index 5a97370..4469ba1 100644 (file)
@@ -8,7 +8,9 @@ Item {
     signal categoryClicked(string cat)
 
     function reload() {
-        categories.reload();
+        //categories.reload();
+        categories.xml = controller.getCategoryXml()
+        //console.log(controller.getCategoryXml())
     }
 
     ListView {
@@ -25,6 +27,7 @@ Item {
 
         XmlRole { name: "title"; query: "catname/string()" }
         XmlRole { name: "catid"; query: "catid/string()"; isKey: true }
+        XmlRole { name: "unread"; query: "unread/string()" }
     }
 
     Component {
@@ -36,46 +39,68 @@ Item {
             Item {
                 id: moveMe
                 height: parent.height
-                Rectangle { color: "#eeeeee"; opacity: index % 2 ? 0.2 : 0.4; height: 84; width: wrapper.width; y: 1 }
+                Rectangle { color: settings.backColour; 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: 15;
-                    width: wrapper.ListView.view.width /*- 95; y: 15*/; spacing: 2
+                    width: wrapper.ListView.view.width /*- 95;*/
+                    y: 15; spacing: 2
                     anchors.margins: 5
                     height: parent.height
 
-                    Text { text: title; color: "white"; width: parent.width; font.bold: true;
-                        height: parent.height
-                        elide: Text.ElideRight; style: Text.Raised; styleColor: "black"; font.pointSize: 20
+                    Text { text: title; color: settings.mainTextColour; width: parent.width; font.bold: true;
+                        //height: parent.height
+                        elide: Text.ElideRight; style: Text.Raised;
+                        styleColor: settings.mainShadowColour;
+                        font.pointSize: settings.mainTextSize
                         verticalAlignment: Text.AlignVCenter;
                     }
+                    Text {
+                        text: qsTr("%1 unread items").arg(unread);
+                        color: (unread=="0") ? settings.mainTextColour : settings.secondaryTextColour;
+                        width: parent.width; font.bold: false;
+                        elide: Text.ElideRight;
+                        //style: Text.Raised; styleColor: settings.mainShadowColour;
+                        font.pointSize: settings.secondaryTextSize
+                    }
                     //Text { text: feedname; width: parent.width; elide: Text.ElideLeft; color: "#cccccc"; style: Text.Raised; styleColor: "black" }
                 }
-                Item {
-                    x: wrapper.ListView.view.width - 128; y: 12
-                    height: 58; width: 58;
-                    //anchors.horizontalCenter: parent.horizontalCenter;
-                    Image { source: "common/images/wmEditIcon.png" }
-                    MouseArea {
-                        anchors.fill: parent; onClicked: { container.categoryEdit(catname, catid); }
-                    }
-                    visible: inEditMode
+//                Item {
+//                    x: wrapper.ListView.view.width - 128; y: 12
+//                    height: 58; width: 58;
+//                    //anchors.horizontalCenter: parent.horizontalCenter;
+//                    Image { source: "common/images/wmEditIcon.png" }
+//                    MouseArea {
+//                        anchors.fill: parent; onClicked: { container.categoryEdit(catname, catid); }
+//                    }
+//                    visible: inEditMode
+//                }
+//                Item {
+//                    x: wrapper.ListView.view.width - 64; y: 12
+//                    height: 58; width: 58;
+//                    //anchors.horizontalCenter: parent.horizontalCenter;
+//                    Image { source: "common/images/delete.png" }
+//                    MouseArea {
+//                        anchors.fill: parent; onClicked: { container.categoryDeleted(catid); }
+//                    }
+//                    visible: inEditMode
+//                }
+            }
+            MouseArea {
+                enabled: !inEditMode; anchors.fill: wrapper;
+                onClicked: { categoryClicked(catid); }
+                onPressAndHold: {
+                    window.longPressCategory(catid)
                 }
-                Item {
-                    x: wrapper.ListView.view.width - 64; y: 12
-                    height: 58; width: 58;
-                    //anchors.horizontalCenter: parent.horizontalCenter;
-                    Image { source: "common/images/delete.png" }
-                    MouseArea {
-                        anchors.fill: parent; onClicked: { container.categoryDeleted(catid); }
-                    }
-                    visible: inEditMode
+            }
+            Component.onCompleted: {
+                if (categories.count == 1) {
+                    categoryClicked(catid)
                 }
             }
-            MouseArea { enabled: !inEditMode; anchors.fill: wrapper; onClicked: { categoryClicked(catid); } }
         }
     }
 }
index 32b5919..5131cbc 100644 (file)
@@ -56,21 +56,34 @@ Item {
 
             Item {
                 id: moveMe
-                Rectangle { color: "#dddddd"; opacity: index % 2 ? 0.2 : 0.4; height: 84; width: wrapper.width; y: 1 }
+                Rectangle { color: settings.backColour; 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: (updating=="True")? "common/images/loading.png" : (icon == "False") ? "common/images/feedingit.png" : icon;
-                        NumberAnimation on rotation {
-                            from: 0; to: 360; running: (updating=="True"); loops: Animation.Infinite; duration: 900
-                        }
+                    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") ? "common/images/feedingit.png" : icon
+                            // (updating=="True")? "common/images/loading.png" : (icon == "False") ? "common/images/feedingit.png" : icon;
+//                        NumberAnimation on rotation {
+//                            from: 0; to: 360; running: (updating=="True"); loops: Animation.Infinite; duration: 900
+//                        }
                     }
                 }
 
                 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"; font.pointSize: 18 }
-                    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"; font.pointSize: 12 }
+                    Text { text: title; color: settings.mainTextColour;
+                        width: parent.width;
+                        font.bold: true; elide: Text.ElideRight; style: Text.Raised; styleColor: settings.mainShadowColour;
+                        font.pointSize: settings.mainTextSize
+                    }
+                    Text {
+                        text: updatedDate + " / " + qsTr("%1 unread items").arg(unread);
+                        color: (unread=="0") ? settings.mainTextColour : settings.secondaryTextColour;
+                        width: parent.width; font.bold: false; elide: Text.ElideRight;
+                        //style: Text.Raised; styleColor: settings.mainShadowColour;
+                        font.pointSize: settings.secondaryTextSize
+                    }
                     //Text { text: feedname; width: parent.width; elide: Text.ElideLeft; color: "#cccccc"; style: Text.Raised; styleColor: "black" }
                 }
 ////                Item {
@@ -101,6 +114,9 @@ Item {
                     feedClicked(feedid)
                     
                 }
+                onPressAndHold: {
+                    window.longPressFeed(feedid)
+                }
             }
 
         }
index 79e05fc..e992e1e 100644 (file)
@@ -20,8 +20,9 @@ Rectangle {
 
         WebView {
             id: webView
-            url: "http://www.google.com";
-            //url: "/home/user/.feedingit/640fb167aca8bf5318ed721c5162f5eb.d/56a86b6b1675716ab54db83b1a78ab4c.html"
+            //url: "http://www.google.com";
+            //url: "http://www.viedemerde.fr/inclassable/5873986?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+viedemerde+%28Vie+de+merde%29"
+            url: "/home/ymarcoz/.feedingit/361f6abe590be9c681b5489e5d48331c.d/1b1033c75378fb19a8a70151d764cd33.html"
             preferredWidth: flickable.width
             preferredHeight: flickable.height
             settings.defaultFontSize: 32
index e38c12a..2fda083 100644 (file)
@@ -6,12 +6,25 @@ PageStackWindow {
     id: window
     initialPage: categoryPage
 
-    signal articleClosed()
+    signal longPressCategory(string catid)
+    signal longPressFeed(string key)
+    signal categoryReloadRequest()
+    signal feedReloadRequest()
     property string feedid
     property string catid
 
     Component.onCompleted: theme.inverted= true
 
+    onLongPressFeed: {
+        unsubscribeFeedMenu.key = key
+        unsubscribeFeedMenu.open()
+    }
+
+    onLongPressCategory: {
+        unsubscribeCategoryMenu.catid = catid
+        unsubscribeCategoryMenu.open()
+    }
+
     ToolBarLayout {
         id: commonTools
         visible: false
@@ -29,6 +42,7 @@ PageStackWindow {
         visualParent: pageStack
         MenuLayout {
             MenuItem { text: qsTr("Settings"); onClicked: {}  }
+            MenuItem { text: qsTr("Invert Theme"); onClicked: { theme.inverted = !theme.inverted }  }
             MenuItem { text: qsTr("Add Feeds"); onClicked: { pageStack.push(addFeedPage)  } }
             MenuItem { text: qsTr("Update All Categories"); onClicked: controller.updateAll(); }
             MenuItem { text: qsTr("About FeedingIt"); onClicked: query.open(); }
@@ -39,8 +53,8 @@ PageStackWindow {
         id: myFeedsMenu
         visualParent: pageStack
         MenuLayout {
-            MenuItem { text: qsTr("Update All Feeds"); onClicked: controller.updateAll(); }
-            MenuItem { text: qsTr("About FeedingIt"); onClicked: query.open(); }
+            MenuItem { text: qsTr("Update All Feeds"); onClicked: controller.updateCategory(catid); }
+            //MenuItem { text: qsTr("About FeedingIt"); onClicked: query.open(); }
         }
     }
 
@@ -50,7 +64,61 @@ PageStackWindow {
         MenuLayout {
             MenuItem { text: qsTr("Mark All As Read"); onClicked: controller.markAllAsRead(feedid); }
             MenuItem { text: qsTr("Update Feed"); onClicked: controller.updateFeed(feedid); }
-            MenuItem { text: qsTr("About FeedingIt"); onClicked: query.open(); }
+            //MenuItem { text: qsTr("About FeedingIt"); onClicked: query.open(); }
+        }
+    }
+
+    Menu {
+        id: unsubscribeFeedMenu
+        visualParent: pageStack
+        property string key
+        MenuLayout {
+            //MenuItem { text: qsTr("Update"); onClicked: controller.updateFeed(parent.feedid); }
+            MenuItem { text: qsTr("Delete");
+                onClicked: {
+                    feedConfirm.open()
+                    unsubscribeFeedMenu.close()
+                }
+            }
+        }
+        QueryDialog {
+            id: feedConfirm
+            //icon: "common/images/feedingit.png"
+            //titleText: "Delete Feed?"
+            message: "Delete this feed?"
+            acceptButtonText: "OK"
+            rejectButtonText: "Cancel"
+            onAccepted: {
+                controller.removeFeed(unsubscribeFeedMenu.key);
+                window.feedReloadRequest()
+            }
+        }
+    }
+
+    Menu {
+        id: unsubscribeCategoryMenu
+        visualParent: pageStack
+        property string catid
+        MenuLayout {
+            //MenuItem { text: qsTr("Update"); onClicked: controller.updateFeed(parent.feedid); }
+            MenuItem { text: qsTr("Delete");
+                onClicked: {
+                    categoryConfirm.open()
+                    unsubscribeFeedMenu.close()
+                }
+            }
+        }
+        QueryDialog {
+            id: categoryConfirm
+            //icon: "common/images/feedingit.png"
+            //titleText: "Delete Feed?"
+            message: "Delete this category?"
+            acceptButtonText: "OK"
+            rejectButtonText: "Cancel"
+            onAccepted: {
+                controller.removeCategory(unsubscribeCategoryMenu.catid);
+                window.categoryReloadRequest()
+            }
         }
     }
 
@@ -65,23 +133,24 @@ PageStackWindow {
         acceptButtonText: "OK"
     }
 
-//    Page{
-//        id: mainPage
-//        Component.onCompleted: {
-//            var main = Qt.createComponent("FeedingIt.qml");
-//            main.createObject(mainPage);
-//        }
-//    }
-
     Component {
         id: categoryPage
         Page {
             tools: commonTools
             Categories {
+                id: categoriesItem
                 onCategoryClicked: {
                     window.catid = cat
                     pageStack.push(feedsPage)
                 }
+
+            }
+            Connections {
+                target: window
+                onCategoryReloadRequest: {
+                    console.log("category reloaded")
+                    categoriesItem.reload()
+                }
             }
         }
     }
@@ -99,6 +168,7 @@ PageStackWindow {
                     window.feedid = feedid
                     pageStack.push(articlesPage)
                 }
+
             }
             ToolBarLayout {
                 id: feedsTools
@@ -117,7 +187,7 @@ PageStackWindow {
             }
             Connections {
                  target: window
-                 onArticleClosed: feedsItem.reload()
+                 onFeedReloadRequest: feedsItem.reload()
              }
         }
     }
@@ -141,7 +211,7 @@ PageStackWindow {
                             flipper.articleShown = false;
                             flipper.reload()
                         } else {
-                            window.articleClosed();
+                            window.feedReloadRequest();
                             pageStack.pop();
                         }
                     }
@@ -174,4 +244,8 @@ PageStackWindow {
         id: addFeedPage
         AddFeed {}
     }
+
+    Settings {
+        id: settings
+    }
 }
index 9b03374..39df53e 100644 (file)
Binary files a/psa_harmattan/feedingit/deb_dist/feedingit_0.1.0-1.debian.tar.gz and b/psa_harmattan/feedingit/deb_dist/feedingit_0.1.0-1.debian.tar.gz differ
index 91c1808..ca9964d 100644 (file)
@@ -7,11 +7,11 @@ Maintainer: Yves <yves@marcoz.org>
 Standards-Version: 3.9.1
 Build-Depends: python-all (>= 2.6.6-3), debhelper (>= 7.4.3)
 Checksums-Sha1: 
- 12a7cdb7b5cdb98d79bda6e6a4dc2562685423c3 176240 feedingit_0.1.0.orig.tar.gz
- 954096a5d2fa51bb359517d7578c684e4625f237 859 feedingit_0.1.0-1.debian.tar.gz
+ 0f46819e2084145776f49c7f7f2ee922a980687c 177736 feedingit_0.1.0.orig.tar.gz
+ bc99501e4cf014353f2f9d8807498a9d311337c7 931 feedingit_0.1.0-1.debian.tar.gz
 Checksums-Sha256: 
- 8421abef41b572247ce1292445c075eec032136b121e9d3bc550897881ea975a 176240 feedingit_0.1.0.orig.tar.gz
- 229779d81f6541d46086a972ee2d93db66abd4a7adc8be746f5c97d585aa4044 859 feedingit_0.1.0-1.debian.tar.gz
+ 223c41eba6bad5241f54e54e776a6e3bb272d07d91b1fa380848b7d8ce0128f4 177736 feedingit_0.1.0.orig.tar.gz
+ 58f20d85f1cae2b33fb346fc6bee304cd304b6674026540aee31b73748d49a7c 931 feedingit_0.1.0-1.debian.tar.gz
 Files: 
- c58fcc9048d74f69926cb53696c75c5e 176240 feedingit_0.1.0.orig.tar.gz
- e143c5daf921dac855fb227f77646a0e 859 feedingit_0.1.0-1.debian.tar.gz
+ 1b7ddb59ac327613cb42c0bbd7ffa06b 177736 feedingit_0.1.0.orig.tar.gz
+ 9c4aba31f4ca66c7cb5fe5dbcd83d100 931 feedingit_0.1.0-1.debian.tar.gz
index e0cb412..70ebaee 100644 (file)
Binary files a/psa_harmattan/feedingit/deb_dist/feedingit_0.1.0-1_all.deb and b/psa_harmattan/feedingit/deb_dist/feedingit_0.1.0-1_all.deb differ
index bfead88..edd979d 100644 (file)
@@ -1,5 +1,5 @@
 Format: 1.8
-Date: Sun, 06 Nov 2011 21:13:19 -0800
+Date: Mon, 07 Nov 2011 21:25:40 -0800
 Source: feedingit
 Binary: feedingit
 Architecture: source all
@@ -15,17 +15,17 @@ Changes:
  .
    * source package automatically created by stdeb 0.6.0+git
 Checksums-Sha1: 
- ec3bc8cdf6562addb5a09da997d8ebdcd8f94b51 753 feedingit_0.1.0-1.dsc
- 12a7cdb7b5cdb98d79bda6e6a4dc2562685423c3 176240 feedingit_0.1.0.orig.tar.gz
- 954096a5d2fa51bb359517d7578c684e4625f237 859 feedingit_0.1.0-1.debian.tar.gz
- 6edf2daadc2cc46ce0a0733ac666207db8ca12b7 165780 feedingit_0.1.0-1_all.deb
+ 4872f7d851392a4c31cf7c4e6fba426ef7bfecf9 753 feedingit_0.1.0-1.dsc
+ 0f46819e2084145776f49c7f7f2ee922a980687c 177736 feedingit_0.1.0.orig.tar.gz
+ bc99501e4cf014353f2f9d8807498a9d311337c7 931 feedingit_0.1.0-1.debian.tar.gz
+ d5f6a17d75b19f6ae48a94c3fc685eb55d2cedab 167012 feedingit_0.1.0-1_all.deb
 Checksums-Sha256: 
- 5b4b10db2bd978e8b26dbda2533912d30a484ce10427ead1667517896f0f4c6c 753 feedingit_0.1.0-1.dsc
- 8421abef41b572247ce1292445c075eec032136b121e9d3bc550897881ea975a 176240 feedingit_0.1.0.orig.tar.gz
- 229779d81f6541d46086a972ee2d93db66abd4a7adc8be746f5c97d585aa4044 859 feedingit_0.1.0-1.debian.tar.gz
- 9e5238dfd7dded6daa107482e4a205442c57042a39e273c740ae8328e65a08b7 165780 feedingit_0.1.0-1_all.deb
+ a39151af4220e3ee0b11e210f1d41b78968f4dfc874b949dd914688e99e97d7f 753 feedingit_0.1.0-1.dsc
+ 223c41eba6bad5241f54e54e776a6e3bb272d07d91b1fa380848b7d8ce0128f4 177736 feedingit_0.1.0.orig.tar.gz
+ 58f20d85f1cae2b33fb346fc6bee304cd304b6674026540aee31b73748d49a7c 931 feedingit_0.1.0-1.debian.tar.gz
+ ef85ba37ee11a4bcdae73fc629c3a0acfa2e023cc0502409f0c37b9045a10eb8 167012 feedingit_0.1.0-1_all.deb
 Files: 
- 87eb4279d8f3744a01cf5de3ee7f87fe 753 user/development optional feedingit_0.1.0-1.dsc
- c58fcc9048d74f69926cb53696c75c5e 176240 user/development optional feedingit_0.1.0.orig.tar.gz
- e143c5daf921dac855fb227f77646a0e 859 user/development optional feedingit_0.1.0-1.debian.tar.gz
- 308928231246478c11cd5078aba9b193 165780 user/development optional feedingit_0.1.0-1_all.deb
+ b885f4386ce99ea355ff17988744f887 753 user/development optional feedingit_0.1.0-1.dsc
+ 1b7ddb59ac327613cb42c0bbd7ffa06b 177736 user/development optional feedingit_0.1.0.orig.tar.gz
+ 9c4aba31f4ca66c7cb5fe5dbcd83d100 931 user/development optional feedingit_0.1.0-1.debian.tar.gz
+ 762bca546128e97766835cf81a2d7a5b 167012 user/development optional feedingit_0.1.0-1_all.deb
index a9857d9..6a367c0 100644 (file)
Binary files a/psa_harmattan/feedingit/deb_dist/feedingit_0.1.0.orig.tar.gz and b/psa_harmattan/feedingit/deb_dist/feedingit_0.1.0.orig.tar.gz differ
index 47e9f38..a606943 100644 (file)
@@ -1,4 +1,5 @@
-This file should contain a writeup describing what your application does,
-and how to use it. The content of this file goes into the long_description
-field of setup.py, which in turn becomes the long version of the Description
-field in the debian/control file of the project.
+FeedingIt is an easy to use RSS feed reader with portrait mode support and 
+automatic feed updates. You can swipe left and right to move between articles.
+Import and export of subscription lists is supported for OPML files.
+Images can be cached during the feed update, so you can view images in the
+downloaded articles while offline.
index 8acdb75..41167cb 100644 (file)
@@ -49,9 +49,11 @@ class XmlHandler():
     def generateCategoryXml(self):
         xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><xml>"
         for cat in self.listing.getListOfCategories():
+            print cat
             xml += "<category>"
             xml += "<catname>%s</catname>" %sanitize(self.listing.getCategoryTitle(cat))
             xml += "<catid>%s</catid>" % cat
+            xml += "<unread>%s</unread>" % self.listing.getCategoryUnread(cat)
             xml += "</category>"
         xml += "</xml>"
         return xml
index 209c021..10d08b9 100644 (file)
@@ -7,6 +7,7 @@ from PySide import QtDeclarative
 import os
 from os import mkdir, remove, stat, environ
 from os.path import isfile, isdir, exists
+import codecs
 
 # Comment the line below if you don't want to use OpenGL for QML rendering or if it is not supported
 from PySide import QtOpenGL,  QtCore
@@ -35,11 +36,11 @@ class Controller(QtCore.QObject):
     def getArticle(self, key, article):
        feed = listing.getFeed(key)
        try:
-          file = open(feed.getContentLink(article))
+          file = codecs.open(feed.getContentLink(article), "r", "utf-8")
           html = file.read().replace("body", "body bgcolor='#ffffff'", 1)
           file.close()
        except:
-          html = "<html><body>Error retrieving article</body></html>"
+          html = u"<html><body>Error retrieving article</body></html>"
        return html
     
     @QtCore.Slot(str, result=str)
@@ -67,9 +68,15 @@ class Controller(QtCore.QObject):
         
     @QtCore.Slot()
     def updateAll(self):
-        for feed in listing.getSortedListOfKeys("Manual"):
-            listing.updateFeed(feed)
-            
+        for catid in listing.getListOfCategories():
+            for feed in listing.getSortedListOfKeys("Manual", category=catid):
+                listing.updateFeed(feed)
+
+    @QtCore.Slot(str)
+    def updateCategory(self, catid):
+        for feed in listing.getSortedListOfKeys("Manual", category=catid):
+            listing.updateFeed(feed)           
+
     @QtCore.Slot(str,str,str)
     def addFeed(self, title, url, catid):
         listing.addFeed(title,url, category=catid)
@@ -79,6 +86,14 @@ class Controller(QtCore.QObject):
         listing.addCategory(name)
 
     @QtCore.Slot(str)
+    def removeFeed(self, key):
+        listing.removeFeed(key)
+
+    @QtCore.Slot(str)
+    def removeCategory(self, catid):
+        listing.removeCategory(catid)
+
+    @QtCore.Slot(str)
     def markAllAsRead(self, key):
         feed = listing.getFeed(key)
         feed.markAllAsRead()
index f90ffc3..68797cd 100644 (file)
@@ -809,7 +809,7 @@ class Feed(BaseObject):
         #text = '''<div style="color: black; background-color: white;">'''
         text = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
         text += "<html><head><title>" + title + "</title>"
-        text += '<meta http-equiv="Content-Type" content="text/html; charset="UTF-8"/>\n'
+        text += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>\n'
         #text += '<style> body {-webkit-user-select: none;} </style>'
         text += '</head><body bgcolor=\"#ffffff\"><div><a href=\"' + link + '\">' + title + "</a>"
         if author != None:
@@ -1211,6 +1211,15 @@ class Listing(BaseObject):
     
     def getCategoryTitle(self, id):
         return self.lookup('categories', 'title', id)
+
+    def getCategoryUnread(self, id):
+        count = 0
+        for key in self.getListOfFeeds(category=id):
+            try: 
+                count = count + self.getFeedNumberOfUnreadItems(key)
+            except:
+                pass
+        return count
     
     def getSortedListOfKeys(self, order, onlyUnread=False, category=1):
         if   order == "Most unread":
@@ -1286,6 +1295,7 @@ class Listing(BaseObject):
             id=1
         self.db.execute("INSERT INTO categories (id, title, unread, rank) VALUES (?, ?, 0, ?)", (id, title, rank))
         self.db.commit()
+        self.cache_invalidate('categories')
     
     def removeFeed(self, key):
         if wc().available ():
@@ -1301,6 +1311,7 @@ class Listing(BaseObject):
 
         if isdir(self.configdir+key+".d/"):
            rmtree(self.configdir+key+".d/")
+        self.cache_invalidate('feeds')
            
     def removeCategory(self, key):
         if self.db.execute("SELECT count(*) FROM categories;").fetchone()[0] > 1:
@@ -1309,6 +1320,7 @@ class Listing(BaseObject):
             self.db.execute("UPDATE categories SET rank=rank-1 WHERE rank>?;", (rank,) )
             self.db.execute("UPDATE feeds SET category=1 WHERE category=?;", (key,) )
             self.db.commit()
+            self.cache_invalidate('categories')
         
     #def saveConfig(self):
     #    self.listOfFeeds["feedingit-order"] = self.sortedKeys
index 6b25fd9..e089dac 100644 (file)
@@ -70,7 +70,7 @@ Page {
                 TextInputClear {
                     id: urlInput
                     placeHolder: "Feed URL"
-
+                    width: parent.width
                 }
 
                 Button {
@@ -81,16 +81,58 @@ Page {
                         //controller.addFeed("",urlInput.text,1);
                         categoryDialog.confirmCategory("", urlInput.text);
                     }
+                    width: 150
                 }
             }
 
-        } //searchTab
+        } //urlTab
+
+        Item {
+            id: categoryTab
+
+            Column {
+                Text {
+                    id: categoryText
+                    font.pixelSize: 22
+                    color: "white"
+                    text: "Enter the category name"
+                }
+
+                TextInputClear {
+                    id: categoryInput
+                    placeHolder: "name"
+                    width: parent.width
+                }
+
+                Button {
+                    id: categoryButton
+                    text: "Add"
+                    onClicked: {
+                        if (categoryInput.text != "") {
+                            controller.addCategory(categoryInput.text)
+                            categoryDialog.reload()
+                            window.categoryReloadRequest()
+                        }
+                    }
+                    width: 150
+                }
+            }
+
+        } //categoryTab
 
         ToolBarLayout {
             id: tabTools
             ToolIcon {
                 iconId: "toolbar-back"
-                onClicked: tabGroup.currentTab.depth > 1 ? tabGroup.currentTab.pop() : pageStack.pop()
+                onClicked: {
+                    if (tabGroup.currentTab.depth > 1) {
+                        tabGroup.currentTab.pop()
+                    } else {
+                        pageStack.pop()
+                    }
+                    window.feedReloadRequest()
+                    window.categoryReloadRequest()
+                }
             }
             ButtonRow {
                 TabButton {
@@ -101,7 +143,12 @@ Page {
                     text: "URL"
                     tab: urlTab
                 }
+                TabButton {
+                    text: "Categories"
+                    tab: categoryTab
+                }
             }
+
         }
     }
 
@@ -130,6 +177,11 @@ Page {
                  open();
              }
 
+             function reload() {
+                 //categories.reload()
+                 categories.xml = controller.getCategoryXml()
+             }
+
              //model: []
              //model: categories
 
index 83898b4..ac31e0b 100644 (file)
@@ -108,16 +108,24 @@ Item {
             id: listing;
 
             Item {
-                width: articleViewer.width; height: 86
+                width: articleViewer.width; height: backRect.height + 3
                 id: listItem
-                Rectangle { id: backRect; color: "#dddddd"; opacity: index % 2 ? 0.2 : 0.4; height: 84; width: listItem.width; y: 1 }
+                Rectangle {
+                    id: backRect; color: settings.backColour; opacity: index % 2 ? 0.2 : 0.4;
+                    height: articleText.height + 22; width: listItem.width;
+                    y: 1
+                }
                 Text {
-                    anchors.fill: backRect
+                    id: articleText
+                    anchors.verticalCenter: backRect.verticalCenter
+                    x: 3
+                    width: listItem.width - 6;
+
                     anchors.margins: 5
                     verticalAlignment: Text.AlignVCenter; text: title;
-                    color: (unread=="True") ? "white" : "#7b97fd";
+                    color: (unread=="True") ? settings.mainTextColour : settings.secondaryTextColour;
 
-                    width: listItem.width; wrapMode: Text.WordWrap; font.bold: false;
+                     wrapMode: Text.WordWrap; font.bold: false;
                     font.pointSize: 18
                 }
                 MouseArea { anchors.fill: listItem;
index 5a97370..4469ba1 100644 (file)
@@ -8,7 +8,9 @@ Item {
     signal categoryClicked(string cat)
 
     function reload() {
-        categories.reload();
+        //categories.reload();
+        categories.xml = controller.getCategoryXml()
+        //console.log(controller.getCategoryXml())
     }
 
     ListView {
@@ -25,6 +27,7 @@ Item {
 
         XmlRole { name: "title"; query: "catname/string()" }
         XmlRole { name: "catid"; query: "catid/string()"; isKey: true }
+        XmlRole { name: "unread"; query: "unread/string()" }
     }
 
     Component {
@@ -36,46 +39,68 @@ Item {
             Item {
                 id: moveMe
                 height: parent.height
-                Rectangle { color: "#eeeeee"; opacity: index % 2 ? 0.2 : 0.4; height: 84; width: wrapper.width; y: 1 }
+                Rectangle { color: settings.backColour; 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: 15;
-                    width: wrapper.ListView.view.width /*- 95; y: 15*/; spacing: 2
+                    width: wrapper.ListView.view.width /*- 95;*/
+                    y: 15; spacing: 2
                     anchors.margins: 5
                     height: parent.height
 
-                    Text { text: title; color: "white"; width: parent.width; font.bold: true;
-                        height: parent.height
-                        elide: Text.ElideRight; style: Text.Raised; styleColor: "black"; font.pointSize: 20
+                    Text { text: title; color: settings.mainTextColour; width: parent.width; font.bold: true;
+                        //height: parent.height
+                        elide: Text.ElideRight; style: Text.Raised;
+                        styleColor: settings.mainShadowColour;
+                        font.pointSize: settings.mainTextSize
                         verticalAlignment: Text.AlignVCenter;
                     }
+                    Text {
+                        text: qsTr("%1 unread items").arg(unread);
+                        color: (unread=="0") ? settings.mainTextColour : settings.secondaryTextColour;
+                        width: parent.width; font.bold: false;
+                        elide: Text.ElideRight;
+                        //style: Text.Raised; styleColor: settings.mainShadowColour;
+                        font.pointSize: settings.secondaryTextSize
+                    }
                     //Text { text: feedname; width: parent.width; elide: Text.ElideLeft; color: "#cccccc"; style: Text.Raised; styleColor: "black" }
                 }
-                Item {
-                    x: wrapper.ListView.view.width - 128; y: 12
-                    height: 58; width: 58;
-                    //anchors.horizontalCenter: parent.horizontalCenter;
-                    Image { source: "common/images/wmEditIcon.png" }
-                    MouseArea {
-                        anchors.fill: parent; onClicked: { container.categoryEdit(catname, catid); }
-                    }
-                    visible: inEditMode
+//                Item {
+//                    x: wrapper.ListView.view.width - 128; y: 12
+//                    height: 58; width: 58;
+//                    //anchors.horizontalCenter: parent.horizontalCenter;
+//                    Image { source: "common/images/wmEditIcon.png" }
+//                    MouseArea {
+//                        anchors.fill: parent; onClicked: { container.categoryEdit(catname, catid); }
+//                    }
+//                    visible: inEditMode
+//                }
+//                Item {
+//                    x: wrapper.ListView.view.width - 64; y: 12
+//                    height: 58; width: 58;
+//                    //anchors.horizontalCenter: parent.horizontalCenter;
+//                    Image { source: "common/images/delete.png" }
+//                    MouseArea {
+//                        anchors.fill: parent; onClicked: { container.categoryDeleted(catid); }
+//                    }
+//                    visible: inEditMode
+//                }
+            }
+            MouseArea {
+                enabled: !inEditMode; anchors.fill: wrapper;
+                onClicked: { categoryClicked(catid); }
+                onPressAndHold: {
+                    window.longPressCategory(catid)
                 }
-                Item {
-                    x: wrapper.ListView.view.width - 64; y: 12
-                    height: 58; width: 58;
-                    //anchors.horizontalCenter: parent.horizontalCenter;
-                    Image { source: "common/images/delete.png" }
-                    MouseArea {
-                        anchors.fill: parent; onClicked: { container.categoryDeleted(catid); }
-                    }
-                    visible: inEditMode
+            }
+            Component.onCompleted: {
+                if (categories.count == 1) {
+                    categoryClicked(catid)
                 }
             }
-            MouseArea { enabled: !inEditMode; anchors.fill: wrapper; onClicked: { categoryClicked(catid); } }
         }
     }
 }
index 32b5919..5131cbc 100644 (file)
@@ -56,21 +56,34 @@ Item {
 
             Item {
                 id: moveMe
-                Rectangle { color: "#dddddd"; opacity: index % 2 ? 0.2 : 0.4; height: 84; width: wrapper.width; y: 1 }
+                Rectangle { color: settings.backColour; 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: (updating=="True")? "common/images/loading.png" : (icon == "False") ? "common/images/feedingit.png" : icon;
-                        NumberAnimation on rotation {
-                            from: 0; to: 360; running: (updating=="True"); loops: Animation.Infinite; duration: 900
-                        }
+                    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") ? "common/images/feedingit.png" : icon
+                            // (updating=="True")? "common/images/loading.png" : (icon == "False") ? "common/images/feedingit.png" : icon;
+//                        NumberAnimation on rotation {
+//                            from: 0; to: 360; running: (updating=="True"); loops: Animation.Infinite; duration: 900
+//                        }
                     }
                 }
 
                 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"; font.pointSize: 18 }
-                    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"; font.pointSize: 12 }
+                    Text { text: title; color: settings.mainTextColour;
+                        width: parent.width;
+                        font.bold: true; elide: Text.ElideRight; style: Text.Raised; styleColor: settings.mainShadowColour;
+                        font.pointSize: settings.mainTextSize
+                    }
+                    Text {
+                        text: updatedDate + " / " + qsTr("%1 unread items").arg(unread);
+                        color: (unread=="0") ? settings.mainTextColour : settings.secondaryTextColour;
+                        width: parent.width; font.bold: false; elide: Text.ElideRight;
+                        //style: Text.Raised; styleColor: settings.mainShadowColour;
+                        font.pointSize: settings.secondaryTextSize
+                    }
                     //Text { text: feedname; width: parent.width; elide: Text.ElideLeft; color: "#cccccc"; style: Text.Raised; styleColor: "black" }
                 }
 ////                Item {
@@ -101,6 +114,9 @@ Item {
                     feedClicked(feedid)
                     
                 }
+                onPressAndHold: {
+                    window.longPressFeed(feedid)
+                }
             }
 
         }
diff --git a/psa_harmattan/feedingit/qml/Settings.qml b/psa_harmattan/feedingit/qml/Settings.qml
new file mode 100644 (file)
index 0000000..e6d7362
--- /dev/null
@@ -0,0 +1,10 @@
+import Qt 4.7
+Item {
+    property string mainTextColour: theme.inverted ? "white" : "black"
+    property string mainShadowColour: theme.inverted ? "black" : "white"
+    property int mainTextSize: 18
+    property string secondaryTextColour: theme.inverted?  "#7b97fd" : "#5c71bd"
+    property int secondaryTextSize: 14
+
+    property string backColour: theme.inverted? "#dddddd" : "#222222"
+}
index e38c12a..577bb7b 100644 (file)
@@ -6,12 +6,25 @@ PageStackWindow {
     id: window
     initialPage: categoryPage
 
-    signal articleClosed()
+    signal longPressCategory(string catid)
+    signal longPressFeed(string key)
+    signal categoryReloadRequest()
+    signal feedReloadRequest()
     property string feedid
     property string catid
 
     Component.onCompleted: theme.inverted= true
 
+    onLongPressFeed: {
+        unsubscribeFeedMenu.key = key
+        unsubscribeFeedMenu.open()
+    }
+
+    onLongPressCategory: {
+        unsubscribeCategoryMenu.catid = catid
+        unsubscribeCategoryMenu.open()
+    }
+
     ToolBarLayout {
         id: commonTools
         visible: false
@@ -29,6 +42,7 @@ PageStackWindow {
         visualParent: pageStack
         MenuLayout {
             MenuItem { text: qsTr("Settings"); onClicked: {}  }
+            MenuItem { text: qsTr("Invert Theme"); onClicked: { theme.inverted = !theme.inverted }  }
             MenuItem { text: qsTr("Add Feeds"); onClicked: { pageStack.push(addFeedPage)  } }
             MenuItem { text: qsTr("Update All Categories"); onClicked: controller.updateAll(); }
             MenuItem { text: qsTr("About FeedingIt"); onClicked: query.open(); }
@@ -39,8 +53,8 @@ PageStackWindow {
         id: myFeedsMenu
         visualParent: pageStack
         MenuLayout {
-            MenuItem { text: qsTr("Update All Feeds"); onClicked: controller.updateAll(); }
-            MenuItem { text: qsTr("About FeedingIt"); onClicked: query.open(); }
+            MenuItem { text: qsTr("Update All Feeds"); onClicked: controller.updateCategory(catid); }
+            //MenuItem { text: qsTr("About FeedingIt"); onClicked: query.open(); }
         }
     }
 
@@ -50,7 +64,61 @@ PageStackWindow {
         MenuLayout {
             MenuItem { text: qsTr("Mark All As Read"); onClicked: controller.markAllAsRead(feedid); }
             MenuItem { text: qsTr("Update Feed"); onClicked: controller.updateFeed(feedid); }
-            MenuItem { text: qsTr("About FeedingIt"); onClicked: query.open(); }
+            //MenuItem { text: qsTr("About FeedingIt"); onClicked: query.open(); }
+        }
+    }
+
+    Menu {
+        id: unsubscribeFeedMenu
+        visualParent: pageStack
+        property string key
+        MenuLayout {
+            //MenuItem { text: qsTr("Update"); onClicked: controller.updateFeed(parent.feedid); }
+            MenuItem { text: qsTr("Delete");
+                onClicked: {
+                    feedConfirm.open()
+                    unsubscribeFeedMenu.close()
+                }
+            }
+        }
+        QueryDialog {
+            id: feedConfirm
+            //icon: "common/images/feedingit.png"
+            //titleText: "Delete Feed?"
+            message: "Delete this feed?"
+            acceptButtonText: "OK"
+            rejectButtonText: "Cancel"
+            onAccepted: {
+                controller.removeFeed(unsubscribeFeedMenu.key);
+                window.feedReloadRequest()
+            }
+        }
+    }
+
+    Menu {
+        id: unsubscribeCategoryMenu
+        visualParent: pageStack
+        property string catid
+        MenuLayout {
+            //MenuItem { text: qsTr("Update"); onClicked: controller.updateFeed(parent.feedid); }
+            MenuItem { text: qsTr("Delete");
+                onClicked: {
+                    categoryConfirm.open()
+                    unsubscribeFeedMenu.close()
+                }
+            }
+        }
+        QueryDialog {
+            id: categoryConfirm
+            //icon: "common/images/feedingit.png"
+            //titleText: "Delete Feed?"
+            message: "Delete this category?"
+            acceptButtonText: "OK"
+            rejectButtonText: "Cancel"
+            onAccepted: {
+                controller.removeCategory(unsubscribeCategoryMenu.catid);
+                window.categoryReloadRequest()
+            }
         }
     }
 
@@ -65,23 +133,24 @@ PageStackWindow {
         acceptButtonText: "OK"
     }
 
-//    Page{
-//        id: mainPage
-//        Component.onCompleted: {
-//            var main = Qt.createComponent("FeedingIt.qml");
-//            main.createObject(mainPage);
-//        }
-//    }
-
     Component {
         id: categoryPage
         Page {
             tools: commonTools
             Categories {
+                id: categoriesItem
                 onCategoryClicked: {
                     window.catid = cat
                     pageStack.push(feedsPage)
                 }
+
+            }
+            Connections {
+                target: window
+                onCategoryReloadRequest: {
+                    console.log("category reloaded")
+                    categoriesItem.reload()
+                }
             }
         }
     }
@@ -99,6 +168,7 @@ PageStackWindow {
                     window.feedid = feedid
                     pageStack.push(articlesPage)
                 }
+
             }
             ToolBarLayout {
                 id: feedsTools
@@ -106,6 +176,7 @@ PageStackWindow {
                 ToolIcon { iconId: "toolbar-back";
                     onClicked: {
                         myArticlesMenu.close();
+                        window.categoryReloadRequest()
                         pageStack.pop();
                     }
                 }
@@ -117,7 +188,7 @@ PageStackWindow {
             }
             Connections {
                  target: window
-                 onArticleClosed: feedsItem.reload()
+                 onFeedReloadRequest: feedsItem.reload()
              }
         }
     }
@@ -141,7 +212,7 @@ PageStackWindow {
                             flipper.articleShown = false;
                             flipper.reload()
                         } else {
-                            window.articleClosed();
+                            window.feedReloadRequest();
                             pageStack.pop();
                         }
                     }
@@ -174,4 +245,8 @@ PageStackWindow {
         id: addFeedPage
         AddFeed {}
     }
+
+    Settings {
+        id: settings
+    }
 }
index d243933..129f500 100644 (file)
@@ -803,7 +803,7 @@ class Feed(BaseObject):
         #text = '''<div style="color: black; background-color: white;">'''
         text = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
         text += "<html><head><title>" + title + "</title>"
-        text += '<meta http-equiv="Content-Type" content="text/html; charset="UTF-8"/>\n'
+        text += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>\n'
         #text += '<style> body {-webkit-user-select: none;} </style>'
         text += '</head><body bgcolor=\"#ffffff\"><div><a href=\"' + link + '\">' + title + "</a>"
         if author != None: