Merge lp:~verzegnassi-stefano/ubuntu-docviewer-app/document-page-filters into lp:ubuntu-docviewer-app/trunk

Proposed by Stefano Verzegnassi on 2015-06-12
Status: Merged
Approved by: Alan Pope 🍺🐧🐱 πŸ¦„ on 2015-06-23
Approved revision: 157
Merged at revision: 152
Proposed branch: lp:~verzegnassi-stefano/ubuntu-docviewer-app/document-page-filters
Merge into: lp:ubuntu-docviewer-app/trunk
Diff against target: 848 lines (+540/-62)
11 files modified
po/com.ubuntu.docviewer.pot (+81/-20)
src/app/graphics/settings_alt.svg (+138/-0)
src/app/qml/documentPage/DocumentGridView.qml (+8/-0)
src/app/qml/documentPage/DocumentListDelegate.qml (+36/-11)
src/app/qml/documentPage/DocumentListView.qml (+46/-14)
src/app/qml/documentPage/DocumentPage.qml (+17/-6)
src/app/qml/documentPage/DocumentPageDefaultHeader.qml (+27/-8)
src/app/qml/documentPage/DocumentPageSearchHeader.qml (+57/-0)
src/app/qml/documentPage/SearchEmptyState.qml (+32/-0)
src/app/qml/documentPage/SortSettingsDialog.qml (+57/-0)
src/app/qml/ubuntu-docviewer-app.qml (+41/-3)
To merge this branch: bzr merge lp:~verzegnassi-stefano/ubuntu-docviewer-app/document-page-filters
Reviewer Review Type Date Requested Status
Alan Pope 🍺🐧🐱 πŸ¦„ 2015-06-12 Approve on 2015-06-22
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve on 2015-06-22
Review via email: mp+261858@code.launchpad.net

Commit Message

Added a search mode for the DocumentPage and a list of sorting options.

Description of the Change

This MP adds a "search" mode for the DocumentPage and a list of sorting options.

The available options are:
- Sort by name
- Sort by date (default)
- Sort by size

The search filter is reset when docviewer receives a request for exporting a document via Content Hub.

A further empty state is shown when the search returns no result.

----------
I'm also interested in getting some opinion about the following questions:

1) Is it ok to use a Dialog to provide these settings?
2) I reused an earlier "settings" icon from the Suru icon theme, since there's no icon for "sort". Is there anything better out there that we can use?
3) Is my English good? :-P Please check for any error in the dialog or in the empty state.

To post a comment you must log in.

Overall it's great, I really like being able to sort the documents now.

A few observations:-

* With more buttons in the taskbar, we truncate the app name further. On the bq e4.5 it's "Document Vie..." in portrait mode. I'm wondering if we should consider truncating it down to just "Viewer"?

* The alphabetical sort order seems to be A-Z then a-z. So a document starting with a lower case "p" appears after a document with upper case "Y" which is confusing to people who don't know how standard sorting on Linux works. Perhaps we should aggregate the sort so docs are grouped together - e.g. docs starting with lower "p" and "P" together?

* I managed to crash the app if I scroll to the bottom of the list, then change the sort order from "Sort by date" to "Sort by name". I have 21 docs locally, and 7 docs on SD card, so not a huge number. Only seems to crash if I'm at the bottom of the list.

* When changing the sort order, should we jump to the top of the list? Seems strange to change the sort order and be left in the middle.

> * With more buttons in the taskbar, we truncate the app name further. On the
> bq e4.5 it's "Document Vie..." in portrait mode. I'm wondering if we should
> consider truncating it down to just "Viewer"?

"Viewer" sounds a bit generic to me. I'd prefer to switch the title of the page to "Documents", so that the purpose of the app is still understandable ("Viewer" could refers also to other formats - e.g. images - which we don't support).

> * The alphabetical sort order seems to be A-Z then a-z. So a document starting
> with a lower case "p" appears after a document with upper case "Y" which is
> confusing to people who don't know how standard sorting on Linux works.
> Perhaps we should aggregate the sort so docs are grouped together - e.g. docs
> starting with lower "p" and "P" together?

Huh, right. This urges a fix. I forgot to set the "sortCaseSensitivity" property to Qt.CaseInsensitive.

> * I managed to crash the app if I scroll to the bottom of the list, then
> change the sort order from "Sort by date" to "Sort by name". I have 21 docs
> locally, and 7 docs on SD card, so not a huge number. Only seems to crash if
> I'm at the bottom of the list.

Will have a check, thanks.

> * When changing the sort order, should we jump to the top of the list? Seems
> strange to change the sort order and be left in the middle.

+1. I'll update the branch with a fix for this.

+1 to "Documents".

153. By Stefano Verzegnassi on 2015-06-22

Updated the title of DocumentPage

154. By Stefano Verzegnassi on 2015-06-22

Fixed case sensitivity for alphabetic sort

155. By Stefano Verzegnassi on 2015-06-22

Fixed date-time of the subText of the DocumentListDelegate (dateDiff value changed when we started to use an Enum for it)

