Finished Font Size Changes for Harmattan, Fremantle
[marketstoday] / src / qml / StockDetailsComponent.qml
1 /*
2 @version: 0.5
3 @author: Sudheer K. <scifi1947 at gmail.com>
4 @license: GNU General Public License
5 */
6
7 import Qt 4.7
8 import "Library" as Library
9 import "Library/js/CSVUtility.js" as CSVUtility
10
11 Item {
12
13     width: 800
14     height: 380
15
16     id: stockDetailsScreen
17     property int componentWidth: width
18     property int itemHeight: 75
19     property int newsItemHeight: 50
20     property int fontSizeMed: 24
21     property int fontSizeSmall: 20
22     property string symbol: "YHOO"
23     property string stockName: ""
24     property string lastTradedPrice: ""
25     property string lastTradedDateTime: ""
26     property string change: ""
27     property string changePercentage: ""
28     property string daysRange: ""
29     property string yearRange: ""
30     property string marketVolume: ""
31     property string prevClose: ""
32     property string marketCap: ""
33     property string baseChartURL: "http://chart.finance.yahoo.com/z?q=&l=&z=m&p=s&a=v&p=s&lang=en-US&region=US"
34     property string chartURL: ""
35     property string rssURL: ""
36     property string orientation: "Portrait"
37
38     property int currentScreenIndex: 1
39
40     signal logRequest(string strMessage)
41     signal loadChart(string duration)
42
43     Rectangle {
44         anchors.fill: parent
45         color:"#343434"
46         id: detailsRect
47
48         Library.CustomGestureArea {
49             anchors.fill: parent
50             onSwipeLeft: detailsRect.switchScreen()
51             onSwipeRight: detailsRect.switchScreen()
52         }
53
54         Component.onCompleted: {                                   
55             if (symbol !== "") {
56                 loadDetails();
57                 loadNews();
58                 chartURL = baseChartURL+"&t=1d&s="+symbol;
59             }
60         }
61
62         function switchScreen(){
63             switch (currentScreenIndex){
64             case 1:
65                 stockDetailsLoader.sourceComponent = (stockDetailsScreen.width > stockDetailsScreen.height)? stockChartComponentLandscape : stockChartComponentPortrait;
66                 currentScreenIndex = currentScreenIndex + 1;
67                 break;
68             case 2:
69                 stockDetailsLoader.sourceComponent = stockDetailsComponent;
70                 currentScreenIndex = currentScreenIndex - 1;
71                 break;
72             default:
73                 //Do Nothing
74             }
75             logRequest("currentScreenIndex = "+currentScreenIndex);
76         }
77
78         function loadDetails(){
79             var queryURL = 'http://download.finance.yahoo.com/d/quotes.csv?s='+symbol+'&f=snl1d1t1c1p2mwvpj1&e=.csv';
80             //var queryURL = 'http://query.yahooapis.com/v1/public/yql?q=select Symbol,Name,LastTradePriceOnly,LastTradeDate,LastTradeTime,Change,ChangeinPercent,DaysRange,YearRange,Volume,PreviousClose,MarketCapitalization from yahoo.finance.quotes where symbol in ("'+symbol+'")&env=store://datatables.org/alltableswithkeys';
81             logRequest("Loading stock details from "+queryURL);
82             var response = new XMLHttpRequest();
83             response.onreadystatechange = function() {
84                 if (response.readyState === XMLHttpRequest.DONE) {
85                     refreshDetails(response.responseText);
86                 }
87             }
88
89             response.open("GET", queryURL);
90             response.send();
91         }
92
93         function loadNews(){
94             rssURL = "http://feeds.finance.yahoo.com/rss/2.0/headline?region=US&lang=en-US&s="+symbol;
95             logRequest("Loading news from "+rssURL);
96             var response = new XMLHttpRequest();
97             response.onreadystatechange = function() {
98                 if (response.readyState === XMLHttpRequest.DONE) {
99                     refreshNewsModel(response.responseXML);
100                 }
101             }
102
103             response.open("GET", rssURL);
104             response.send();
105         }
106
107         function refreshDetails(responseText){
108             if (!responseText) {
109                 logUtility("No responseText for quote "+symbol);
110                 return;
111             }
112
113             var quoteDetails = CSVUtility.csvToArray(responseText.trim());
114             if (quoteDetails && quoteDetails.length > 0){
115                 //We are only expecting one quote row per symbol.
116                 //snl1d1t1c1p2mwvpj1
117                 var lastTradedDate = "", lastTradedTime ="";
118                 stockName = quoteDetails[0][1];
119                 lastTradedPrice = quoteDetails[0][2];
120                 lastTradedDate = quoteDetails[0][3];
121                 lastTradedTime = quoteDetails[0][4];
122                 change = quoteDetails[0][5];
123                 changePercentage = quoteDetails[0][6];
124                 daysRange = quoteDetails[0][7];
125                 yearRange = quoteDetails[0][8];
126                 marketVolume = quoteDetails[0][9];
127                 prevClose = quoteDetails[0][10];
128                 marketCap = quoteDetails[0][11];
129                 if (lastTradedDate !== "") lastTradedDateTime = lastTradedDate + " " + lastTradedTime;
130             }
131             else {
132                 logRequest("No results for stock quote details");
133             }
134         }
135
136         function refreshNewsModel(responseXML){
137             if (!(responseXML && stockNewsDataModel)) return;
138
139             var xmlDoc = responseXML.documentElement;
140             var channel = xmlDoc.firstChild;
141
142             //Not the best code I ever wrote, but got no choice
143             //Refer to Memory leak issue with XMLListModel --> http://bugreports.qt.nokia.com/browse/QTBUG-15191
144
145             if (channel) {
146                 var itemNodes = channel.childNodes;
147                 if (itemNodes){
148
149                     logRequest("Clearing News Model");
150                     stockNewsDataModel.clear();
151
152                     var i = 0;
153                     for (i = 0; i < itemNodes.length; i++) {
154
155                         if (itemNodes[i].nodeName === 'item'){
156                             var newsElements = itemNodes[i].childNodes;
157                             var j = 0;
158                             var newsTitle,newsLink
159                             for (j = 0; j < newsElements.length; j++){
160
161                                 switch (newsElements[j].nodeName){
162                                     case 'title':
163                                         newsTitle = newsElements[j].childNodes[0].nodeValue;
164                                         break;
165                                     case 'link':
166                                         newsLink = newsElements[j].childNodes[0].nodeValue;
167                                         break;
168                                     default:
169                                 }
170                             }
171                             stockNewsDataModel.append({"title":newsTitle,"link":newsLink});
172                         }
173                     }
174                 }
175             }
176         }
177
178         ListModel{
179             id: stockNewsDataModel
180         }
181
182         Component {
183             id: stockNewsDelegate
184
185             Item {
186                 id: newsWrapper; width: stockDetailsLoader.width; height: newsItemHeight
187                 Item {
188                     anchors.fill: parent
189                     Rectangle { color: "black"; opacity: index % 2 ? 0.2 : 0.4; height: newsWrapper.height - 2; width: newsWrapper.width; y: 1 }
190                     Text {
191                         anchors {verticalCenter: parent.verticalCenter;left: parent.left;leftMargin: 10;right: parent.right}
192                         text: title; font.pixelSize: stockDetailsScreen.fontSizeSmall
193                         font.bold: false;
194                         verticalAlignment: Text.AlignVCenter
195                         horizontalAlignment: Text.AlignLeft
196                         elide: Text.ElideRight;
197                         color: "white";
198                         style: Text.Raised;
199                         styleColor: "black"
200                     }
201                     Library.CustomGestureArea {
202                         anchors.fill: parent
203                         onDoubleClicked: {
204                             logRequest("Opening news article: "+link);
205                             Qt.openUrlExternally(link);
206                         }
207                         onSwipeLeft: detailsRect.switchScreen()
208                         onSwipeRight: detailsRect.switchScreen()
209                     }
210                 }
211             }
212         }
213
214         Component {
215             id: stockDetailsComponent
216
217             Item {
218                 anchors.fill: parent
219
220                 Text {
221                     id: stockNameLabel
222                     anchors.top: parent.top
223                     width: parent.width
224                     z: 5
225                     anchors.horizontalCenter: parent.horizontalCenter
226                     height: stockDetailsScreen.fontSizeMed + 15
227                     horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter
228                     font.pixelSize: stockDetailsScreen.fontSizeMed; font.bold: true; elide: Text.ElideMiddle; color: "#B8B8B8"; style: Text.Raised; styleColor: "black"
229                     text: (stockName != "")? (stockName +" ("+symbol+")"):symbol
230                 }
231
232
233                 Rectangle {
234                     id: stockDetailsSection
235                     border.width: 1
236                     border.color: "#BFBFBF"
237                     color:"#2E2E2E"
238                     anchors {top: stockNameLabel.bottom;left: parent.left;right: parent.right}
239                     z: 5
240                     height: (stockDetailsScreen.width > stockDetailsScreen.height)? 105:155
241                     radius: 15
242
243                     Column{
244                         id: stockDetailsColumn
245                         anchors {top: parent.top; left: parent.left; leftMargin: 10; right: parent.right; rightMargin: 10}
246                         //spacing: 10
247                         //width: parent.width
248
249                         StockDetailsRow{
250                             label1: "Last Traded"
251                             value1: lastTradedPrice
252                             cell1Width: stockDetailsColumn.width/2
253                             multilineLabel1: false
254                             landscape: (stockDetailsScreen.width > stockDetailsScreen.height)
255
256                             label2: "Day's Range"
257                             value2: daysRange
258                             cell2Width: stockDetailsColumn.width/2
259                             multilineLabel2: true
260                         }
261
262                         StockDetailsRow{
263                             label1: "Last Trade Time"
264                             value1: lastTradedDateTime
265                             cell1Width: stockDetailsColumn.width/2
266                             multilineLabel1: true
267                             landscape: (stockDetailsScreen.width > stockDetailsScreen.height)
268
269                             label2: "52w Range"
270                             value2: yearRange
271                             cell2Width: stockDetailsColumn.width/2
272                             multilineLabel2: true
273                         }
274
275                         StockDetailsRow{
276                             label1: "Change"
277                             value1: ((change != "" && changePercentage != "")? change + " ("+changePercentage+")":"")
278                             cell1Width: stockDetailsColumn.width/2
279                             landscape: (stockDetailsScreen.width > stockDetailsScreen.height)
280
281                             label2: "Volume"
282                             value2: marketVolume
283                             cell2Width: stockDetailsColumn.width/2
284                         }
285
286                         StockDetailsRow{
287                             label1: "Prev. Close"
288                             value1: prevClose
289                             cell1Width: stockDetailsColumn.width/2
290                             landscape: (stockDetailsScreen.width > stockDetailsScreen.height)
291
292                             label2: "Market Cap"
293                             value2: marketCap
294                             cell2Width: stockDetailsColumn.width/2
295                         }
296                     }
297                 }
298
299                 Rectangle{
300                     border.width: 1
301                     border.color: "#BFBFBF"
302                     color:"#2E2E2E"
303                     width: parent.width
304                     anchors {top: stockDetailsSection.bottom;topMargin: 10;
305                              bottom: parent.bottom;
306                              left: parent.left;
307                              right: parent.right}
308                     ListView {
309                         flickDeceleration: 500
310                         anchors.fill: parent
311                         model: stockNewsDataModel
312                         delegate: stockNewsDelegate
313                         focus:true
314                         snapMode: ListView.SnapToItem
315                     }
316                 }
317
318             }
319         }
320
321         Loader {
322           id: stockDetailsLoader
323           anchors{top: parent.top; bottom: parent.bottom; bottomMargin: 20;
324                   left: parent.left; leftMargin: 10
325                   right:  parent.right; rightMargin: 10}
326           sourceComponent: stockDetailsComponent
327
328           Connections{
329               target: stockDetailsScreen
330               onOrientationChanged: {
331                   logRequest("Orientation Changed");
332                   logRequest("New orientation is "+stockDetailsScreen.orientation);
333                   logRequest("Margins for StockDetailsLoader are "+stockDetailsLoader.anchors.leftMargin+", "+stockDetailsLoader.anchors.rightMargin);
334
335                   if (currentScreenIndex === 2){
336                       if (stockDetailsScreen.orientation == "Landscape")
337                           stockDetailsLoader.sourceComponent = stockChartComponentLandscape;
338                       else
339                           stockDetailsLoader.sourceComponent = stockChartComponentPortrait;
340                   }
341               }
342           }
343         }
344
345         Rectangle{
346             id: footerText
347             width: parent.width
348             height: 20
349             z: 5
350             color: "#343434"
351             anchors.top: stockDetailsLoader.bottom
352             Text {
353                 id: footerMessage
354                 anchors.fill: parent
355                 text: "Swipe horizontally to switch between details and charts."
356                 horizontalAlignment: Text.AlignRight; verticalAlignment: Text.AlignVCenter
357                 width: parent.width; font.pixelSize: 12; elide: Text.ElideRight;
358                 color: "#cccccc"
359                 style: Text.Raised; styleColor: "black"
360             }
361
362             Timer {
363                 id: footerMessageTimer
364                 interval: 10000
365                 repeat: false
366                 onTriggered: {
367                     footerMessage.text = "";
368                 }
369             }
370
371             Component.onCompleted: {
372                 footerMessageTimer.start();
373             }
374         }
375
376         Component{
377             id: stockChartComponentLandscape
378
379             Item {
380                 id: chartAreaWrapperLand
381                 anchors.fill: parent
382
383                 Rectangle {
384                     id: chartAreaLand
385                     border.width: 1
386                     border.color: "#BFBFBF"
387                     //color:"#2E2E2E"
388                     color:"white"
389                     anchors { top: parent.top;topMargin: 40;
390                               bottom: parent.bottom; bottomMargin: 20;
391                               left: parent.left; right: parent.right}
392                     radius: 10
393
394                     Library.Loading { anchors.centerIn: parent; visible: chartImg.status == Image.Loading}
395
396                     Image {
397                         id: chartImg
398                         anchors {left: parent.left; leftMargin: 10; verticalCenter: parent.verticalCenter}
399                         source: chartURL
400                         sourceSize.width: 512
401                         sourceSize.height: 288
402                         smooth: true
403                         fillMode: Image.PreserveAspectFit
404                         onStatusChanged: {
405                             switch(status){
406                                 case Image.Ready:
407                                     logRequest("Image is ready");
408                                     break;
409                                 case Image.Loading:
410                                     logRequest("Image is loading");
411                                     break;
412                                 case Image.Error:
413                                     logRequest("Image loading failed");
414                                     break;
415                                 default:
416                                     logRequest("No image specified");
417                                     break;
418                             }
419
420                         }
421
422                         Connections{
423                             target: stockDetailsScreen
424                             onLoadChart: {
425                                 chartURL = baseChartURL+"&t="+duration+"&s="+symbol;
426                                 logRequest(chartURL);
427                             }
428                         }
429                     }
430
431                     Column {
432                         width: 130
433                         spacing: 20
434                         anchors {top: parent.top; topMargin: 40; bottom: parent.bottom;
435                                  right: chartAreaLand.right;rightMargin: 60}
436
437                         Row {
438                             height: 40
439                             spacing: 20
440                             anchors.horizontalCenter: parent.horizontalCenter
441                             Library.Button {
442                                 text:  "1d"
443                                 anchors { verticalCenter: parent.verticalCenter}
444                                 width: 75; height: 40
445                                 onClicked: loadChart("1d");
446                             }
447
448                             Library.Button {
449                                 text:  "5d"
450                                 anchors { verticalCenter: parent.verticalCenter}
451                                 width: 75; height: 40
452                                 onClicked: loadChart("5d");
453                             }
454                         }
455
456                         Row {
457                             height: 40
458                             spacing: 20
459                             anchors.horizontalCenter: parent.horizontalCenter
460                             Library.Button {
461                                 text:  "3m"
462                                 anchors { verticalCenter: parent.verticalCenter}
463                                 width: 75; height: 40
464                                 onClicked: loadChart("3m");
465                             }
466
467                             Library.Button {
468                                 text:  "6m"
469                                 anchors { verticalCenter: parent.verticalCenter}
470                                 width: 75; height: 40
471                                 onClicked: loadChart("6m");
472                             }
473                         }
474                         Row {
475                             height: 40
476                             spacing: 20
477                             anchors.horizontalCenter: parent.horizontalCenter
478                             Library.Button {
479                                 text:  "1y"
480                                 anchors { verticalCenter: parent.verticalCenter}
481                                 width: 75; height: 40
482                                 onClicked: loadChart("1y");
483                             }
484
485                             Library.Button {
486                                 text:  "2y"
487                                 anchors { verticalCenter: parent.verticalCenter}
488                                 width: 75; height: 40
489                                 onClicked: loadChart("2y");
490                             }
491                         }
492                         Row {
493                             height: 40
494                             spacing: 20
495                             anchors.horizontalCenter: parent.horizontalCenter
496                             Library.Button {
497                                 text:  "5y"
498                                 anchors { verticalCenter: parent.verticalCenter}
499                                 width: 75; height: 40
500                                 onClicked: loadChart("5y");
501                             }
502
503                             Library.Button {
504                                 text:  "max"
505                                 anchors { verticalCenter: parent.verticalCenter}
506                                 width: 75; height: 40
507                                 onClicked: loadChart("my");
508                             }
509                         }
510                     }
511                 }
512             }
513         }
514
515         Component{
516             id: stockChartComponentPortrait
517
518             Item {
519                 id: chartAreaWrapperPort
520                 anchors.fill: parent
521
522                 Rectangle {
523                     id: chartAreaPort
524                     border.width: 1
525                     border.color: "#BFBFBF"
526                     //color:"#2E2E2E"
527                     color:"white"
528                     anchors { top: parent.top;topMargin: 40;
529                               bottom: parent.bottom; bottomMargin: 20;
530                               left: parent.left; right: parent.right}
531                     radius: 10
532
533                     Library.Loading { anchors.centerIn: parent; visible: chartImgPort.status == Image.Loading}
534
535                     Image {
536                         id: chartImgPort
537                         //anchors {left: parent.left; leftMargin: 10; horizontalCenter: parent.horizontalCenter}
538                         anchors {horizontalCenter: parent.horizontalCenter; top: parent.top; topMargin: 40}
539                         source: chartURL
540                         sourceSize.width: 512
541                         sourceSize.height: 288
542                         smooth: true
543                         fillMode: Image.PreserveAspectFit
544                         width: parent.width - 20
545                         onStatusChanged: {
546                             switch(status){
547                                 case Image.Ready:
548                                     logRequest("Image is ready");
549                                     break;
550                                 case Image.Loading:
551                                     logRequest("Image is loading");
552                                     break;
553                                 case Image.Error:
554                                     logRequest("Image loading failed");
555                                     break;
556                                 default:
557                                     logRequest("No image specified");
558                                     break;
559                             }
560
561                         }
562
563                         Connections{
564                             target: stockDetailsScreen
565                             onLoadChart: {
566                                 chartURL = baseChartURL+"&t="+duration+"&s="+symbol;
567                                 logRequest(chartURL);
568                             }
569                         }
570                     }
571
572                     Column {
573                         width: 280
574                         spacing: 20
575                         anchors {verticalCenter: parent.verticalCenter;verticalCenterOffset: 100; horizontalCenter: parent.horizontalCenter}
576
577                         Row {
578                             height: 40
579                             spacing: 20
580                             anchors.horizontalCenter: parent.horizontalCenter
581                             Library.Button {
582                                 text:  "1d"
583                                 anchors { verticalCenter: parent.verticalCenter}
584                                 width: 75; height: 40
585                                 onClicked: loadChart("1d");
586                             }
587
588                             Library.Button {
589                                 text:  "5d"
590                                 anchors { verticalCenter: parent.verticalCenter}
591                                 width: 75; height: 40
592                                 onClicked: loadChart("5d");
593                             }
594
595                             Library.Button {
596                                 text:  "3m"
597                                 anchors { verticalCenter: parent.verticalCenter}
598                                 width: 75; height: 40
599                                 onClicked: loadChart("3m");
600                             }
601
602                             Library.Button {
603                                 text:  "6m"
604                                 anchors { verticalCenter: parent.verticalCenter}
605                                 width: 75; height: 40
606                                 onClicked: loadChart("6m");
607                             }
608                         }
609
610                         Row {
611                             height: 40
612                             spacing: 20
613                             anchors.horizontalCenter: parent.horizontalCenter
614                             Library.Button {
615                                 text:  "1y"
616                                 anchors { verticalCenter: parent.verticalCenter}
617                                 width: 75; height: 40
618                                 onClicked: loadChart("1y");
619                             }
620
621                             Library.Button {
622                                 text:  "2y"
623                                 anchors { verticalCenter: parent.verticalCenter}
624                                 width: 75; height: 40
625                                 onClicked: loadChart("2y");
626                             }
627
628                             Library.Button {
629                                 text:  "5y"
630                                 anchors { verticalCenter: parent.verticalCenter}
631                                 width: 75; height: 40
632                                 onClicked: loadChart("5y");
633                             }
634
635                             Library.Button {
636                                 text:  "max"
637                                 anchors { verticalCenter: parent.verticalCenter}
638                                 width: 75; height: 40
639                                 onClicked: loadChart("my");
640                             }
641                         }
642                     }
643                 }
644             }
645         }
646
647     }
648 }