There is now a basic infrastructure for building settings dialogs.
--- /dev/null
+//SettingsStorage.js
+.pragma library
+
+// First, let's create a short helper function to get the database connection
+function getDatabase() {
+ return openDatabaseSync("QuickNewsReader", "1.0", "SettingsStorageDatabase", 100000);
+}
+
+// At the start of the application, we can initialize the tables we need if they haven't been created yet
+function initialize() {
+ var db = getDatabase();
+ db.transaction(
+ function(tx) {
+ // Create the settings table if it doesn't already exist
+ // If the table exists, this is skipped
+ tx.executeSql('CREATE TABLE IF NOT EXISTS settings(setting TEXT UNIQUE, value TEXT)');
+ });
+}
+
+// This function is used to write a setting into the database
+function setSetting(setting, value) {
+ // setting: string representing the setting name (eg: “username”)
+ // value: string representing the value of the setting (eg: “myUsername”)
+ var db = getDatabase();
+ var res = "";
+ db.transaction(function(tx) {
+ var rs = tx.executeSql('INSERT OR REPLACE INTO settings VALUES (?,?);', [setting,value]);
+ //console.log(rs.rowsAffected)
+ if (rs.rowsAffected > 0) {
+ res = "OK";
+ } else {
+ res = "Error";
+ }
+ }
+ );
+ // The function returns “OK” if it was successful, or “Error” if it wasn't
+ return res;
+}
+
+// This function is used to retrieve a setting from the database
+function getSetting(setting) {
+ var db = getDatabase();
+ var res="";
+ db.transaction(function(tx) {
+ var rs = tx.executeSql('SELECT value FROM settings WHERE setting=?;', [setting]);
+ if (rs.rows.length > 0) {
+ res = rs.rows.item(0).value;
+ } else {
+ res = "Unknown";
+ }
+ })
+ // The function returns “Unknown” if the setting was not found in the database
+ // For more advanced projects, this should probably be handled through error codes
+ return res
+}
+
}
loading: newsModel.loading
+ hasSettings: true
+ settingsComponent: "FavoriteRssConfig.qml"
}
XmlRole { name: "link"; query: "lien_web/string()" }
XmlRole { name: "description"; query: "description_appel/string()" }
XmlRole { name: "detailedContent"; query: "contenu/string()" }
+ XmlRole { name: "commentURL"; query: "commentaires/url_commentaires/string()" }
}
listViews: [
{ viewComponent: 'content/view/Categories.qml', viewId: 'categoriesRect' } ,
{ viewComponent: 'content/view/News.qml', viewId: 'newsRect' },
- { viewComponent: 'content/view/NewsDetail.qml', viewId: 'newsDetailRect' }
+ { viewComponent: 'content/view/NewsDetail.qml', viewId: 'newsDetailRect' },
+ { viewComponent: 'content/view/NewsComments.qml', viewId: 'newsCommentsRect' }
]
listModels: [
categoriesModel,
newsModel,
- newsModel
+ newsModelDetail,
+ newsModelDetailComments
]
function getSeqId(categoryIndex)
return ""
}
+ function getNewsModelItem(prop)
+ {
+ var newsIndex = currentPath[2]
+
+ if( typeof newsModel.get(newsIndex) != "undefined" )
+ if( typeof newsModel.get(newsIndex)[prop] != "undefined" )
+ return newsModel.get(newsIndex)[prop]
+
+ return ""
+ }
+
property variant categoriesModel: LeMondeSequencesList { }
property variant newsModel: LeMondeSequenceNews {
seqid: getSeqId(currentPath[1])
}
+ property variant newsModelDetail: QtObject {
+ property variant parentModel: newsModel
+ property int sourceDepth: 3
+
+ property string urllink: getNewsModelItem('link')
+ property string htmlcontent: getNewsModelItem('detailedContent')
+ property string title: getNewsModelItem('title')
+ property string image: getNewsModelItem('image')
+ }
+ property variant newsModelDetailComments: QtObject {
+ property variant parentModel: newsModel
+ property int sourceDepth: 4
+
+ property string commentURL: "http://www.lemonde.fr" + getNewsModelItem('commentURL')
+ property string title: getNewsModelItem('title')
+ property string image: getNewsModelItem('image')
+ }
loading: categoriesModel.loading || newsModel.loading
}
property string name: "Source"
property bool loading
+ property bool hasSettings: false
+ property string settingsComponent
property variant listViews;
property variant listModels;
x: 0; y: 0
width: 220; height: window.height
model: currentSource.listModels[componentDepth-1]
- footer: quitButtonDelegate
+ footer: getFooter()
delegate: CategoryDelegate { }
highlight: Rectangle { color: "steelblue" }
highlightMoveSpeed: 9999999
+
+ function getFooter()
+ {
+ return componentDepth === 1 && currentSource.hasSettings ? settingsButtonDelegate : null
+ }
}
ScrollBar { scrollArea: categories; height: categories.height; width: 8; anchors.right: categories.right }
Component.onCompleted: categories.currentIndex = -1
+
+ Component {
+ id: settingsButtonDelegate
+ Item {
+ width: categories.width; height: 70
+
+ FancyButton {
+ icon: "../images/settings.png"
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: -2
+
+ /*
+ onClicked: {
+ if (editMenu.visible) {
+ editMenu.opacity = 0.0
+ } else {
+ editMenu.opacity = 0.8
+ }
+ }*/
+ }
+ }
+ }
}
--- /dev/null
+/* This file is part of MeeGoFrames Component Library
+ * Copyright (C) 2011 Martin Grimme <martin.grimme _AT_ gmail.com>
+ *
+ * This program is free software; you can redistribute it, even commercially,
+ * as long as this copyright notice remains in place.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+import Qt 4.7
+
+Rectangle {
+
+ property alias icon: imageLabel.source
+
+ signal clicked()
+
+ id: button
+ width: 70
+ height: 70
+
+ radius: 3
+ color: "#a0000000"
+
+
+ states: [
+ State {
+ name: "pressed"
+ when: mouseArea.pressed
+ PropertyChanges {
+ target: button
+ color: "#606060"
+ scale: 0.9
+ }
+ }
+ ]
+
+ Behavior on color {
+ ColorAnimation { duration: 100 }
+ }
+
+ Behavior on scale {
+ NumberAnimation { duration: 100 }
+ }
+
+ Image {
+ anchors.centerIn: parent
+ id: imageLabel
+ visible: source != ""
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ onClicked: parent.clicked()
+ }
+}
--- /dev/null
+import QtQuick 1.0
+
+Rectangle {
+ width: 100
+ height: 62
+
+ color: "blue"
+}
width: newsRect.width; height: window.height
model: currentSource.listModels[componentDepth-1]
delegate: NewsDelegate { }
+ highlight: Rectangle { color: "steelblue" }
}
ScrollBar { scrollArea: list; height: list.height; width: 8; anchors.right: list.right }
+
+ Component.onCompleted: list.currentIndex = -1
}
--- /dev/null
+import QtQuick 1.0
+import QtWebKit 1.0
+
+Item {
+ id: newsCommentsRect
+ width: window.width; height: window.height
+
+ function getNewsModelItem(prop)
+ {
+ if( typeof currentSource.listModels[componentDepth-1] != "undefined" )
+ if( typeof currentSource.listModels[componentDepth-1][prop] != "undefined" )
+ return currentSource.listModels[componentDepth-1][prop]
+
+ return ""
+ }
+
+ property string commentURL: getNewsModelItem('commentURL')
+ property string title: getNewsModelItem('title')
+ property string image: getNewsModelItem('image')
+
+ VisualItemModel {
+ id: itemModel
+
+ Column {
+ id: column
+ x: 0; y: 0
+ width: newsCommentsRect.width
+// height: newsCommentsRect.height
+
+ Row {
+ id: titleRow
+ spacing: 5
+
+ Image {
+ id: detailImage
+ source: image
+ }
+
+ Text {
+ anchors.verticalCenter: detailImage.verticalCenter
+ text: title; width: column.width - detailImage.width - 10; wrapMode: Text.WordWrap
+ font { bold: true; family: "Helvetica"; pointSize: 16 }
+ }
+ }
+
+ WebView {
+ id: newsCommentsWebView
+ width: newsCommentsRect.width
+ url: commentURL
+ preferredWidth: window.width
+// preferredHeight: parent.height - titleRow.height
+ }
+ }
+ }
+ ListView {
+ id: itemListView
+ anchors.fill: newsCommentsRect
+ model: itemModel
+ }
+ ScrollBar { scrollArea: itemListView; height: itemListView.height; width: 8; anchors.right: itemListView.right }
+}
}
Text {
+ anchors.verticalCenter: detailImage.verticalCenter
text: description; width: column.width - detailImage.width - 10; wrapMode: Text.WordWrap
font.family: "Helvetica"
}
MouseArea {
anchors.fill: delegate
- onDoubleClicked: {
+ onClicked: {
if (typeof detailedContent != "undefined") {
var currentSourceDepth = delegate.ListView.view.model.sourceDepth
function getNewsModelItem(prop)
{
- var newsIndex = listSourceModel[window.currentSourceIndex].currentPath[componentDepth-1]
-
if( typeof currentSource.listModels[componentDepth-1] != "undefined" )
- if( typeof currentSource.listModels[componentDepth-1].get(newsIndex) != "undefined" )
- if( typeof currentSource.listModels[componentDepth-1].get(newsIndex)[prop] != "undefined" )
- return currentSource.listModels[componentDepth-1].get(newsIndex)[prop]
+ if( typeof currentSource.listModels[componentDepth-1][prop] != "undefined" )
+ return currentSource.listModels[componentDepth-1][prop]
return ""
}
- property string urllink: getNewsModelItem('link')
- property string htmlcontent: getNewsModelItem('detailedContent')
+ property string urllink: getNewsModelItem('urllink')
+ property string htmlcontent: getNewsModelItem('htmlcontent')
property string title: getNewsModelItem('title')
property string image: getNewsModelItem('image')
VisualItemModel {
id: itemModel
- Column {
- id: column
- x: 10; y: 10
- width: newsDetailRect.width - 20
+ Item {
+ x: 0; y: 0
+ width: newsDetailRect.width
+ height: column.height
+
+ Column {
+ id: column
+ x: 0; y: 0
+ width: parent.width - 20
+
+ Row {
+ spacing: 5
- Row {
- spacing: 5
+ Image {
+ id: detailImage
+ source: image
+ }
- Image {
- id: detailImage
- source: image
+ Text {
+ anchors.verticalCenter: detailImage.verticalCenter
+ text: title; width: column.width - detailImage.width - 10; wrapMode: Text.WordWrap
+ font { bold: true; family: "Helvetica"; pointSize: 16 }
+ }
}
Text {
- text: title; width: column.width - detailImage.width - 10; wrapMode: Text.WordWrap
- font { bold: true; family: "Helvetica"; pointSize: 16 }
+ id: detailText
+ text: htmlcontent; width: newsDetailRect.width - 20; wrapMode: Text.WordWrap
+ font.family: "Helvetica"
}
}
- Text {
- id: detailText
- text: htmlcontent; width: newsDetailRect.width - 20; wrapMode: Text.WordWrap
- font.family: "Helvetica"
+ MouseArea {
+ anchors.fill: column
+
+ onClicked: {
+ var currentSourceDepth = currentSource.listModels[componentDepth-1].sourceDepth
+
+ // here we remove everything in viewsModel after index "currentSourceDepth"
+ while(window.windowViewsModel.count>currentSourceDepth+1)
+ window.windowViewsModel.remove(window.windowViewsModel.count-1)
+
+ var path = listSourceModel[window.currentSourceIndex].currentPath
+ path[currentSourceDepth] = index
+ listSourceModel[window.currentSourceIndex].currentPath = path
+
+ window.windowViewsModel.append({ component: listSourceModel[window.currentSourceIndex].listViews[currentSourceDepth].viewComponent,
+ componentId: listSourceModel[window.currentSourceIndex].listViews[currentSourceDepth].viewId,
+ componentDepth: currentSourceDepth+1 })
+
+ window.windowViewsList.currentIndex = currentSourceDepth+1;
+ }
}
}
}
model: itemModel
}
ScrollBar { scrollArea: itemListView; height: itemListView.height; width: 8; anchors.right: itemListView.right }
-/*
- WebView {
- id: newsDetailWebView
- anchors.fill: parent
- html: htmlcontent
- url: urllink
- preferredWidth: window.width
- preferredHeight: window.height
- }
-*/
}
--- /dev/null
+import QtQuick 1.0
+import "../modelitf"
+
+Rectangle {
+ id: configDialog
+ anchors.fill: parent
+ color: "#00000000"
+ visible: false
+ state: "hidden"
+
+ property string configViewComponent
+
+ //property SourceModel model;
+ //property SourceConfigComponentView viewComponent;
+
+ states: [
+ State {
+ name: "showSourceConfig"
+
+ // In this state, we bring the configuration UI of the source
+ PropertyChanges { target: configDialog; color: "#d0000000" }
+ PropertyChanges { target: sourceConfigLoader; opacity: 1 }
+ PropertyChanges { target: sourceConfigLoader; source: configViewComponent }
+
+ AnchorChanges { target: quitApplyConfigButton; anchors.left: undefined; anchors.right: configDialog.right }
+ AnchorChanges { target: quitCancelConfigButton; anchors.right: undefined; anchors.left: configDialog.left }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ from: "hidden"
+ to: "showSourceConfig"
+
+ SequentialAnimation {
+ // Show the dialog
+ PropertyAction { target: configDialog; property: "visible"; value: true }
+ // Bring the UI elements
+ ParallelAnimation {
+ AnchorAnimation { duration: 500 }
+ ColorAnimation { duration: 400 }
+ }
+ }
+ },
+ Transition {
+ from: "showSourceConfig"
+ to: "hidden"
+
+ SequentialAnimation {
+ // Move out the UI elements
+ ParallelAnimation {
+ AnchorAnimation { duration: 500 }
+ ColorAnimation { duration: 400 }
+ }
+ // Hide the dialog
+ PropertyAction { target: configDialog; property: "visible"; value: false }
+ }
+ }
+ ]
+
+ Loader {
+ id: sourceConfigLoader
+ opacity: 0
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: quitApplyConfigButton.top
+
+ Behavior on opacity {
+ NumberAnimation { duration: 1000; easing.type: Easing.InOutQuad }
+ }
+ }
+
+ FancyButton {
+ id: quitApplyConfigButton
+ icon: "../images/apply.png"
+ anchors.bottom: parent.bottom
+ anchors.left: parent.right
+
+ onClicked: {
+ // Store the configuration of this source, and disappear
+ configDialog.state = "hidden"
+ }
+ }
+
+ FancyButton {
+ id: quitCancelConfigButton
+ icon: "../images/cancel.png"
+ anchors.bottom: parent.bottom
+ anchors.right: parent.left
+
+ onClicked: {
+ // Store the configuration of this source, and disappear
+ configDialog.state = "hidden"
+ }
+ }
+
+}
MouseArea {
anchors.fill: delegate
+
+ onPressAndHold: {
+ // show the configuration for this journal
+ if( listSourceModel[index].hasSettings )
+ {
+ window.showConfigDialog(listSourceModel[index].settingsComponent)
+ }
+ }
+
onClicked: {
if( delegate.ListView.view.currentIndex !== index )
{
componentId: listSourceModel[index].listViews[0].viewId,
componentDepth: 1 })
- listSourceModel[window.currentSourceIndex].currentPath = [index]
+ listSourceModel[index].currentPath = [index]
window.currentSourceIndex = index
}
}
+ function showConfigDialog(settingsComponent) {
+ configDialog.configViewComponent = settingsComponent
+ configDialog.state = "showSourceConfig"
+ }
+
+ SourceConfigDialog {
+ id:configDialog
+ }
+
+/*
+*/
+
Component {
id: quitButtonDelegate
Item {
Source: quicknewsreader
-Section: web
+Section: user/network
Version: 0.2-0
Priority: optional
Maintainer: Christophe CHAPUIS <chris@unknown>