156. By Stefano Verzegnassi on 2015-06-22

Fixed badly formatted date-time in the subText of DocumentListDelegate when a sort rule, different than 'by date' is used.

157. By Stefano Verzegnassi on 2015-06-22

Position view at beginning when the sortMode value is changed

* Update title to "Documents"
Done.

* Perhaps we should aggregate the sort so docs are grouped together - e.g. docs starting with lower "p" and "P" together?
Done.

* I managed to crash the app if I scroll to the bottom of the list, then change the sort order from "Sort by date" to "Sort by name". I have 21 docs locally, and 7 docs on SD card, so not a huge number. Only seems to crash if I'm at the bottom of the list.
I've tried to reproduce this on my desktop (Ubuntu 15.04 and ubuntu-sdk-team PPA). I've also mount an additional drive in order to emulate the SD card presence.
I've seen no crash: could you please make a second attempt with the latest commit?

* When changing the sort order, should we jump to the top of the list? Seems strange to change the sort order and be left in the middle.
Done.

Also, I've fixed an issue with the date-time shown in the ListView delegate. With the revision 143, I changed the values for the "dateDiff" role of DocumentsModel, but the logic that generates the date-time strings hasn't been updated.

Moreover, now we also show the right date-time string for any of the implemented sortModes (e.g. when sorting by name, we don't have a "Today" or "This week" section header. The string is now properly set as "Today, hh:mm" and not a generic "hh:mm").

Tested on my bq E4.5 and it works really nicely. I couldn't reproduce the crash any more and the sort order looks better. Thanks Stefano!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'po/com.ubuntu.docviewer.pot'
2--- po/com.ubuntu.docviewer.pot 2015-05-19 12:06:27 +0000
3+++ po/com.ubuntu.docviewer.pot 2015-06-22 17:06:51 +0000
4@@ -8,7 +8,7 @@
5 msgstr ""
6 "Project-Id-Version: \n"
7 "Report-Msgid-Bugs-To: \n"
8-"POT-Creation-Date: 2015-05-19 14:05+0200\n"
9+"POT-Creation-Date: 2015-06-22 19:03+0200\n"
10 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
11 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12 "Language-Team: LANGUAGE <LL@li.org>\n"
13@@ -33,8 +33,7 @@
14 msgstr ""
15
16 #: ../src/app/docviewer-application.cpp:171
17-#: ../src/app/qml/documentPage/DocumentPage.qml:25
18-#: /home/stefano/tmp/build-sdcard-read-support-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:1
19+#: /home/stefano/Progetti/docviewer/build-document-page-filters-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:1
20 msgid "Document Viewer"
21 msgstr ""
22
23@@ -76,6 +75,7 @@
24 #: ../src/app/qml/common/PickImportedDialog.qml:47
25 #: ../src/app/qml/common/RejectedImportDialog.qml:38
26 #: ../src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml:32
27+#: ../src/app/qml/documentPage/SortSettingsDialog.qml:53
28 #: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:61
29 #: ../src/app/qml/textView/TextViewDefaultHeader.qml:61
30 msgid "Close"
31@@ -203,43 +203,70 @@
32 #. TRANSLATORS: this is a datetime formatting string,
33 #. see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
34 #: ../src/app/qml/documentPage/DocumentGridDelegate.qml:45
35-#: ../src/app/qml/documentPage/DocumentListDelegate.qml:36
36+#: ../src/app/qml/documentPage/DocumentListDelegate.qml:58
37 msgid "dddd, hh:mm"
38 msgstr ""
39
40 #. TRANSLATORS: this is a datetime formatting string,
41 #. see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
42 #: ../src/app/qml/documentPage/DocumentGridDelegate.qml:49
43-#: ../src/app/qml/documentPage/DocumentListDelegate.qml:40
44+#: ../src/app/qml/documentPage/DocumentListDelegate.qml:47
45+#: ../src/app/qml/documentPage/DocumentListDelegate.qml:63
46 msgid "dd-MM-yyyy hh:mm"
47 msgstr ""
48
49-#: ../src/app/qml/documentPage/DocumentListView.qml:136
50+#. TRANSLATORS: this is a datetime formatting string, and the
51+#. singlequote is an escape character.
52+#. See http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
53+#: ../src/app/qml/documentPage/DocumentListDelegate.qml:36
54+msgid "'Today', hh:mm"
55+msgstr ""
56+
57+#. TRANSLATORS: this is a datetime formatting string, and the
58+#. singlequote is an escape character.
59+#. See http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
60+#: ../src/app/qml/documentPage/DocumentListDelegate.qml:42
61+msgid "'Yesterday', hh:mm"
62+msgstr ""
63+
64+#: ../src/app/qml/documentPage/DocumentListView.qml:157
65 msgid "Today"
66 msgstr ""
67
68-#: ../src/app/qml/documentPage/DocumentListView.qml:139
69+#: ../src/app/qml/documentPage/DocumentListView.qml:160
70 msgid "Yesterday"
71 msgstr ""
72
73-#: ../src/app/qml/documentPage/DocumentListView.qml:142
74+#: ../src/app/qml/documentPage/DocumentListView.qml:163
75 msgid "Earlier this week"
76 msgstr ""
77
78-#: ../src/app/qml/documentPage/DocumentListView.qml:145
79+#: ../src/app/qml/documentPage/DocumentListView.qml:166
80 msgid "Earlier this month"
81 msgstr ""
82
83-#: ../src/app/qml/documentPage/DocumentListView.qml:147
84+#: ../src/app/qml/documentPage/DocumentListView.qml:168
85 msgid "Even earlier..."
86 msgstr ""
87
88-#: ../src/app/qml/documentPage/DocumentPageDefaultHeader.qml:28
89+#: ../src/app/qml/documentPage/DocumentPage.qml:24
90+msgid "Documents"
91+msgstr ""
92+
93+#: ../src/app/qml/documentPage/DocumentPageDefaultHeader.qml:29
94+msgid "Search..."
95+msgstr ""
96+
97+#: ../src/app/qml/documentPage/DocumentPageDefaultHeader.qml:37
98+msgid "Sorting settings..."
99+msgstr ""
100+
101+#: ../src/app/qml/documentPage/DocumentPageDefaultHeader.qml:46
102 #: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:35
103 msgid "Switch to single column list"
104 msgstr ""
105
106-#: ../src/app/qml/documentPage/DocumentPageDefaultHeader.qml:28
107+#: ../src/app/qml/documentPage/DocumentPageDefaultHeader.qml:46
108 #: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:35
109 msgid "Switch to grid"
110 msgstr ""
111@@ -248,6 +275,16 @@
112 msgid "Pick"
113 msgstr ""
114
115+#: ../src/app/qml/documentPage/DocumentPageSearchHeader.qml:27
116+#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:61
117+#: ../src/app/qml/textView/TextViewDefaultHeader.qml:61
118+msgid "Back"
119+msgstr ""
120+
121+#: ../src/app/qml/documentPage/DocumentPageSearchHeader.qml:47
122+msgid "search in documents..."
123+msgstr ""
124+
125 #: ../src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml:52
126 msgid "Select None"
127 msgstr ""
128@@ -256,6 +293,35 @@
129 msgid "Select All"
130 msgstr ""
131
132+#: ../src/app/qml/documentPage/SearchEmptyState.qml:24
133+msgid "No matching document found"
134+msgstr ""
135+
136+#: ../src/app/qml/documentPage/SearchEmptyState.qml:26
137+msgid ""
138+"Please ensure that your query is not misspelled and/or try a different query."
139+msgstr ""
140+
141+#: ../src/app/qml/documentPage/SortSettingsDialog.qml:26
142+msgid "Sorting settings"
143+msgstr ""
144+
145+#: ../src/app/qml/documentPage/SortSettingsDialog.qml:31
146+msgid "Sort by date (Latest first)"
147+msgstr ""
148+
149+#: ../src/app/qml/documentPage/SortSettingsDialog.qml:32
150+msgid "Sort by name (A-Z)"
151+msgstr ""
152+
153+#: ../src/app/qml/documentPage/SortSettingsDialog.qml:33
154+msgid "Sort by size (Smaller first)"
155+msgstr ""
156+
157+#: ../src/app/qml/documentPage/SortSettingsDialog.qml:47
158+msgid "Reverse order"
159+msgstr ""
160+
161 #. TRANSLATORS: "Contents" refers to the "Table of Contents" of a PDF document.
162 #: ../src/app/qml/pdfView/PdfContentsPage.qml:32
163 #: ../src/app/qml/pdfView/PdfView.qml:37
164@@ -273,11 +339,6 @@
165 msgid "Page %1 of %2"
166 msgstr ""
167
168-#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:61
169-#: ../src/app/qml/textView/TextViewDefaultHeader.qml:61
170-msgid "Back"
171-msgstr ""
172-
173 #: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:85
174 msgid "Go to page..."
175 msgstr ""
176@@ -309,16 +370,16 @@
177 msgid "Loading..."
178 msgstr ""
179
180-#: ../src/app/qml/ubuntu-docviewer-app.qml:202
181+#: ../src/app/qml/ubuntu-docviewer-app.qml:240
182 msgid "Document successfully imported!"
183 msgid_plural "Documents successfully imported!"
184 msgstr[0] ""
185 msgstr[1] ""
186
187-#: ../src/app/qml/ubuntu-docviewer-app.qml:205
188+#: ../src/app/qml/ubuntu-docviewer-app.qml:243
189 msgid "Open"
190 msgstr ""
191
192-#: /home/stefano/tmp/build-sdcard-read-support-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:2
193+#: /home/stefano/Progetti/docviewer/build-document-page-filters-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:2
194 msgid "documents;viewer;pdf;reader;"
195 msgstr ""
196
197=== added file 'src/app/graphics/settings_alt.svg'
198--- src/app/graphics/settings_alt.svg 1970-01-01 00:00:00 +0000
199+++ src/app/graphics/settings_alt.svg 2015-06-22 17:06:51 +0000
200@@ -0,0 +1,138 @@
201+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
202+<!-- Created with Inkscape (http://www.inkscape.org/) -->
203+
204+<svg
205+ xmlns:dc="http://purl.org/dc/elements/1.1/"
206+ xmlns:cc="http://creativecommons.org/ns#"
207+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
208+ xmlns:svg="http://www.w3.org/2000/svg"
209+ xmlns="http://www.w3.org/2000/svg"
210+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
211+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
212+ width="90"
213+ height="90"
214+ id="svg3133"
215+ version="1.1"
216+ inkscape:version="0.48.3.1 r9886"
217+ sodipodi:docname="settings@30.svg">
218+ <defs
219+ id="defs3135" />
220+ <sodipodi:namedview
221+ id="base"
222+ pagecolor="#ffffff"
223+ bordercolor="#666666"
224+ borderopacity="1.0"
225+ inkscape:pageopacity="0.0"
226+ inkscape:pageshadow="2"
227+ inkscape:zoom="6.3664628"
228+ inkscape:cx="93.340685"
229+ inkscape:cy="27.377839"
230+ inkscape:document-units="px"
231+ inkscape:current-layer="g4674"
232+ showgrid="true"
233+ inkscape:window-width="1920"
234+ inkscape:window-height="1029"
235+ inkscape:window-x="0"
236+ inkscape:window-y="24"
237+ inkscape:window-maximized="1"
238+ fit-margin-top="0"
239+ fit-margin-left="0"
240+ fit-margin-right="0"
241+ fit-margin-bottom="0"
242+ showguides="true"
243+ inkscape:guide-bbox="true">
244+ <inkscape:grid
245+ type="xygrid"
246+ id="grid2992"
247+ empspacing="6"
248+ visible="true"
249+ enabled="true"
250+ snapvisiblegridlinesonly="true"
251+ originx="4.2039363e-07px"
252+ originy="0px" />
253+ <sodipodi:guide
254+ orientation="1,0"
255+ position="45,11"
256+ id="guide3763" />
257+ <sodipodi:guide
258+ orientation="0,1"
259+ position="48,45"
260+ id="guide3765" />
261+ </sodipodi:namedview>
262+ <metadata
263+ id="metadata3138">
264+ <rdf:RDF>
265+ <cc:Work
266+ rdf:about="">
267+ <dc:format>image/svg+xml</dc:format>
268+ <dc:type
269+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
270+ <dc:title />
271+ </cc:Work>
272+ </rdf:RDF>
273+ </metadata>
274+ <g
275+ inkscape:label="Layer 1"
276+ inkscape:groupmode="layer"
277+ id="layer1"
278+ transform="translate(4.2039363e-7,-962.3622)">
279+ <g
280+ id="g4978"
281+ transform="matrix(0.99934414,0,0,1,-106.92982,549.00002)">
282+ <g
283+ id="g4674"
284+ transform="matrix(1.0006563,0,0,1,-155.17195,-2.6171874e-6)">
285+ <rect
286+ y="431.36218"
287+ x="262"
288+ height="72"
289+ width="72"
290+ id="rect4869"
291+ style="opacity:0.01000001;color:#000000;fill:none;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
292+ <path
293+ style="color:#000000;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
294+ d="m 320.5,419.36218 c 6.5,0 7.49965,0 7.49979,7 l 2.1e-4,10 c 1.5e-4,7 -1,7 -7.5,7 -6.5,0 -7.50015,0 -7.5,-7 l 2.1e-4,-9.99997 c 1.4e-4,-7.00003 0.99979,-7.00003 7.49979,-7.00003 z"
295+ id="rect4871"
296+ inkscape:connector-curvature="0"
297+ sodipodi:nodetypes="zsszssz" />
298+ <path
299+ style="color:#000000;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
300+ d="m 262,428.36218 0,6 45,0 0,-6 z m 72,0 0,6 18,0 0,-6 z"
301+ id="rect4882"
302+ inkscape:connector-curvature="0"
303+ sodipodi:nodetypes="cccccccccc" />
304+ <path
305+ id="path4887"
306+ d="m 262,455.36218 0,6 18,0 0,-6 z m 45,0 0,6 45,0 0,-6 z"
307+ style="color:#000000;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
308+ inkscape:connector-curvature="0"
309+ sodipodi:nodetypes="cccccccccc" />
310+ <path
311+ sodipodi:nodetypes="cccccccccc"
312+ inkscape:connector-curvature="0"
313+ style="color:#000000;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
314+ d="m 262,482.36218 0,6 45,0 0,-6 z m 72,0 0,6 18,0 0,-6 z"
315+ id="path4889" />
316+ <rect
317+ y="413.36218"
318+ x="262"
319+ height="90"
320+ width="90"
321+ id="rect2993"
322+ style="color:#000000;fill:none;stroke:none;stroke-width:11.80000019;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
323+ <path
324+ sodipodi:nodetypes="zsszssz"
325+ inkscape:connector-curvature="0"
326+ id="path3775"
327+ d="m 293.5,446.36218 c 6.5,0 7.49965,0 7.49979,7 l 2.1e-4,10 c 1.5e-4,7 -1,7 -7.5,7 -6.5,0 -7.50015,0 -7.5,-7 l 2.1e-4,-9.99997 c 1.4e-4,-7.00003 0.99979,-7.00003 7.49979,-7.00003 z"
328+ style="color:#000000;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
329+ <path
330+ style="color:#000000;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
331+ d="m 320.5,473.36218 c 6.5,0 7.49965,0 7.49979,7 l 2.1e-4,10 c 1.5e-4,7 -1,7 -7.5,7 -6.5,0 -7.50015,0 -7.5,-7 l 2.1e-4,-9.99997 c 1.4e-4,-7.00003 0.99979,-7.00003 7.49979,-7.00003 z"
332+ id="path3777"
333+ inkscape:connector-curvature="0"
334+ sodipodi:nodetypes="zsszssz" />
335+ </g>
336+ </g>
337+ </g>
338+</svg>
339
340=== modified file 'src/app/qml/documentPage/DocumentGridView.qml'
341--- src/app/qml/documentPage/DocumentGridView.qml 2015-04-29 15:23:32 +0000
342+++ src/app/qml/documentPage/DocumentGridView.qml 2015-06-22 17:06:51 +0000
343@@ -72,5 +72,13 @@
344 parent: documentGridView.parent
345 }
346
347+ Connections {
348+ target: sortSettings
349+
350+ onSortModeChanged: {
351+ documentGridView.positionViewAtBeginning()
352+ }
353+ }
354+
355 Component.onCompleted: { if (DOC_VIEWER.pickModeEnabled) documentGridView.startSelection(); }
356 }
357
358=== modified file 'src/app/qml/documentPage/DocumentListDelegate.qml'
359--- src/app/qml/documentPage/DocumentListDelegate.qml 2015-05-13 14:22:36 +0000
360+++ src/app/qml/documentPage/DocumentListDelegate.qml 2015-06-22 17:06:51 +0000
361@@ -27,17 +27,42 @@
362 var date = new Date(model.date)
363 var diff = model.dateDiff
364
365- if (diff < 2)
366- return Qt.formatDateTime(date, Qt.locale().timeFormat(Locale.ShortFormat))
367-
368- if (diff < 7)
369- // TRANSLATORS: this is a datetime formatting string,
370- // see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
371- return Qt.formatDateTime(date, i18n.tr("dddd, hh:mm"))
372-
373- // TRANSLATORS: this is a datetime formatting string,
374- // see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
375- return Qt.formatDateTime(date, i18n.tr("dd-MM-yyyy hh:mm"))
376+ if (sortSettings.sortMode !== 0) { // The sort rule is not "by date"
377+ switch(diff) {
378+ case 0: // DocumentsModel.Today
379+ // TRANSLATORS: this is a datetime formatting string, and the
380+ // singlequote is an escape character.
381+ // See http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
382+ return Qt.formatDateTime(date, i18n.tr("'Today', hh:mm"))
383+
384+ case 1: // DocumentsModel.Yesterday
385+ // TRANSLATORS: this is a datetime formatting string, and the
386+ // singlequote is an escape character.
387+ // See http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
388+ return Qt.formatDateTime(date, i18n.tr("'Yesterday', hh:mm"))
389+
390+ default: // DocumentsModel.LastWeek || DocumentsModel.LastMonth || DocumentsModel.Earlier
391+ // TRANSLATORS: this is a datetime formatting string,
392+ // see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
393+ return Qt.formatDateTime(date, i18n.tr("dd-MM-yyyy hh:mm"))
394+ }
395+ } else {
396+ switch(diff) {
397+ case 0: // DocumentsModel.Today, or
398+ case 1: // DocumentsModel.Yesterday
399+ return Qt.formatDateTime(date, Qt.locale().timeFormat(Locale.ShortFormat))
400+
401+ case 2: // DocumentsModel.LastWeek
402+ // TRANSLATORS: this is a datetime formatting string,
403+ // see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
404+ return Qt.formatDateTime(date, i18n.tr("dddd, hh:mm"))
405+
406+ default: // DocumentsModel.LastMonth || DocumentsModel.Earlier
407+ // TRANSLATORS: this is a datetime formatting string,
408+ // see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
409+ return Qt.formatDateTime(date, i18n.tr("dd-MM-yyyy hh:mm"))
410+ }
411+ }
412 }
413
414 anchors { left: parent.left; right: parent.right }
415
416=== modified file 'src/app/qml/documentPage/DocumentListView.qml'
417--- src/app/qml/documentPage/DocumentListView.qml 2015-04-29 15:58:13 +0000
418+++ src/app/qml/documentPage/DocumentListView.qml 2015-06-22 17:06:51 +0000
419@@ -129,22 +129,46 @@
420
421 listModel: folderModel
422
423- section.property: "dateDiff"
424+ section.property: {
425+ switch (sortSettings.sortMode) {
426+ case 0: // sort by date
427+ return "dateDiff"
428+ case 1: // sort by name
429+ return "name"
430+ default: // sort by size -> do not show section header
431+ return ""
432+ }
433+ }
434+
435+ section.criteria: {
436+ if (sortSettings.sortMode === 1) // sort by name
437+ return ViewSection.FirstCharacter
438+
439+ return ViewSection.FullString
440+ }
441+
442 section.delegate: ListItem.Header {
443 text: {
444- if (section == DocumentsModel.Today)
445- return i18n.tr("Today")
446-
447- if (section == DocumentsModel.Yesterday)
448- return i18n.tr("Yesterday")
449-
450- if (section == DocumentsModel.LastWeek)
451- return i18n.tr("Earlier this week")
452-
453- if (section == DocumentsModel.LastMonth)
454- return i18n.tr("Earlier this month")
455-
456- return i18n.tr("Even earlier...")
457+ if (sortSettings.sortMode === 1) // sort by name
458+ return section.toUpperCase()
459+
460+ if (sortSettings.sortMode === 0) { // sort by date
461+ if (section == DocumentsModel.Today)
462+ return i18n.tr("Today")
463+
464+ if (section == DocumentsModel.Yesterday)
465+ return i18n.tr("Yesterday")
466+
467+ if (section == DocumentsModel.LastWeek)
468+ return i18n.tr("Earlier this week")
469+
470+ if (section == DocumentsModel.LastMonth)
471+ return i18n.tr("Earlier this month")
472+
473+ return i18n.tr("Even earlier...")
474+ }
475+
476+ return ""
477 }
478 }
479
480@@ -153,5 +177,13 @@
481 parent: documentListView.parent
482 }
483
484+ Connections {
485+ target: sortSettings
486+
487+ onSortModeChanged: {
488+ documentListView.positionViewAtBeginning()
489+ }
490+ }
491+
492 Component.onCompleted: { if (DOC_VIEWER.pickModeEnabled) documentListView.startSelection(); }
493 }
494
495=== modified file 'src/app/qml/documentPage/DocumentPage.qml'
496--- src/app/qml/documentPage/DocumentPage.qml 2015-05-13 14:22:36 +0000
497+++ src/app/qml/documentPage/DocumentPage.qml 2015-06-22 17:06:51 +0000
498@@ -16,16 +16,16 @@
499
500 import QtQuick 2.0
501 import Ubuntu.Components 1.1
502-import Ubuntu.Components.Popups 1.0
503 import Qt.labs.settings 1.0
504
505 Page {
506 id: documentPage
507
508- title: i18n.tr("Document Viewer")
509+ title: i18n.tr("Documents")
510 flickable: null
511
512 property bool useGridView: false
513+ property bool searchMode: false
514 property alias view: viewLoader
515
516 onActiveChanged: {
517@@ -43,9 +43,10 @@
518 id: viewLoader
519 anchors.fill: parent
520
521- source: (folderModel.count === 0) ? Qt.resolvedUrl("./DocumentEmptyState.qml")
522- : useGridView ? Qt.resolvedUrl("./DocumentGridView.qml")
523- : Qt.resolvedUrl("./DocumentListView.qml")
524+ source: (folderModel.count === 0) ? documentPage.state == "search" ? Qt.resolvedUrl("./SearchEmptyState.qml")
525+ : Qt.resolvedUrl("./DocumentEmptyState.qml")
526+ : useGridView ? Qt.resolvedUrl("./DocumentGridView.qml")
527+ : Qt.resolvedUrl("./DocumentListView.qml")
528 }
529
530 // *** HEADER ***
531@@ -53,7 +54,7 @@
532 DocumentPageDefaultHeader {
533 name: "default"
534 targetPage: documentPage
535- when: !mainView.pickMode && !viewLoader.item.isInSelectionMode
536+ when: !mainView.pickMode && !viewLoader.item.isInSelectionMode && !documentPage.searchMode
537 },
538
539 DocumentPagePickModeHeader {
540@@ -66,6 +67,12 @@
541 name: "selection"
542 targetPage: documentPage
543 when: !mainView.pickMode && viewLoader.item.isInSelectionMode
544+ },
545+
546+ DocumentPageSearchHeader {
547+ name: "search"
548+ targetPage: documentPage
549+ when: !mainView.pickMode && !viewLoader.item.isInSelectionMode && documentPage.searchMode
550 }
551 ]
552
553@@ -78,6 +85,10 @@
554 } else {
555 viewLoader.item.cancelSelection()
556 }
557+
558+ // Reset any previous search
559+ documentPage.searchMode = false
560+ folderModel.search("") // Empty search, reset filter.
561 }
562 }
563 }
564
565=== modified file 'src/app/qml/documentPage/DocumentPageDefaultHeader.qml'
566--- src/app/qml/documentPage/DocumentPageDefaultHeader.qml 2015-03-03 15:41:11 +0000
567+++ src/app/qml/documentPage/DocumentPageDefaultHeader.qml 2015-06-22 17:06:51 +0000
568@@ -16,6 +16,7 @@
569
570 import QtQuick 2.3
571 import Ubuntu.Components 1.1
572+import Ubuntu.Components.Popups 1.0
573
574 PageHeadState {
575 id: rootItem
576@@ -23,12 +24,30 @@
577 property Page targetPage
578 head: targetPage.head
579
580- actions: Action {
581- id: switchView
582- text: targetPage.useGridView ? i18n.tr("Switch to single column list") : i18n.tr("Switch to grid")
583- iconName: targetPage.useGridView ? "view-list-symbolic" : "view-grid-symbolic"
584- onTriggered: targetPage.useGridView = !targetPage.useGridView
585-
586- visible: folderModel.count !== 0
587- }
588+ actions: [
589+ Action {
590+ text: i18n.tr("Search...")
591+ iconName: "search"
592+ onTriggered: targetPage.searchMode = true
593+
594+ visible: folderModel.count !== 0
595+ },
596+
597+ Action {
598+ text: i18n.tr("Sorting settings...")
599+ iconSource: Qt.resolvedUrl("../../graphics/settings_alt.svg")
600+ onTriggered: PopupUtils.open(Qt.resolvedUrl("SortSettingsDialog.qml"))
601+
602+ visible: folderModel.count !== 0
603+ },
604+
605+ Action {
606+ id: switchView
607+ text: targetPage.useGridView ? i18n.tr("Switch to single column list") : i18n.tr("Switch to grid")
608+ iconName: targetPage.useGridView ? "view-list-symbolic" : "view-grid-symbolic"
609+ onTriggered: targetPage.useGridView = !targetPage.useGridView
610+
611+ visible: folderModel.count !== 0
612+ }
613+ ]
614 }
615
616=== added file 'src/app/qml/documentPage/DocumentPageSearchHeader.qml'
617--- src/app/qml/documentPage/DocumentPageSearchHeader.qml 1970-01-01 00:00:00 +0000
618+++ src/app/qml/documentPage/DocumentPageSearchHeader.qml 2015-06-22 17:06:51 +0000
619@@ -0,0 +1,57 @@
620+/*
621+ * Copyright (C) 2014-2015 Canonical, Ltd.
622+ *
623+ * This program is free software; you can redistribute it and/or modify
624+ * it under the terms of the GNU General Public License as published by
625+ * the Free Software Foundation; version 3.
626+ *
627+ * This program is distributed in the hope that it will be useful,
628+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
629+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
630+ * GNU General Public License for more details.
631+ *
632+ * You should have received a copy of the GNU General Public License
633+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
634+ */
635+
636+import QtQuick 2.3
637+import Ubuntu.Components 1.1
638+
639+PageHeadState {
640+ id: rootItem
641+
642+ property Page targetPage
643+ head: targetPage.head
644+
645+ backAction: Action {
646+ text: i18n.tr("Back")
647+ iconName: "back"
648+
649+ onTriggered: {
650+ // Clear the search
651+ searchField.text = ""
652+ targetPage.searchMode = false
653+ }
654+ }
655+
656+ contents: TextField {
657+ id: searchField
658+ width: parent.width - units.gu(4)
659+
660+ primaryItem: Icon {
661+ height: parent.height - units.gu(2)
662+ width: height
663+ name: "search"
664+ }
665+
666+ placeholderText: i18n.tr("search in documents...")
667+ onTextChanged: folderModel.search(text)
668+
669+ // Disable predictive text
670+ inputMethodHints: Qt.ImhNoPredictiveText
671+
672+ // Force active focus when this becomes the current PageHead state and
673+ // show OSK if appropriate.
674+ onVisibleChanged: forceActiveFocus()
675+ }
676+}
677
678=== added file 'src/app/qml/documentPage/SearchEmptyState.qml'
679--- src/app/qml/documentPage/SearchEmptyState.qml 1970-01-01 00:00:00 +0000
680+++ src/app/qml/documentPage/SearchEmptyState.qml 2015-06-22 17:06:51 +0000
681@@ -0,0 +1,32 @@
682+/*
683+ Copyright (C) 2015 Stefano Verzegnassi
684+
685+ This program is free software: you can redistribute it and/or modify
686+ it under the terms of the GNU General Public License 3 as published by
687+ the Free Software Foundation.
688+
689+ This program is distributed in the hope that it will be useful,
690+ but WITHOUT ANY WARRANTY; without even the implied warranty of
691+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
692+ GNU General Public License for more details.
693+
694+ You should have received a copy of the GNU General Public License
695+ along with this program. If not, see http://www.gnu.org/licenses/.
696+*/
697+
698+import QtQuick 2.0
699+import "../upstreamComponents"
700+
701+Item {
702+ anchors.fill: parent
703+
704+ EmptyState {
705+ title: i18n.tr("No matching document found")
706+
707+ subTitle: i18n.tr("Please ensure that your query is not misspelled and/or try a different query.")
708+ iconName: "search"
709+
710+ anchors.centerIn: parent
711+ width: parent.width
712+ }
713+}
714
715=== added file 'src/app/qml/documentPage/SortSettingsDialog.qml'
716--- src/app/qml/documentPage/SortSettingsDialog.qml 1970-01-01 00:00:00 +0000
717+++ src/app/qml/documentPage/SortSettingsDialog.qml 2015-06-22 17:06:51 +0000
718@@ -0,0 +1,57 @@
719+/*
720+ Copyright (C) 2013-2015 Stefano Verzegnassi
721+
722+ This program is free software: you can redistribute it and/or modify
723+ it under the terms of the GNU General Public License 3 as published by
724+ the Free Software Foundation, either version 3 of the License, or
725+ (at your option) any later version.
726+
727+ This program is distributed in the hope that it will be useful,
728+ but WITHOUT ANY WARRANTY; without even the implied warranty of
729+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
730+ GNU General Public License for more details.
731+
732+ You should have received a copy of the GNU General Public License
733+ along with this program. If not, see http://www.gnu.org/licenses/.
734+*/
735+
736+import QtQuick 2.0
737+import Ubuntu.Components 1.1
738+import Ubuntu.Components.Popups 1.0
739+import QtQuick.Layouts 1.0
740+
741+Dialog {
742+ id: sortSettingsDialog
743+
744+ title: i18n.tr("Sorting settings")
745+
746+ OptionSelector {
747+ expanded: true
748+ model: [
749+ i18n.tr("Sort by date (Latest first)"),
750+ i18n.tr("Sort by name (A-Z)"),
751+ i18n.tr("Sort by size (Smaller first)")
752+ ]
753+
754+ Component.onCompleted: selectedIndex = sortSettings.sortMode
755+ onSelectedIndexChanged: sortSettings.sortMode = selectedIndex
756+ }
757+
758+ RowLayout {
759+ CheckBox {
760+ Component.onCompleted: checked = sortSettings.reverseOrder
761+ onCheckedChanged: sortSettings.reverseOrder = checked
762+ }
763+
764+ Label {
765+ text: i18n.tr("Reverse order")
766+ Layout.fillWidth: true
767+ }
768+ }
769+
770+ Button {
771+ text: i18n.tr("Close")
772+ onClicked: PopupUtils.close(sortSettingsDialog)
773+ }
774+}
775+
776
777=== modified file 'src/app/qml/ubuntu-docviewer-app.qml'
778--- src/app/qml/ubuntu-docviewer-app.qml 2015-04-29 16:06:32 +0000
779+++ src/app/qml/ubuntu-docviewer-app.qml 2015-06-22 17:06:51 +0000
780@@ -19,6 +19,7 @@
781 import Ubuntu.Components.Popups 1.0
782 import DocumentViewer 1.0
783 import QtQuick.Window 2.0
784+import Qt.labs.settings 1.0
785
786 import "common"
787 import "common/loadComponent.js" as LoadComponent
788@@ -131,6 +132,12 @@
789
790 SortFilterModel {
791 id: folderModel
792+
793+ function search(pattern) {
794+ // Search the given pattern, case insensitive
795+ filter.pattern = new RegExp(pattern, 'i')
796+ }
797+
798 model: DocumentsModel {
799 id: docModel
800
801@@ -138,13 +145,44 @@
802 customDir: DOC_VIEWER.documentsDir
803 }
804
805- sort.property: "date"
806- sort.order: Qt.DescendingOrder
807- sortCaseSensitivity: Qt.CaseSensitive
808+ sort.property: {
809+ switch (sortSettings.sortMode) {
810+ case 0:
811+ return "date"
812+ case 1:
813+ return "name"
814+ case 2:
815+ return "size"
816+ default:
817+ return "date"
818+ }
819+ }
820+ sort.order: {
821+ switch (sortSettings.sortMode) {
822+ case 0: // sort by date
823+ return sortSettings.reverseOrder ? Qt.AscendingOrder : Qt.DescendingOrder
824+ case 1: // sort by name
825+ return sortSettings.reverseOrder ? Qt.DescendingOrder : Qt.AscendingOrder
826+ case 2: // sort by size
827+ return sortSettings.reverseOrder ? Qt.DescendingOrder : Qt.AscendingOrder
828+ default:
829+ return sortSettings.reverseOrder ? Qt.AscendingOrder : Qt.DescendingOrder
830+ }
831+ }
832+ sortCaseSensitivity: Qt.CaseInsensitive
833+
834+ filter.property: "name"
835 }
836
837 PageStack { id: pageStack }
838
839+ Settings {
840+ id: sortSettings
841+
842+ property int sortMode: 0 // 0 = by date, 1 = by name, 2 = by size
843+ property bool reverseOrder: false
844+ }
845+
846 Connections {
847 target: UriHandler
848 onOpened: {

Subscribers

People subscribed via source and target branches