deb094ece81a263baddfa4c5db991d848a381a49
[marketstoday] / src / qml / MarketsTodayApp.qml
1 /*
2 @version: 0.2
3 @author: Sudheer K. <scifi1947 at gmail.com>
4 @license: GNU General Public License
5 */
6
7 import QtQuick 1.1
8 import com.nokia.meego 1.0
9
10 import "Library" as Library
11 import "Library/js/ISODate.js" as DateLib
12 import "Library/js/DBUtility.js" as DBUtility
13 import "Library/js/Common.js" as Common
14 import "Library/js/CoreLogic.js" as CoreLib
15
16 PageStackWindow {
17     id: appWindow
18     initialPage: mainPage
19     showToolBar: false
20     showStatusBar: false
21
22     property int autoUpdateInterval: 300000
23     property bool updateWeekDaysOnly: false
24     property bool updateOnSavedNetworksOnly: false
25     property string rssURL: "http://finance.yahoo.com/rss/topfinstories"
26     property string lastUpdatedTimeStamp
27     property bool isDesktopWidget
28     //property string selectedSymbol:"YHOO"
29     property string selectedSymbol:sharedContext.getStockSymbol()
30
31     signal showConfigInNewWindow
32     signal showStockDetails(string strSymbol)
33     signal quoteRefreshStarted
34     signal quoteRefreshCompleted(bool success, string strMessage)
35     signal newsReloadCompleted(bool success, string strMessage)
36     signal checkNetworkStatus
37
38     function initialize(){
39         mainPage.initializePage();
40     }
41
42     Page {
43         id: mainPage
44
45         property int itemHeight: 50
46         property int titleBarHeight: 60
47         property int toolBarHeight: 40
48         property int componentWidth: mainPage.width
49
50         function reloadData(){
51             CoreLib.reloadQuotes();
52             CoreLib.reloadNews();
53         }
54
55         function initializePage(){
56             var componentToDisplay = sharedContext.getComponentToDisplay();
57             if (componentToDisplay === "StockQuoteDetails"){
58                 uiLoader.sourceComponent = stockDetailsComponent;
59                 titleBar.buttonType = "Close";
60                 titleBar.displayMenu = false;
61                 toolBar.displayIcons = false;
62             }
63             else{
64                 DBUtility.initialize();
65                 uiLoader.sourceComponent = stockQuotesUIComponent;
66                 CoreLib.initialize();
67             }
68         }
69
70         Component.onCompleted: {
71             initializePage();
72         }
73
74         Timer {
75             id: autoUpdateTimer
76             interval: autoUpdateInterval
77             //running: (autoUpdateInterval == 0? false:true)
78             repeat: true
79             onTriggered: {
80                 if (!updateWeekDaysOnly){
81                     logUtility.logMessage("Allowed to update all days of the week");
82                     mainPage.reloadData();
83                     //checkNetworkStatus();
84                 }
85                 else if (Common.isTodayAWeekDay()){
86                     logUtility.logMessage("Today is a weekday");
87                     mainPage.reloadData();
88                     //checkNetworkStatus();
89                 }
90                 else{
91                     logUtility.logMessage("Update not triggered: Today is not a weekday");
92                 }
93             }
94         }
95
96         ListModel{
97             id: stockQuoteDataModel
98         }
99
100         ListModel {
101             id: newsDataModel
102         }
103
104         Rectangle {
105             id: background
106             anchors.fill: parent;
107             color: "#343434"
108             clip: true
109
110             Component {
111                 id: stockQuotesDelegateLandscape
112
113                 Item {
114                     id: wrapper; width: mainPage.componentWidth; height: mainPage.itemHeight
115                     Item {
116                         Rectangle { color: "black"; opacity: index % 2 ? 0.2 : 0.4; height: wrapper.height - 2; width: wrapper.width; y: 1
117                             MouseArea {
118                                 anchors.fill: parent
119                                 onDoubleClicked: {
120                                     appWindow.selectedSymbol = symbol;
121                                     uiLoader.sourceComponent = stockDetailsComponent;
122                                     titleBar.buttonType = "Back";
123                                     titleBar.displayMenu = false;
124                                     toolBar.displayIcons = false;
125                                 }
126                             }
127                         }
128
129                         Row {
130                             x: 30;y: 15;
131                             width: mainPage.componentWidth - 60;
132                             spacing: 5
133
134                             Text { text: stockName; width: parent.width * 30/100; font.pixelSize: 18; font.bold: true; elide: Text.ElideRight; color: "white"; style: Text.Raised; styleColor: "black" }
135                             Text { text: lastTradedPrice; width: parent.width * 15/100; font.pixelSize: 18; horizontalAlignment: Text.AlignLeft; elide: Text.ElideLeft; color: "#cccccc"; style: Text.Raised; styleColor: "black" }
136                             Text { text: change !== ""? (change + " ("+changePercentage+")"):""; width: parent.width * 25/100;  font.pixelSize: 18; horizontalAlignment: Text.AlignLeft; elide: Text.ElideRight
137                                     color: if(change >= 0){"green";} else {"red";}
138                                         style: Text.Raised; styleColor: "black" }
139                             Text { text: volume; width: parent.width * 15/100; font.pixelSize: 18; horizontalAlignment: Text.AlignLeft; elide: Text.ElideLeft; color: "#cccccc"; style: Text.Raised; styleColor: "black" }
140                             Text { text: marketCap; width: parent.width * 15/100; font.pixelSize: 18; horizontalAlignment: Text.AlignLeft; elide: Text.ElideLeft; color: "#cccccc"; style: Text.Raised; styleColor: "black" }
141                         }
142                     }
143                 }
144             }
145
146             Component {
147                 id: stockQuotesDelegatePortrait
148
149                 Item {
150                     id: wrapperItem; width: mainPage.componentWidth; height: mainPage.itemHeight
151                     Item {
152                         Rectangle { color: "black"; opacity: index % 2 ? 0.2 : 0.4; height: wrapperItem.height - 2; width: wrapperItem.width; y: 1                            
153                             MouseArea {
154                                 anchors.fill: parent
155                                 onDoubleClicked: {
156                                     appWindow.selectedSymbol = symbol;
157                                     uiLoader.sourceComponent = stockDetailsComponent;
158                                     titleBar.buttonType = "Back";
159                                     titleBar.displayMenu = false;
160                                     toolBar.displayIcons = false;
161                                 }
162                             }
163                         }
164
165                         Row {
166                             x: 10;y: 15;
167                             width: mainPage.componentWidth - 5;
168                             spacing: 3
169
170                             Text { text: stockName; width: parent.width * 42/100; font.pixelSize: 18; font.bold: true; elide: Text.ElideRight; color: "white"; style: Text.Raised; styleColor: "black" }
171                             Text { text: lastTradedPrice; width: parent.width * 20/100; font.pixelSize: 18; horizontalAlignment: Text.AlignLeft; elide: Text.ElideLeft; color: "#cccccc"; style: Text.Raised; styleColor: "black" }
172                             Column {
173                                 y: -15;
174                                 width: parent.width * 18/100; height: parent.height
175                                 spacing: 2
176                                 Text { text: change; font.pixelSize: 16; horizontalAlignment: Text.AlignLeft; elide: Text.ElideRight
177                                     color: if(change >= 0){"green";} else {"red";}
178                                         style: Text.Raised; styleColor: "black" }
179                                 Text { text: changePercentage; font.pixelSize: 16; horizontalAlignment: Text.AlignLeft; elide: Text.ElideRight;
180                                     color: if(change >= 0){"green";} else {"red";}
181                                         style: Text.Raised; styleColor: "black" }
182                             }
183                             Text { text: volume; width: parent.width * 20/100; font.pixelSize: 18; horizontalAlignment: Text.AlignLeft; elide: Text.ElideLeft; color: "#cccccc"; style: Text.Raised; styleColor: "black" }
184                         }
185                     }
186                 }
187             }
188
189             Component {
190                 id: newsDelegate
191
192                 Item {
193                     id: newsWrapper; width: mainPage.componentWidth; height: mainPage.itemHeight
194                     Item {
195                         anchors.fill: parent
196                         Rectangle { color: "black"; opacity: index % 2 ? 0.2 : 0.4; height: newsWrapper.height - 2; width: newsWrapper.width; y: 1 }
197                         Text {
198                             anchors.verticalCenter: parent.verticalCenter
199                             anchors.left: parent.left
200                             anchors.leftMargin: 10
201                             anchors.right: parent.right
202                             text: title; font.pixelSize: 18
203                             font.bold: false;
204                             verticalAlignment: Text.AlignVCenter
205                             horizontalAlignment: Text.AlignLeft
206                             elide: Text.ElideRight;
207                             color: "white";
208                             style: Text.Raised;
209                             styleColor: "black"
210                         }
211                         MouseArea{
212                             anchors.fill: parent
213                             onClicked: Qt.openUrlExternally(link);
214                         }
215                     }
216                 }
217             }
218
219             Library.TitleBar {
220                 id: titleBar;
221                 width: parent.width; height: mainPage.titleBarHeight;
222                 anchors.top: parent.top
223                 title: "Markets Today";
224                 buttonType: "Close";
225                 z: 5  //required to keep Titlebar and Menu buttons on top of everything else
226
227                 onCloseClicked: Qt.quit()
228
229                 onTickersClicked: {
230                     uiLoader.sourceComponent = configTickersComponent;
231                     titleBar.buttonType = "Back";
232                     titleBar.displayMenu = false;
233                     toolBar.displayIcons = false;
234                 }
235
236                 onOptionsClicked: {
237                     uiLoader.sourceComponent = configParamsComponent;
238                     titleBar.buttonType = "Back";
239                     titleBar.displayMenu = false;
240                     toolBar.displayIcons = false;
241                 }
242
243                 onBackClicked: {
244                     uiLoader.sourceComponent = stockQuotesUIComponent;
245                     titleBar.buttonType = "Close";
246                     titleBar.displayMenu = false;
247                     toolBar.displayIcons = true;
248                     mainPage.initializePage();
249                 }
250             }
251
252             Loader {
253                 id: uiLoader
254                 width: parent.width
255                 anchors.top: titleBar.bottom
256                 anchors.bottom: toolBar.top
257             }
258
259             Library.ToolBar {
260                 id:toolBar
261                 width: parent.width; height: mainPage.toolBarHeight
262                 anchors.bottom: parent.bottom
263                 opacity: 0.9
264                 displayNavigation: false
265                 onReloadButtonClicked: mainPage.reloadData();
266
267                 onNewsButtonClicked: {
268                     uiLoader.sourceComponent = newsComponent;
269                     toolBar.displayIcons = true;
270                     toolBar.targetContentType = "Stocks";
271                 }
272
273                 onStocksButtonClicked: {
274                     uiLoader.sourceComponent = stockQuotesUIComponent;
275                     toolBar.displayIcons = true;
276                     toolBar.targetContentType = "News";
277                 }
278
279
280                 Connections {
281                     target: appWindow
282                     onQuoteRefreshStarted:{
283                         if (!toolBar.updatePending) toolBar.updatePending = true;
284                     }
285                     onQuoteRefreshCompleted:{
286                         toolBar.updatePending = false;
287                     }
288                 }
289             }
290
291
292
293             Component {
294                 id: stockQuotesUIComponent
295                 Item {
296                     Rectangle{
297                         id: listViewWrapper
298                         width: parent.width
299                         anchors.top: parent.top
300                         anchors.bottom: footerText.top
301                         color: "#343434"
302
303                         ListView {
304                             id: stockQuotesView
305                             anchors.fill: parent
306                             flickDeceleration: 500
307                             model: stockQuoteDataModel
308                             delegate:  listViewWrapper.height > listViewWrapper.width ? stockQuotesDelegatePortrait : stockQuotesDelegateLandscape
309                             focus:true
310                             snapMode: ListView.SnapToItem
311                         }
312                     }
313
314                     Rectangle {
315                         id: stockStatusMsgArea
316                         height: 100
317                         color: "#343434"
318                         anchors {left: parent.left; leftMargin: 15; right: parent.right; rightMargin: 15;
319                                 verticalCenter: parent.verticalCenter}
320                         visible: false
321
322                         Text {
323                             id: stockStatusText
324                             anchors.fill: parent
325                             text: "Loading quotes.."
326                             horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter
327                             width: parent.width; font.pixelSize: 16; elide: Text.ElideNone;
328                             color: "#cccccc"
329                             wrapMode: Text.WrapAtWordBoundaryOrAnywhere
330                             style: Text.Raised; styleColor: "black"
331
332                             Connections {
333                                 target: appWindow
334                                 onQuoteRefreshCompleted: {
335                                     if (success){
336                                         stockStatusMsgArea.visible = false;
337                                     }
338                                     else{
339                                         stockStatusText.text = strMessage;
340                                         stockStatusMsgArea.visible = true;
341                                     }
342                                 }
343                             }
344                         }
345                     }
346
347                     Rectangle{
348                         id: footerText
349                         width: parent.width
350                         height: 25
351                         color: "#343434"
352                         anchors.bottom: parent.bottom
353                         Text {
354                             id: timeStamp
355                             anchors.fill: parent
356                             text: lastUpdatedTimeStamp
357                             horizontalAlignment: Text.AlignRight; verticalAlignment: Text.AlignVCenter
358                             width: parent.width; font.pixelSize: 12; elide: Text.ElideRight;
359                             color: "#cccccc"
360                             style: Text.Raised; styleColor: "black"
361
362                             Connections {
363                                 target: appWindow
364                                 onQuoteRefreshCompleted:{
365                                     timeStamp.text = lastUpdatedTimeStamp;
366                                 }
367                             }
368                         }
369                     }
370                 }
371             }
372
373             Component{
374                 id: stockDetailsComponent
375                 StockDetailsComponent {
376                     symbol: selectedSymbol
377                     onLogRequest: logUtility.logMessage(strMessage)
378                     onLockInLandscape: mainPage.orientationLock = PageOrientation.LockLandscape
379                     onUnlockOrientation: mainPage.orientationLock = PageOrientation.Automatic
380                 }
381             }
382
383             Component {
384                 id: newsComponent
385                 Item {
386                     Rectangle{
387                         id: newsViewArea
388                         width: parent.width
389                         anchors.top: parent.top
390                         anchors.bottom: parent.bottom
391                         color: "#343434"
392
393                         ListView {
394                             id: newsView
395                             anchors.fill: parent
396                             flickDeceleration: 500
397                             model: newsDataModel
398                             delegate:  newsDelegate
399                             focus:true
400                             snapMode: ListView.SnapToItem
401                         }
402                     }
403
404                     Rectangle {
405                         id: newsStatusMsgArea
406                         height: 100
407                         color: "#343434"
408                         anchors {left: parent.left; leftMargin: 15; right: parent.right; rightMargin: 15;
409                                 verticalCenter: parent.verticalCenter}
410                         visible: false
411
412                         Text {
413                             id: newsStatusText
414                             anchors.fill: parent
415                             text: "Loading news.."
416                             horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter
417                             width: parent.width; font.pixelSize: 16; elide: Text.ElideNone;
418                             color: "#cccccc"
419                             wrapMode: Text.WrapAtWordBoundaryOrAnywhere
420                             style: Text.Raised; styleColor: "black"
421
422                             Connections {
423                                 target: appWindow
424                                 onNewsReloadCompleted: {
425                                     if (success){
426                                         newsStatusMsgArea.visible = false;
427                                         newsViewArea.visible = true;
428                                     }
429                                     else{
430                                         newsStatusText.text = strMessage;
431                                         newsViewArea.visible = false;
432                                         newsStatusMsgArea.visible = true;
433                                     }
434                                 }
435                             }
436                         }
437                     }
438
439                 }
440             }
441
442             Component {
443                 id: configTickersComponent
444
445                 ConfigTickersComponent{
446                     itemHeight: mainPage.itemHeight
447                     componentWidth: mainPage.componentWidth
448                     onLogRequest: logUtility.logMessage(strMessage)
449                 }
450             }
451
452             Component {
453                 id: configParamsComponent
454                 ConfigParametersComponent{
455                     onLogRequest: logUtility.logMessage(strMessage)
456                 }
457             }
458         }
459     }
460 }