Merge lp:~artmello/webbrowser-app/webbrowser-app-new_history into lp:webbrowser-app

Proposed by Arthur Mello
Status: Merged
Merged at revision: 644
Proposed branch: lp:~artmello/webbrowser-app/webbrowser-app-new_history
Merge into: lp:webbrowser-app
Diff against target: 592 lines (+458/-1)
9 files modified
src/app/webbrowser/ActivityView.qml (+51/-0)
src/app/webbrowser/ExpandedHistoryView.qml (+132/-0)
src/app/webbrowser/HistoryView.qml (+233/-0)
src/app/webbrowser/history-domain-model.cpp (+16/-0)
src/app/webbrowser/history-domain-model.h (+9/-0)
src/app/webbrowser/history-domainlist-model.cpp (+9/-0)
src/app/webbrowser/history-domainlist-model.h (+3/-0)
src/app/webbrowser/history-model.cpp (+3/-0)
src/app/webbrowser/history-model.h (+2/-1)
To merge this branch: bzr merge lp:~artmello/webbrowser-app/webbrowser-app-new_history
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Ubuntu Phablet Team Pending
Review via email: mp+226871@code.launchpad.net

Commit message

Add new history view

Description of the change

Add new history view

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Bill Filler (bfiller) wrote :

Works very nice. A few comments:
1) many sites are missing favicons, especially the ones in the history from some days ago. I believe Olivier said these are not stored locally, but maybe they should be. At minimum we should have a place holder icon (like a globe or something) for the sites that don't have favicons. Would be better than blank white shape.

2) I think the spec says to only display 2 links and then a See More button. This works well for sites with more than 3 links, but sites with exactly 3 links show all of them when expanding. I don't think it's bad, but is different than what the spec says.

3) The second level list (when expanding the main list) is scrollable, but don't know if it needs to be as we're only showing two items

Can't wait to see the See More page!

Revision history for this message
Olivier Tilloy (osomon) wrote :

A few additional comments:

> 1) many sites are missing favicons, especially the ones in the history from
> some days ago. I believe Olivier said these are not stored locally, but maybe
> they should be. At minimum we should have a place holder icon (like a globe or
> something) for the sites that don't have favicons. Would be better than blank
> white shape.

The lack of a persistent cache for favicons is tracked by bug #1340585, but let’s address it separately.
We could use a placeholder icon indeed. I’ve been using one in my new-header branch, in fact we could probably modify the Favicon component to show a fallback icon when not available (see what I did at http://bazaar.launchpad.net/~osomon/webbrowser-app/new-header/view/head:/src/app/webbrowser/AddressBar.qml#L60).

> 3) The second level list (when expanding the main list) is scrollable, but
> don't know if it needs to be as we're only showing two items

I think it shouldn’t be scrollable.

624. By Arthur Mello

Add expanded history view

625. By Arthur Mello

Merge with trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:625
http://jenkins.qa.ubuntu.com/job/webbrowser-app-ci/952/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/2134
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic/1784/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-amd64-ci/151
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-armhf-ci/151
        deb: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-armhf-ci/151/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-i386-ci/151
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/2354
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/3288
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/3288/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/10005
    FAILURE: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic/1494/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/1997
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/1997/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/webbrowser-app-ci/952/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/app/webbrowser/ActivityView.qml'
2--- src/app/webbrowser/ActivityView.qml 2014-03-12 22:45:12 +0000
3+++ src/app/webbrowser/ActivityView.qml 2014-07-17 13:31:54 +0000
4@@ -64,4 +64,55 @@
5 }
6 }
7 }
8+ Tab {
9+ title: i18n.tr("History")
10+ page: PageStack {
11+ id: historyStack
12+ Component.onCompleted: push(historyViewPage)
13+
14+ Page {
15+ id: historyViewPage
16+ visible: false
17+
18+ HistoryView {
19+ id: historyView
20+ anchors.fill: parent
21+
22+ historyModel: activityView.historyModel
23+
24+ onHistoryEntryClicked: activityView.historyEntryRequested(url)
25+ onSeeMoreEntriesClicked: {
26+ historyStack.push(timelineViewPage, {model: model, modelPreviousLimit: model.limit})
27+ model.limit = -1
28+ }
29+ }
30+
31+ tools: ToolbarItems { locked: true; opened: false; }
32+ }
33+
34+ Page {
35+ id: timelineViewPage
36+ visible: false
37+
38+ property alias model: expandedHistoryView.model
39+ property alias modelPreviousLimit: expandedHistoryView.modelPreviousLimit
40+
41+ ExpandedHistoryView {
42+ id: expandedHistoryView
43+ anchors.fill: parent
44+
45+ onHistoryEntryClicked: {
46+ historyStack.pop()
47+ activityView.historyEntryRequested(url)
48+ }
49+ onBackToHistoryClicked: {
50+ model.limit = modelPreviousLimit
51+ historyStack.pop()
52+ }
53+ }
54+
55+ tools: ToolbarItems { locked: true; opened: false; }
56+ }
57+ }
58+ }
59 }
60
61=== added file 'src/app/webbrowser/ExpandedHistoryView.qml'
62--- src/app/webbrowser/ExpandedHistoryView.qml 1970-01-01 00:00:00 +0000
63+++ src/app/webbrowser/ExpandedHistoryView.qml 2014-07-17 13:31:54 +0000
64@@ -0,0 +1,132 @@
65+/*
66+ * Copyright 2014 Canonical Ltd.
67+ *
68+ * This file is part of webbrowser-app.
69+ *
70+ * webbrowser-app is free software; you can redistribute it and/or modify
71+ * it under the terms of the GNU General Public License as published by
72+ * the Free Software Foundation; version 3.
73+ *
74+ * webbrowser-app is distributed in the hope that it will be useful,
75+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
76+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
77+ * GNU General Public License for more details.
78+ *
79+ * You should have received a copy of the GNU General Public License
80+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
81+ */
82+
83+import QtQuick 2.0
84+import Ubuntu.Components 0.1
85+import Ubuntu.Components.ListItems 0.1 as ListItem
86+import webbrowserapp.private 0.1
87+
88+Item {
89+ id: expandedHistoryView
90+
91+ property alias model: entriesListView.model
92+ property string expandedDomain: ""
93+ property int modelPreviousLimit
94+
95+ signal historyEntryClicked(url url)
96+ signal backToHistoryClicked()
97+
98+ Rectangle {
99+ id: expandedHistoryViewBackground
100+ anchors.fill: parent
101+ color: "white"
102+ }
103+
104+ ListView {
105+ id: entriesListView
106+
107+ anchors {
108+ fill: parent
109+ margins: units.gu(2)
110+ }
111+
112+ spacing: units.gu(1)
113+
114+ header: Rectangle {
115+ width: parent.width
116+ height: units.gu(5)
117+
118+ MouseArea {
119+ anchors.fill: parent
120+ onClicked: backToHistoryClicked()
121+ }
122+
123+ Row {
124+ spacing: units.gu(2)
125+
126+ UbuntuShape {
127+ height: parent.height
128+ width: parent.height
129+
130+ Image {
131+ anchors.fill: parent
132+ }
133+ }
134+
135+ Label {
136+ fontSize: "large"
137+ text: i18n.tr("History")
138+ }
139+ }
140+ }
141+ section.property: "lastVisitDate"
142+ section.delegate: Rectangle {
143+ anchors {
144+ left: parent.left
145+ right: parent.right
146+ }
147+
148+ height: sectionHeader.height + units.gu(1)
149+
150+ color: expandedHistoryViewBackground.color
151+
152+ ListItem.Header {
153+ id: sectionHeader
154+
155+ text:{
156+ var today = new Date()
157+ var yesterday = new Date()
158+ yesterday.setDate(yesterday.getDate() - 1)
159+
160+ if (section === Qt.formatDateTime(today, "yyyy-MM-dd")) {
161+ return i18n.tr("Last visited")
162+ } else if (section === Qt.formatDateTime(yesterday, "yyyy-MM-dd")) {
163+ return i18n.tr("Yesterday")
164+ } else {
165+ var values = section.split("-", 3)
166+ var year = values[0]
167+ var month = values[1]
168+ var day = values[2]
169+
170+ var d = new Date(year, month-1, day)
171+ if (parseInt(day) === 1)
172+ return Qt.formatDateTime(d, "dddd dd'st' MMMM")
173+ if (parseInt(day) === 2)
174+ return Qt.formatDateTime(d, "dddd dd'nd' MMMM")
175+ if (parseInt(day) === 3)
176+ return Qt.formatDateTime(d, "dddd dd'rd' MMMM")
177+ else
178+ return Qt.formatDateTime(d, "dddd dd'th' MMMM")
179+ }
180+ }
181+ }
182+ }
183+
184+ delegate: UrlDelegate {
185+ id: entriesDelegate
186+ width: parent.width
187+ height: units.gu(5)
188+
189+ url: model.url
190+ title: model.title
191+ icon: model.icon
192+
193+ onClicked: historyEntryClicked(model.url)
194+ }
195+ }
196+}
197
198=== added file 'src/app/webbrowser/HistoryView.qml'
199--- src/app/webbrowser/HistoryView.qml 1970-01-01 00:00:00 +0000
200+++ src/app/webbrowser/HistoryView.qml 2014-07-17 13:31:54 +0000
201@@ -0,0 +1,233 @@
202+/*
203+ * Copyright 2014 Canonical Ltd.
204+ *
205+ * This file is part of webbrowser-app.
206+ *
207+ * webbrowser-app is free software; you can redistribute it and/or modify
208+ * it under the terms of the GNU General Public License as published by
209+ * the Free Software Foundation; version 3.
210+ *
211+ * webbrowser-app is distributed in the hope that it will be useful,
212+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
213+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
214+ * GNU General Public License for more details.
215+ *
216+ * You should have received a copy of the GNU General Public License
217+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
218+ */
219+
220+import QtQuick 2.0
221+import Ubuntu.Components 0.1
222+import Ubuntu.Components.ListItems 0.1 as ListItem
223+import webbrowserapp.private 0.1
224+
225+Item {
226+ id: historyView
227+
228+ property QtObject historyModel
229+ property string expandedDomainName: ""
230+
231+ signal historyEntryClicked(url url)
232+ signal seeMoreEntriesClicked(LimitProxyModel model)
233+
234+ Rectangle {
235+ id: historyViewBackground
236+ anchors.fill: parent
237+ color: "white"
238+ }
239+
240+ ListView {
241+ id: domainsListView
242+
243+ anchors {
244+ fill: parent
245+ margins: units.gu(2)
246+ }
247+
248+ spacing: units.gu(1)
249+
250+ model: HistoryDomainListChronologicalModel {
251+ sourceModel: HistoryDomainListModel {
252+ sourceModel: HistoryTimeframeModel {
253+ sourceModel: historyModel
254+ }
255+ }
256+ }
257+
258+ section.property: "lastVisitDate"
259+ section.delegate: Rectangle {
260+ anchors {
261+ left: parent.left
262+ right: parent.right
263+ }
264+
265+ height: sectionHeader.height + units.gu(1)
266+
267+ color: historyViewBackground.color
268+
269+ ListItem.Header {
270+ id: sectionHeader
271+
272+ text:{
273+ var today = new Date()
274+ var yesterday = new Date()
275+ yesterday.setDate(yesterday.getDate() - 1)
276+
277+ if (section === Qt.formatDateTime(today, "yyyy-MM-dd")) {
278+ return i18n.tr("Last visited")
279+ } else if (section === Qt.formatDateTime(yesterday, "yyyy-MM-dd")) {
280+ return i18n.tr("Yesterday")
281+ } else {
282+ var values = section.split("-", 3)
283+ var year = values[0]
284+ var month = values[1]
285+ var day = values[2]
286+
287+ var d = new Date(year, month-1, day)
288+ if (parseInt(day) === 1)
289+ return Qt.formatDateTime(d, "dddd dd'st' MMMM")
290+ if (parseInt(day) === 2)
291+ return Qt.formatDateTime(d, "dddd dd'nd' MMMM")
292+ if (parseInt(day) === 3)
293+ return Qt.formatDateTime(d, "dddd dd'rd' MMMM")
294+ else
295+ return Qt.formatDateTime(d, "dddd dd'th' MMMM")
296+ }
297+ }
298+ }
299+ }
300+
301+ delegate: Column {
302+ height: domainsDelegate.height + entriesView.height
303+ width: parent.width
304+ clip: true
305+
306+ LimitProxyModel {
307+ id: entriesModelLimited
308+ sourceModel: model.entries
309+ limit: 3
310+ }
311+
312+ UrlDelegate {
313+ id: domainsDelegate
314+ width: parent.width
315+ height: units.gu(5)
316+
317+ property bool expanded: historyView.expandedDomainName === model.domain
318+
319+ url: {
320+ if (expanded) {
321+ if (entriesModelLimited.unlimitedCount === 1)
322+ return i18n.tr("%1 page").arg(entriesModelLimited.unlimitedCount)
323+ else
324+ return i18n.tr("%1 pages").arg(entriesModelLimited.unlimitedCount)
325+ } else {
326+ return model.lastVisitedTitle
327+ }
328+ }
329+
330+ title: model.domain
331+ icon: model.lastVisitedIcon
332+
333+ onClicked: {
334+ if (historyView.expandedDomainName === model.domain)
335+ historyView.expandedDomainName = ""
336+ else
337+ historyView.expandedDomainName = model.domain
338+
339+ if (entriesView.domain !== model.domain) {
340+ entriesView.domain = model.domain
341+
342+ if (entriesModelLimited.unlimitedCount > 3)
343+ entriesModelLimited.limit = 2
344+
345+ entriesView.limitedModel = entriesModelLimited
346+ }
347+ }
348+ }
349+
350+ Item {
351+ id: entriesView
352+
353+ property LimitProxyModel limitedModel
354+ property string domain: ""
355+
356+ anchors {
357+ left: parent.left
358+ right: parent.right
359+ }
360+
361+ height: 0
362+ opacity: 0.0
363+
364+ ListView {
365+ id: entriesListView
366+
367+ anchors {
368+ fill: parent
369+ margins: domainsListView.spacing
370+ }
371+
372+ spacing: domainsListView.spacing
373+
374+ model: entriesView.limitedModel
375+
376+ interactive: false
377+
378+ delegate: UrlDelegate {
379+ id: entriesDelegate
380+
381+ width: parent.width
382+ height: units.gu(5)
383+
384+ url: model.url
385+ title: model.title ? model.title : model.url
386+ icon: model.icon
387+
388+ onClicked: historyEntryClicked(model.url)
389+ }
390+
391+ footer: Rectangle {
392+ width: parent.width
393+ height: footerLabel.visible ? units.gu(5) : 0
394+
395+ MouseArea {
396+ width: footerLabel.width + units.gu(4)
397+ height: parent.height
398+
399+ anchors.centerIn: footerLabel
400+
401+ enabled: footerLabel.visible
402+
403+ onClicked: seeMoreEntriesClicked(entriesView.limitedModel)
404+ }
405+
406+ Label {
407+ id: footerLabel
408+ anchors.centerIn: parent
409+
410+ visible: entriesView.limitedModel ? entriesView.limitedModel.unlimitedCount > 3 : false
411+
412+ font.bold: true
413+ text: i18n.tr("see more")
414+ }
415+ }
416+ }
417+
418+ states: State {
419+ name: "expanded"
420+ when: (domain !== "") && domain === historyView.expandedDomainName
421+ PropertyChanges {
422+ target: entriesView
423+ height: limitedModel ? limitedModel.count * (units.gu(5) + domainsListView.spacing) + entriesListView.footerItem.height : 0
424+ opacity: 1.0
425+ }
426+ }
427+
428+ transitions: Transition {
429+ UbuntuNumberAnimation { properties: "height,opacity" }
430+ }
431+ }
432+ }
433+ }
434+}
435
436=== modified file 'src/app/webbrowser/history-domain-model.cpp'
437--- src/app/webbrowser/history-domain-model.cpp 2014-05-22 15:32:52 +0000
438+++ src/app/webbrowser/history-domain-model.cpp 2014-07-17 13:31:54 +0000
439@@ -78,6 +78,16 @@
440 return m_lastVisit;
441 }
442
443+const QString& HistoryDomainModel::lastVisitedTitle() const
444+{
445+ return m_lastVisitedTitle;
446+}
447+
448+const QUrl& HistoryDomainModel::lastVisitedIcon() const
449+{
450+ return m_lastVisitedIcon;
451+}
452+
453 bool HistoryDomainModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
454 {
455 if (m_domain.isEmpty()) {
456@@ -92,8 +102,14 @@
457 {
458 if (rowCount() > 0) {
459 m_lastVisit = data(index(0, 0), HistoryModel::LastVisit).toDateTime();
460+ m_lastVisitedTitle = data(index(0, 0), HistoryModel::Title).toString();
461+ m_lastVisitedIcon = data(index(0, 0), HistoryModel::Icon).toUrl();
462 } else {
463 m_lastVisit = QDateTime();
464+ m_lastVisitedTitle = QString();
465+ m_lastVisitedIcon = QUrl();
466 }
467 Q_EMIT lastVisitChanged();
468+ Q_EMIT lastVisitedTitleChanged();
469+ Q_EMIT lastVisitedIconChanged();
470 }
471
472=== modified file 'src/app/webbrowser/history-domain-model.h'
473--- src/app/webbrowser/history-domain-model.h 2014-03-12 10:59:54 +0000
474+++ src/app/webbrowser/history-domain-model.h 2014-07-17 13:31:54 +0000
475@@ -23,6 +23,7 @@
476 #include <QtCore/QDateTime>
477 #include <QtCore/QSortFilterProxyModel>
478 #include <QtCore/QString>
479+#include <QtCore/QUrl>
480
481 class HistoryTimeframeModel;
482
483@@ -33,6 +34,8 @@
484 Q_PROPERTY(HistoryTimeframeModel* sourceModel READ sourceModel WRITE setSourceModel NOTIFY sourceModelChanged)
485 Q_PROPERTY(QString domain READ domain WRITE setDomain NOTIFY domainChanged)
486 Q_PROPERTY(QDateTime lastVisit READ lastVisit NOTIFY lastVisitChanged)
487+ Q_PROPERTY(QString lastVisitedTitle READ lastVisitedTitle NOTIFY lastVisitedTitleChanged)
488+ Q_PROPERTY(QUrl lastVisitedIcon READ lastVisitedIcon NOTIFY lastVisitedIconChanged)
489
490 public:
491 HistoryDomainModel(QObject* parent=0);
492@@ -44,11 +47,15 @@
493 void setDomain(const QString& domain);
494
495 const QDateTime& lastVisit() const;
496+ const QString& lastVisitedTitle() const;
497+ const QUrl& lastVisitedIcon() const;
498
499 Q_SIGNALS:
500 void sourceModelChanged() const;
501 void domainChanged() const;
502 void lastVisitChanged() const;
503+ void lastVisitedTitleChanged() const;
504+ void lastVisitedIconChanged() const;
505
506 protected:
507 // reimplemented from QSortFilterProxyModel
508@@ -57,6 +64,8 @@
509 private:
510 QString m_domain;
511 QDateTime m_lastVisit;
512+ QString m_lastVisitedTitle;
513+ QUrl m_lastVisitedIcon;
514
515 private Q_SLOTS:
516 void onModelChanged();
517
518=== modified file 'src/app/webbrowser/history-domainlist-model.cpp'
519--- src/app/webbrowser/history-domainlist-model.cpp 2014-05-22 15:32:52 +0000
520+++ src/app/webbrowser/history-domainlist-model.cpp 2014-07-17 13:31:54 +0000
521@@ -51,6 +51,9 @@
522 if (roles.isEmpty()) {
523 roles[Domain] = "domain";
524 roles[LastVisit] = "lastVisit";
525+ roles[LastVisitDate] = "lastVisitDate";
526+ roles[LastVisitedTitle] = "lastVisitedTitle";
527+ roles[LastVisitedIcon] = "lastVisitedIcon";
528 roles[Entries] = "entries";
529 }
530 return roles;
531@@ -75,6 +78,12 @@
532 return domain;
533 case LastVisit:
534 return entries->lastVisit();
535+ case LastVisitDate:
536+ return entries->lastVisit().date();
537+ case LastVisitedTitle:
538+ return entries->lastVisitedTitle();
539+ case LastVisitedIcon:
540+ return entries->lastVisitedIcon();
541 case Entries:
542 return QVariant::fromValue(entries);
543 default:
544
545=== modified file 'src/app/webbrowser/history-domainlist-model.h'
546--- src/app/webbrowser/history-domainlist-model.h 2014-03-12 10:59:54 +0000
547+++ src/app/webbrowser/history-domainlist-model.h 2014-07-17 13:31:54 +0000
548@@ -42,6 +42,9 @@
549 enum Roles {
550 Domain = Qt::UserRole + 1,
551 LastVisit,
552+ LastVisitDate,
553+ LastVisitedTitle,
554+ LastVisitedIcon,
555 Entries
556 };
557
558
559=== modified file 'src/app/webbrowser/history-model.cpp'
560--- src/app/webbrowser/history-model.cpp 2014-05-22 15:32:52 +0000
561+++ src/app/webbrowser/history-model.cpp 2014-07-17 13:31:54 +0000
562@@ -130,6 +130,7 @@
563 roles[Icon] = "icon";
564 roles[Visits] = "visits";
565 roles[LastVisit] = "lastVisit";
566+ roles[LastVisitDate] = "lastVisitDate";
567 }
568 return roles;
569 }
570@@ -159,6 +160,8 @@
571 return entry.visits;
572 case LastVisit:
573 return entry.lastVisit;
574+ case LastVisitDate:
575+ return entry.lastVisit.date();
576 default:
577 return QVariant();
578 }
579
580=== modified file 'src/app/webbrowser/history-model.h'
581--- src/app/webbrowser/history-model.h 2014-05-22 15:32:52 +0000
582+++ src/app/webbrowser/history-model.h 2014-07-17 13:31:54 +0000
583@@ -45,7 +45,8 @@
584 Title,
585 Icon,
586 Visits,
587- LastVisit
588+ LastVisit,
589+ LastVisitDate,
590 };
591
592 // reimplemented from QAbstractListModel

Subscribers

People subscribed via source and target branches

to status/vote changes: