Merge lp:~verzegnassi-stefano/quick-memo/10-misc-refactoring into lp:quick-memo

Proposed by Stefano Verzegnassi on 2015-04-26
Status: Merged
Approved by: Stefano Verzegnassi on 2015-04-26
Approved revision: 69
Merged at revision: 64
Proposed branch: lp:~verzegnassi-stefano/quick-memo/10-misc-refactoring
Merge into: lp:quick-memo
Diff against target: 6833 lines (+3352/-3035) (has conflicts)
46 files modified
CMakeLists.txt (+15/-6)
app/CMakeLists.txt (+0/-15)
app/common/ColorDialog.qml (+168/-0)
app/common/NoteModel.qml (+119/-0)
app/common/NoteTextArea.qml (+59/-0)
app/common/NoteTextField.qml (+53/-0)
app/common/PageBackground.qml (+25/-0)
app/common/PageWithBottomEdge.qml (+407/-0)
app/common/Toaster.qml (+81/-0)
app/common/dateHelper.js (+23/-0)
app/components/AboutPage.qml (+0/-206)
app/components/CMakeLists.txt (+0/-7)
app/components/ColorDialog.qml (+0/-168)
app/components/Delegate.qml (+0/-291)
app/components/EditMemoPage.qml (+0/-328)
app/components/HorizontalFlowListView.qml (+0/-78)
app/components/IconButton.qml (+0/-45)
app/components/ImageViewer.qml (+0/-130)
app/components/ListManager.qml (+0/-311)
app/components/ListViewDelegate.qml (+0/-299)
app/components/MultiSelectionHandler.qml (+0/-106)
app/components/NoteModel.qml (+0/-119)
app/components/NoteTextArea.qml (+0/-59)
app/components/NoteTextField.qml (+0/-53)
app/components/PageBackground.qml (+0/-25)
app/components/PageWithBottomEdge.qml (+0/-407)
app/components/PictureButton.qml (+0/-40)
app/components/PicturesManager.qml (+0/-162)
app/components/Toaster.qml (+0/-81)
app/components/dateHelper.js (+0/-23)
app/editPage/ListManager.qml (+313/-0)
app/editPage/PictureButton.qml (+40/-0)
app/editPage/PicturesManager.qml (+162/-0)
app/main.qml (+5/-18)
app/mainPage/Delegate.qml (+291/-0)
app/mainPage/HorizontalFlowListView.qml (+78/-0)
app/mainPage/ListViewDelegate.qml (+299/-0)
app/mainPage/MultiSelectionHandler.qml (+106/-0)
app/ubuntucomponents/CMakeLists.txt (+0/-7)
app/ui/AboutPage.qml (+206/-0)
app/ui/EditMemoPage.qml (+328/-0)
app/ui/ImageViewer.qml (+130/-0)
app/ui/MainPage.qml (+308/-0)
app_info.json.in (+0/-3)
po/CMakeLists.txt (+2/-2)
po/quick-memo.pot (+134/-46)
Conflict: can't delete app/components because it is not empty.  Not deleting.
Conflict because app/components is not versioned, but has versioned children.  Versioned directory.
Contents conflict in app/components/MainPage.qml
Text conflict in po/quick-memo.pot
To merge this branch: bzr merge lp:~verzegnassi-stefano/quick-memo/10-misc-refactoring
Reviewer Review Type Date Requested Status
Stefano Verzegnassi Pending
Review via email: mp+257481@code.launchpad.net

Commit message

General refactoring of the project:
- changed folder structures
- cleaning up the project

Description of the change

General refactoring of the project:
- changed folder structures
- cleaning up the project

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2015-04-13 20:26:48 +0000
3+++ CMakeLists.txt 2015-04-26 16:57:43 +0000
4@@ -43,6 +43,7 @@
5 set(APP_NAME quick-memo)
6 set(APP_DIR "app")
7 set(MAIN_QML "main.qml")
8+set(DESKTOP_FILE "quick-memo.desktop")
9 set(ICON "graphics/quick-memo.png")
10
11 # Set install paths
12@@ -64,6 +65,8 @@
13 configure_file(manifest.json.in ${CMAKE_CURRENT_BINARY_DIR}/manifest.json)
14 install(FILES ${CMAKE_CURRENT_BINARY_DIR}/manifest.json
15 DESTINATION ${CMAKE_INSTALL_PREFIX})
16+configure_file(manifest.json.in ${CMAKE_CURRENT_BINARY_DIR}/app_info.json)
17+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/app_info.json DESTINATION ${DATA_DIR})
18
19 install(DIRECTORY "app/graphics" DESTINATION ${DATA_DIR})
20 install(FILES "quick-memo.apparmor" DESTINATION ${DATA_DIR})
21@@ -71,12 +74,18 @@
22 install(FILES "COPYING.LGPL-3" DESTINATION ${DATA_DIR})
23 install(FILES "copyright" DESTINATION ${DATA_DIR})
24
25-# Configure app_info.json
26-configure_file(app_info.json.in ${CMAKE_CURRENT_BINARY_DIR}/app_info.json)
27-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/app_info.json DESTINATION ${DATA_DIR})
28-
29-add_subdirectory(app)
30-#add_subdirectory(backend)
31+# "App" subdirectory
32+configure_file(${DESKTOP_FILE_NAME}.in ${CMAKE_CURRENT_BINARY_DIR}/${DESKTOP_FILE_NAME}.in)
33+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${DESKTOP_FILE} DESTINATION ${DESKTOP_DIR})
34+
35+file(GLOB_RECURSE QML_JS_FILES *.qml *.js)
36+add_custom_target(quick-memo_QMlFiles ALL
37+ SOURCES ${QML_JS_FILES}
38+ COMMAND cp -r ${CMAKE_CURRENT_SOURCE_DIR}/app ${CMAKE_CURRENT_BINARY_DIR}
39+ DEPENDS ${QMLFILES}
40+)
41+install(DIRECTORY app DESTINATION ${DATA_DIR})
42+
43 add_subdirectory(po)
44
45 add_custom_target("autopilot" chmod +x ${CMAKE_SOURCE_DIR}/app/tests/autopilot/run
46
47=== removed file 'app/CMakeLists.txt'
48--- app/CMakeLists.txt 2014-11-03 00:21:23 +0000
49+++ app/CMakeLists.txt 1970-01-01 00:00:00 +0000
50@@ -1,15 +0,0 @@
51-file(GLOB QML_JS_FILES *.qml *.js)
52-
53-# make the files visible on qtcreator
54-add_custom_target(quick-memo_QMlFiles ALL SOURCES ${QML_JS_FILES})
55-
56-#substitute variables in the desktop file
57-set(DESKTOP_FILE "quick-memo.desktop")
58-configure_file(${DESKTOP_FILE_NAME}.in ${CMAKE_CURRENT_BINARY_DIR}/${DESKTOP_FILE_NAME}.in)
59-
60-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${DESKTOP_FILE} DESTINATION ${DESKTOP_DIR})
61-install(FILES ${QML_JS_FILES} DESTINATION ${APP_DIR})
62-
63-add_subdirectory(components)
64-add_subdirectory(ubuntucomponents)
65-
66
67=== added directory 'app/common'
68=== added file 'app/common/ColorDialog.qml'
69--- app/common/ColorDialog.qml 1970-01-01 00:00:00 +0000
70+++ app/common/ColorDialog.qml 2015-04-26 16:57:43 +0000
71@@ -0,0 +1,168 @@
72+/*
73+ This file is part of quick-memo
74+ Copyright (C) 2014 Stefano Verzegnassi
75+
76+ This program is free software: you can redistribute it and/or modify
77+ it under the terms of the GNU General Public License 3 as published by
78+ the Free Software Foundation.
79+
80+ This program is distributed in the hope that it will be useful,
81+ but WITHOUT ANY WARRANTY; without even the implied warranty of
82+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
83+ GNU General Public License for more details.
84+
85+ You should have received a copy of the GNU General Public License
86+ along with this program. If not, see http://www.gnu.org/licenses/.
87+*/
88+
89+import QtQuick 2.0
90+import Ubuntu.Components 1.1
91+import Ubuntu.Components.Popups 1.0
92+
93+Dialog {
94+ id: rootItem
95+
96+ title: i18n.tr("Pick a color")
97+
98+ property var colors: ["#fdfdfd", "#e9674d", "#f0a250", "#eec34f", "#aea79f", "#95c253", "#8bbee2", "#e46f8e"]
99+ property color selectedColor: colors[0]
100+
101+ property bool showTick: true
102+ property bool askConfirmation: false
103+
104+ signal colorPicked(bool isChanged)
105+
106+ onSelectedColorChanged: view.setCurrentColor()
107+ Component.onCompleted: internal.oldColor = rootItem.selectedColor
108+
109+ QtObject {
110+ id: internal
111+
112+ property color oldColor
113+ }
114+
115+ Grid {
116+ id: grid
117+ width: parent.width
118+
119+ columns: (width / cellWidth).toFixed(0)
120+
121+ property int cellHeight: units.gu(5)
122+ property int cellWidth: units.gu(5)
123+
124+ Repeater {
125+ id: view
126+
127+ width: parent.width
128+
129+ Component.onCompleted: setCurrentColor()
130+
131+ function setCurrentColor() {
132+ if (rootItem.colors) {
133+ for (var i=0; i<rootItem.colors.length; i++) {
134+ if (rootItem.colors[i] == rootItem.selectedColor) {
135+ view.currentIndex = i
136+ }
137+ }
138+ }
139+ }
140+
141+ model: rootItem.colors
142+
143+ property int currentIndex: 0
144+
145+ delegate: AbstractButton {
146+ id: delegate
147+
148+ height: grid.cellHeight
149+ width: grid.cellWidth
150+
151+ onClicked: {
152+ view.currentIndex = model.index
153+
154+ if (!rootItem.askConfirmation) {
155+ rootItem.selectedColor = rootItem.colors[view.currentIndex]
156+
157+ console.log ("Old color:", internal.oldColor, "New color:", rootItem.selectedColor)
158+ if (internal.oldColor == rootItem.selectedColor) {
159+ rootItem.colorPicked(false)
160+ } else {
161+ rootItem.colorPicked(true)
162+ }
163+
164+ rootItem.hide()
165+ }
166+ }
167+
168+ UbuntuShape {
169+ anchors { fill: parent; margins: units.gu(0.5)}
170+ color: modelData
171+ clip: true
172+
173+ Icon {
174+ id: tick
175+ anchors { fill: parent; margins: units.gu(0.5) }
176+ name: "tick"
177+ visible: view.currentIndex == model.index && rootItem.showTick
178+ color: getColor()
179+
180+ function getColor() {
181+ return Qt.rgba(1 - parseInt(modelData.substr(1,2), 16) / 255, 1 - parseInt(modelData.substr(3,2), 16) / 255, 1 - parseInt(modelData.substr(5,2), 16) / 255)
182+ }
183+ }
184+ }
185+ }
186+ }
187+ }
188+
189+ Column {
190+ width: parent.width
191+ spacing: units.gu(2)
192+
193+ Loader {
194+ width: parent.width
195+ sourceComponent: if (askConfirmation) return confirmationButtons
196+
197+ Component {
198+ id: confirmationButtons
199+ Button {
200+ width: parent.width
201+ text: i18n.tr("OK")
202+ color: UbuntuColors.orange
203+
204+ onClicked: {
205+ rootItem.selectedColor = rootItem.colors[view.currentIndex]
206+
207+ console.log ("Old color:", internal.oldColor, "New color:", rootItem.selectedColor)
208+ if (internal.oldColor == rootItem.selectedColor) {
209+ rootItem.colorPicked(false)
210+ } else {
211+ rootItem.colorPicked(true)
212+ }
213+
214+ rootItem.hide()
215+ }
216+ }
217+ }
218+ }
219+
220+ Button {
221+ width: parent.width
222+ text: i18n.tr("Cancel")
223+
224+ onClicked: {
225+ rootItem.hide()
226+
227+ for (var i=0; i<rootItem.colors.length; i++) {
228+ if (rootItem.colors[i] == internal.oldColor) {
229+ view.currentIndex = i
230+ }
231+ }
232+ rootItem.selectedColor = internal.oldColor
233+ }
234+ }
235+ }
236+
237+
238+
239+}
240
241=== added file 'app/common/NoteModel.qml'
242--- app/common/NoteModel.qml 1970-01-01 00:00:00 +0000
243+++ app/common/NoteModel.qml 2015-04-26 16:57:43 +0000
244@@ -0,0 +1,119 @@
245+/*
246+ This file is part of quick-memo
247+ Copyright (C) 2014 Stefano Verzegnassi
248+
249+ This program is free software: you can redistribute it and/or modify
250+ it under the terms of the GNU General Public License 3 as published by
251+ the Free Software Foundation.
252+
253+ This program is distributed in the hope that it will be useful,
254+ but WITHOUT ANY WARRANTY; without even the implied warranty of
255+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
256+ GNU General Public License for more details.
257+
258+ You should have received a copy of the GNU General Public License
259+ along with this program. If not, see http://www.gnu.org/licenses/.
260+*/
261+
262+import QtQuick 2.0
263+import U1db 1.0 as U1db
264+import Ubuntu.Components 1.1
265+
266+Item {
267+ id: rootItem
268+ property alias model: model
269+
270+ signal initialized()
271+
272+ // *** functions
273+ function addNote(noteTitle, noteText, noteColor, noteList, notePictures) {
274+ // Get the current date
275+ var dateString = new Date().valueOf()
276+
277+ db.putDoc(JSON.stringify({memos: {title: noteTitle, text: noteText, color: noteColor, date: dateString, list: noteList, pictures: notePictures}}))
278+ }
279+
280+ // Function used for changing a single value of the note
281+ function setNoteProperty(index, field, value) {
282+ var obj = JSON.parse(JSON.stringify(model.get(index)))
283+
284+ // Edit the required property
285+ switch(field) {
286+ case "title":
287+ obj.contents.title = value
288+ break
289+ case "text":
290+ obj.contents.text = value
291+ break
292+ case "color":
293+ // The char '#' from the hex color is not correctly parse by JSON. We add an empty string, so that it works well.
294+ obj.contents.color = "" + value
295+ break
296+ case "list":
297+ obj.contents.list = value
298+ break
299+ case "pictures":
300+ obj.contents.pictures = value
301+ }
302+
303+ // Get the current date and update the time of the last update
304+ obj.contents.date = new Date().valueOf()
305+
306+ db.putDoc(JSON.stringify({memos: obj.contents}), obj.docId)
307+ }
308+
309+ // Function used for rewriting the whole content of the note. json variant is a JSON object.
310+ function editNote(index, json) {
311+ var obj = json
312+
313+ // Get the current date and update the time of the last update
314+ obj.contents.date = new Date().valueOf()
315+
316+ console.log(JSON.stringify({memos: obj.contents}))
317+ db.putDoc(JSON.stringify({memos: obj.contents}), obj.docId)
318+ }
319+
320+
321+ function deleteNote(index) {
322+ db.deleteDoc(model.get(index).docId)
323+ }
324+
325+ function deleteNotes(indexes) {
326+ var deletedItemNumber = 0;
327+ for (var i=0; i<indexes.length; i++) {
328+ db.deleteDoc(model.get(indexes[i] - deletedItemNumber).docId)
329+ deletedItemNumber++
330+ }
331+ }
332+
333+ // *** U1db database
334+ U1db.Database {
335+ id: db
336+ path: "quick-memo"
337+ Component.onCompleted: {
338+ // TODO: Delete pictures that are not used by the notes at startup.
339+ rootItem.initialized()
340+ }
341+ }
342+
343+ // TODO: More queries, more pages, a more powerful app.
344+ // TODO: Search feature. Use "filter" from SortFilterModel?
345+ SortFilterModel {
346+ id: model
347+ sort {
348+ property: "date"
349+ order: Qt.DescendingOrder
350+ }
351+
352+ model: U1db.Query {
353+ id: query
354+ index: U1db.Index {
355+ database: db
356+ expression: ["memos.docId", "memos.title", "memos.text", "memos.color", "memos.date", "memos.list", "memos.pictures"]
357+ }
358+ query: ["*", "*", "*", "*", "*", "*", "*"]
359+ }
360+ }
361+
362+
363+}
364
365=== added file 'app/common/NoteTextArea.qml'
366--- app/common/NoteTextArea.qml 1970-01-01 00:00:00 +0000
367+++ app/common/NoteTextArea.qml 2015-04-26 16:57:43 +0000
368@@ -0,0 +1,59 @@
369+/*
370+ This file is part of quick-memo
371+ Copyright (C) 2014 Stefano Verzegnassi
372+
373+ This program is free software: you can redistribute it and/or modify
374+ it under the terms of the GNU General Public License 3 as published by
375+ the Free Software Foundation.
376+
377+ This program is distributed in the hope that it will be useful,
378+ but WITHOUT ANY WARRANTY; without even the implied warranty of
379+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
380+ GNU General Public License for more details.
381+
382+ You should have received a copy of the GNU General Public License
383+ along with this program. If not, see http://www.gnu.org/licenses/.
384+*/
385+
386+import QtQuick 2.0
387+import Ubuntu.Components 1.1
388+import Ubuntu.Components.Themes.Ambiance 0.1
389+
390+TextArea {
391+ id: rootItem
392+ width: parent.width
393+
394+ autoSize: true
395+ maximumLineCount: 0
396+
397+ // Prevent data loss
398+ inputMethodHints: Qt.ImhNoPredictiveText
399+
400+ opacity: 1.0
401+
402+ signal focusLost()
403+ signal textReallyChanged
404+
405+ property string __oldText: ""
406+ onTextChanged: {
407+ //WORKAROUND: textChanged seems to be emitted also when TextArea has the activeFocus (and text does not change).
408+ if (__oldText !== text) {
409+ rootItem.textReallyChanged()
410+ __oldText = text;
411+ }
412+ }
413+
414+ InverseMouseArea {
415+ visible: parent.activeFocus
416+ anchors.fill: parent
417+ onClicked: {
418+ rootItem.focusLost()
419+ mouse.accepted = false
420+ }
421+ }
422+
423+ style: TextAreaStyle {
424+ frameSpacing: 0
425+ background: Item { anchors.fill: parent }
426+ }
427+}
428
429=== added file 'app/common/NoteTextField.qml'
430--- app/common/NoteTextField.qml 1970-01-01 00:00:00 +0000
431+++ app/common/NoteTextField.qml 2015-04-26 16:57:43 +0000
432@@ -0,0 +1,53 @@
433+/*
434+ This file is part of quick-memo
435+ Copyright (C) 2014 Stefano Verzegnassi
436+
437+ This program is free software: you can redistribute it and/or modify
438+ it under the terms of the GNU General Public License 3 as published by
439+ the Free Software Foundation.
440+
441+ This program is distributed in the hope that it will be useful,
442+ but WITHOUT ANY WARRANTY; without even the implied warranty of
443+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
444+ GNU General Public License for more details.
445+
446+ You should have received a copy of the GNU General Public License
447+ along with this program. If not, see http://www.gnu.org/licenses/.
448+*/
449+
450+import QtQuick 2.0
451+import Ubuntu.Components 1.1
452+import Ubuntu.Components.Themes.Ambiance 0.1
453+
454+import "../ubuntucomponents" as UbuntuComponents
455+
456+// WORKAROUND: We need a 'custom' version of TextField in wait of LP:1376510 to be fixed.
457+// FIXME: Some issue with InputHandler (e.g. Keys.Down or Keys.PgDown) but we don't care it, since at the moment the main focus is not desktop.
458+UbuntuComponents.TextField {
459+ id: textArea
460+ width: parent.width - (checkBox.width + (parent.spacing * 2))
461+
462+ // Dynamic height: units.gu(3) = implicitHeight - (frameSpacing * 2)
463+ height: (contentHeight > units.gu(3)) ? contentHeight : units.gu(3)
464+
465+ wrapMode: TextInput.Wrap
466+
467+ // Prevent data loss
468+ inputMethodHints: Qt.ImhNoPredictiveText
469+
470+ signal focusLost()
471+ signal focusReceived()
472+
473+ onActiveFocusChanged: {
474+ if (activeFocus) {
475+ focusReceived()
476+ } else {
477+ focusLost()
478+ }
479+ }
480+
481+ style: TextFieldStyle {
482+ frameSpacing: 0
483+ background: Item { anchors.fill: parent }
484+ }
485+}
486
487=== added file 'app/common/PageBackground.qml'
488--- app/common/PageBackground.qml 1970-01-01 00:00:00 +0000
489+++ app/common/PageBackground.qml 2015-04-26 16:57:43 +0000
490@@ -0,0 +1,25 @@
491+import QtQuick 2.0
492+
493+// Background
494+Rectangle {
495+ id: bg
496+ anchors.fill: parent
497+ z: -10; opacity: 0.5
498+
499+ property bool __parentPageAboutToBeClosed: false
500+
501+ /* MainView clips its content, so that it does not overlap the header.
502+ We need to bypass this, using another Rectangle that specifically overlap the header. */
503+ Rectangle {
504+ parent: root.header
505+ z: -10; opacity: 0.5
506+
507+ width: root.width
508+ height: root.header.height
509+ color: bg.color
510+
511+ // FIXME: Header background should progressively change opacity to 0.0 when the BottomEdge page is dismissed.
512+ visible: !bg.__parentPageAboutToBeClosed
513+ }
514+}
515+
516
517=== added file 'app/common/PageWithBottomEdge.qml'
518--- app/common/PageWithBottomEdge.qml 1970-01-01 00:00:00 +0000
519+++ app/common/PageWithBottomEdge.qml 2015-04-26 16:57:43 +0000
520@@ -0,0 +1,407 @@
521+/*
522+ * Copyright (C) 2014 Canonical, Ltd.
523+ *
524+ * This program is free software; you can redistribute it and/or modify
525+ * it under the terms of the GNU General Public License as published by
526+ * the Free Software Foundation; version 3.
527+ *
528+ * This program is distributed in the hope that it will be useful,
529+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
530+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
531+ * GNU General Public License for more details.
532+ *
533+ * You should have received a copy of the GNU General Public License
534+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
535+ */
536+
537+/*
538+ Example:
539+
540+ MainView {
541+ objectName: "mainView"
542+
543+ applicationName: "com.ubuntu.developer.boiko.bottomedge"
544+
545+ width: units.gu(100)
546+ height: units.gu(75)
547+
548+ Component {
549+ id: pageComponent
550+
551+ PageWithBottomEdge {
552+ id: mainPage
553+ title: i18n.tr("Main Page")
554+
555+ Rectangle {
556+ anchors.fill: parent
557+ color: "white"
558+ }
559+
560+ bottomEdgePageComponent: Page {
561+ title: "Contents"
562+ anchors.fill: parent
563+ //anchors.topMargin: contentsPage.flickable.contentY
564+
565+ ListView {
566+ anchors.fill: parent
567+ model: 50
568+ delegate: ListItems.Standard {
569+ text: "One Content Item: " + index
570+ }
571+ }
572+ }
573+ bottomEdgeTitle: i18n.tr("Bottom edge action")
574+ }
575+ }
576+
577+ PageStack {
578+ id: stack
579+ Component.onCompleted: stack.push(pageComponent)
580+ }
581+ }
582+
583+*/
584+
585+import QtQuick 2.2
586+import Ubuntu.Components 1.1
587+
588+Page {
589+ id: page
590+
591+ property alias bottomEdgePageComponent: edgeLoader.sourceComponent
592+ property alias bottomEdgePageSource: edgeLoader.source
593+ property alias bottomEdgeTitle: tipLabel.text
594+ property bool bottomEdgeEnabled: true
595+ property int bottomEdgeExpandThreshold: page.height * 0.2
596+ property int bottomEdgeExposedArea: bottomEdge.state !== "expanded" ? (page.height - bottomEdge.y - bottomEdge.tipHeight) : _areaWhenExpanded
597+ property bool reloadBottomEdgePage: true
598+
599+ readonly property alias bottomEdgePage: edgeLoader.item
600+ readonly property bool isReady: ((bottomEdge.y === 0) && bottomEdgePageLoaded && edgeLoader.item.active)
601+ readonly property bool isCollapsed: (bottomEdge.y === page.height)
602+ readonly property bool bottomEdgePageLoaded: (edgeLoader.status == Loader.Ready)
603+
604+ property bool _showEdgePageWhenReady: false
605+ property int _areaWhenExpanded: 0
606+
607+ signal bottomEdgeReleased()
608+ signal bottomEdgeDismissed()
609+
610+
611+ function showBottomEdgePage(source, properties)
612+ {
613+ edgeLoader.setSource(source, properties)
614+ _showEdgePageWhenReady = true
615+ }
616+
617+ function setBottomEdgePage(source, properties)
618+ {
619+ edgeLoader.setSource(source, properties)
620+ }
621+
622+ function _pushPage()
623+ {
624+ if (edgeLoader.status === Loader.Ready) {
625+ edgeLoader.item.active = true
626+ page.pageStack.push(edgeLoader.item)
627+ if (edgeLoader.item.flickable) {
628+ edgeLoader.item.flickable.contentY = -page.header.height
629+ edgeLoader.item.flickable.returnToBounds()
630+ }
631+ if (edgeLoader.item.ready)
632+ edgeLoader.item.ready()
633+ }
634+ }
635+
636+
637+ Component.onCompleted: {
638+ // avoid a binding on the expanded height value
639+ var expandedHeight = height;
640+ _areaWhenExpanded = expandedHeight;
641+ }
642+
643+ onActiveChanged: {
644+ if (active) {
645+ bottomEdge.state = "collapsed"
646+ }
647+ }
648+
649+ onBottomEdgePageLoadedChanged: {
650+ if (_showEdgePageWhenReady && bottomEdgePageLoaded) {
651+ bottomEdge.state = "expanded"
652+ _showEdgePageWhenReady = false
653+ }
654+ }
655+
656+ Rectangle {
657+ id: bgVisual
658+
659+ color: "black"
660+ anchors.fill: page
661+ opacity: 0.7 * ((page.height - bottomEdge.y) / page.height)
662+ z: 1
663+ }
664+
665+ UbuntuShape {
666+ id: tip
667+ objectName: "bottomEdgeTip"
668+
669+ property bool hidden: (activeFocus === false) || ((bottomEdge.y - units.gu(1)) < tip.y)
670+
671+ enabled: mouseArea.enabled
672+ visible: page.bottomEdgeEnabled
673+ anchors {
674+ bottom: parent.bottom
675+ horizontalCenter: bottomEdge.horizontalCenter
676+ bottomMargin: hidden ? - height + units.gu(1) : -units.gu(1)
677+ Behavior on bottomMargin {
678+ SequentialAnimation {
679+ // wait some msecs in case of the focus change again, to avoid flickering
680+ PauseAnimation {
681+ duration: 300
682+ }
683+ UbuntuNumberAnimation {
684+ duration: UbuntuAnimation.SnapDuration
685+ }
686+ }
687+ }
688+ }
689+
690+ z: 1
691+ width: tipLabel.paintedWidth + units.gu(6)
692+ height: bottomEdge.tipHeight + units.gu(1)
693+ color: Theme.palette.normal.overlay
694+ Label {
695+ id: tipLabel
696+
697+ anchors {
698+ top: parent.top
699+ left: parent.left
700+ right: parent.right
701+ }
702+ height: bottomEdge.tipHeight
703+ verticalAlignment: Text.AlignVCenter
704+ horizontalAlignment: Text.AlignHCenter
705+ opacity: tip.hidden ? 0.0 : 1.0
706+ Behavior on opacity {
707+ UbuntuNumberAnimation {
708+ duration: UbuntuAnimation.SnapDuration
709+ }
710+ }
711+ }
712+ }
713+
714+ Rectangle {
715+ id: shadow
716+
717+ anchors {
718+ left: parent.left
719+ right: parent.right
720+ bottom: parent.bottom
721+ }
722+ height: units.gu(1)
723+ z: 1
724+ opacity: 0.0
725+ gradient: Gradient {
726+ GradientStop { position: 0.0; color: "transparent" }
727+ GradientStop { position: 1.0; color: Qt.rgba(0, 0, 0, 0.2) }
728+ }
729+ }
730+
731+ MouseArea {
732+ id: mouseArea
733+
734+ property real previousY: -1
735+ property string dragDirection: "None"
736+
737+ preventStealing: true
738+ drag {
739+ axis: Drag.YAxis
740+ target: bottomEdge
741+ minimumY: bottomEdge.pageStartY
742+ maximumY: page.height
743+ }
744+ enabled: edgeLoader.status == Loader.Ready
745+ visible: page.bottomEdgeEnabled
746+
747+ anchors {
748+ left: parent.left
749+ right: parent.right
750+ bottom: parent.bottom
751+
752+ }
753+ height: bottomEdge.tipHeight
754+ z: 1
755+
756+ onReleased: {
757+ page.bottomEdgeReleased()
758+ if ((dragDirection === "BottomToTop") &&
759+ bottomEdge.y < (page.height - bottomEdgeExpandThreshold - bottomEdge.tipHeight)) {
760+ bottomEdge.state = "expanded"
761+ } else {
762+ bottomEdge.state = "collapsed"
763+ }
764+ previousY = -1
765+ dragDirection = "None"
766+ }
767+
768+ onPressed: {
769+ previousY = mouse.y
770+ tip.forceActiveFocus()
771+ }
772+
773+ onMouseYChanged: {
774+ var yOffset = previousY - mouseY
775+ // skip if was a small move
776+ if (Math.abs(yOffset) <= units.gu(2)) {
777+ return
778+ }
779+ previousY = mouseY
780+ dragDirection = yOffset > 0 ? "BottomToTop" : "TopToBottom"
781+ }
782+ }
783+
784+ Rectangle {
785+ id: bottomEdge
786+ objectName: "bottomEdge"
787+
788+ readonly property int tipHeight: units.gu(3)
789+ readonly property int pageStartY: 0
790+
791+ z: 1
792+ color: Theme.palette.normal.background
793+ clip: true
794+ anchors {
795+ left: parent.left
796+ right: parent.right
797+ }
798+ height: page.height
799+ y: height
800+ visible: !page.isCollapsed
801+ state: "collapsed"
802+ states: [
803+ State {
804+ name: "collapsed"
805+ PropertyChanges {
806+ target: bottomEdge
807+ y: bottomEdge.height
808+ }
809+ },
810+ State {
811+ name: "expanded"
812+ PropertyChanges {
813+ target: bottomEdge
814+ y: bottomEdge.pageStartY
815+ }
816+ },
817+ State {
818+ name: "floating"
819+ when: mouseArea.drag.active
820+ PropertyChanges {
821+ target: shadow
822+ opacity: 1.0
823+ }
824+ }
825+ ]
826+
827+ transitions: [
828+ Transition {
829+ to: "expanded"
830+ SequentialAnimation {
831+ alwaysRunToEnd: true
832+
833+ SmoothedAnimation {
834+ target: bottomEdge
835+ property: "y"
836+ duration: UbuntuAnimation.FastDuration
837+ easing.type: Easing.Linear
838+ }
839+ SmoothedAnimation {
840+ target: edgeLoader
841+ property: "anchors.topMargin"
842+ to: - units.gu(4)
843+ duration: UbuntuAnimation.FastDuration
844+ easing.type: Easing.Linear
845+ }
846+ SmoothedAnimation {
847+ target: edgeLoader
848+ property: "anchors.topMargin"
849+ to: 0
850+ duration: UbuntuAnimation.FastDuration
851+ easing: UbuntuAnimation.StandardEasing
852+ }
853+ ScriptAction {
854+ script: page._pushPage()
855+ }
856+ }
857+ },
858+ Transition {
859+ from: "expanded"
860+ to: "collapsed"
861+ SequentialAnimation {
862+ alwaysRunToEnd: true
863+
864+ ScriptAction {
865+ script: {
866+ Qt.inputMethod.hide()
867+ edgeLoader.item.parent = edgeLoader
868+ edgeLoader.item.anchors.fill = edgeLoader
869+ edgeLoader.item.active = false
870+ }
871+ }
872+ SmoothedAnimation {
873+ target: bottomEdge
874+ property: "y"
875+ duration: UbuntuAnimation.SlowDuration
876+ }
877+ ScriptAction {
878+ script: {
879+ // destroy current bottom page
880+ if (page.reloadBottomEdgePage) {
881+ edgeLoader.active = false
882+ // tip will receive focus on page active true
883+ } else {
884+ tip.forceActiveFocus()
885+ }
886+
887+ // notify
888+ page.bottomEdgeDismissed()
889+
890+ edgeLoader.active = true
891+ }
892+ }
893+ }
894+ },
895+ Transition {
896+ from: "floating"
897+ to: "collapsed"
898+ SmoothedAnimation {
899+ target: bottomEdge
900+ property: "y"
901+ duration: UbuntuAnimation.FastDuration
902+ }
903+ }
904+ ]
905+
906+ Loader {
907+ id: edgeLoader
908+
909+ asynchronous: true
910+ anchors.fill: parent
911+ //WORKAROUND: The SDK move the page contents down to allocate space for the header we need to avoid that during the page dragging
912+ Binding {
913+ target: edgeLoader.status === Loader.Ready ? edgeLoader : null
914+ property: "anchors.topMargin"
915+ value: edgeLoader.item && edgeLoader.item.flickable ? edgeLoader.item.flickable.contentY : 0
916+ when: !page.isReady
917+ }
918+
919+ onLoaded: {
920+ tip.forceActiveFocus()
921+ if (page.isReady && edgeLoader.item.active !== true) {
922+ page._pushPage()
923+ }
924+ }
925+ }
926+ }
927+}
928
929=== added file 'app/common/Toaster.qml'
930--- app/common/Toaster.qml 1970-01-01 00:00:00 +0000
931+++ app/common/Toaster.qml 2015-04-26 16:57:43 +0000
932@@ -0,0 +1,81 @@
933+/*
934+ This file is part of quick-memo
935+ Copyright (C) 2014 Stefano Verzegnassi
936+
937+ This program is free software: you can redistribute it and/or modify
938+ it under the terms of the GNU General Public License 3 as published by
939+ the Free Software Foundation.
940+
941+ This program is distributed in the hope that it will be useful,
942+ but WITHOUT ANY WARRANTY; without even the implied warranty of
943+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
944+ GNU General Public License for more details.
945+
946+ You should have received a copy of the GNU General Public License
947+ along with this program. If not, see http://www.gnu.org/licenses/.
948+*/
949+
950+import QtQuick 2.0
951+import Ubuntu.Components 1.1
952+
953+Rectangle {
954+ id: rootItem
955+
956+ property alias text: label.text
957+
958+ width: parent.width
959+ height: units.gu(8)
960+
961+ color: "#131313"
962+ opacity: 0.85
963+
964+ anchors {
965+ horizontalCenter: parent.horizontalCenter
966+ bottom: parent.bottom; bottomMargin: - height
967+ }
968+
969+ Label {
970+ id: label
971+ anchors.centerIn: parent
972+
973+ font.weight: Font.DemiBold
974+ color: "white"
975+ }
976+
977+ MouseArea {
978+ anchors.fill: parent
979+
980+ onClicked: {
981+ showAnimation.stop()
982+ destroyAnimation.restart()
983+ }
984+ }
985+
986+ Rectangle {
987+ anchors {
988+ bottom: parent.bottom
989+ left: parent.left
990+ right: parent.right
991+ }
992+
993+ height: units.dp(2)
994+ color: UbuntuColors.orange
995+ }
996+
997+ SequentialAnimation {
998+ id: showAnimation
999+ running: true
1000+
1001+ NumberAnimation { target: rootItem; property: "anchors.bottomMargin"; to: 0; duration: 300 }
1002+ PauseAnimation { duration: 2000 }
1003+ ScriptAction { script: destroyAnimation.restart() }
1004+ }
1005+
1006+ SequentialAnimation {
1007+ id: destroyAnimation
1008+
1009+ NumberAnimation { target: rootItem; property: "opacity"; to: 0; duration: 500 }
1010+ ScriptAction { script: rootItem.destroy() }
1011+ }
1012+}
1013+
1014
1015=== added file 'app/common/dateHelper.js'
1016--- app/common/dateHelper.js 1970-01-01 00:00:00 +0000
1017+++ app/common/dateHelper.js 2015-04-26 16:57:43 +0000
1018@@ -0,0 +1,23 @@
1019+/*
1020+ This file is part of quick-memo
1021+ Copyright (C) 2014 Stefano Verzegnassi
1022+
1023+ This program is free software: you can redistribute it and/or modify
1024+ it under the terms of the GNU General Public License 3 as published by
1025+ the Free Software Foundation.
1026+
1027+ This program is distributed in the hope that it will be useful,
1028+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1029+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1030+ GNU General Public License for more details.
1031+
1032+ You should have received a copy of the GNU General Public License
1033+ along with this program. If not, see http://www.gnu.org/licenses/.
1034+*/
1035+
1036+function parseDate(value) {
1037+ var d = new Date();
1038+ d.setTime(value)
1039+
1040+ return d
1041+}
1042
1043=== removed file 'app/components/AboutPage.qml'
1044--- app/components/AboutPage.qml 2015-01-17 20:25:00 +0000
1045+++ app/components/AboutPage.qml 1970-01-01 00:00:00 +0000
1046@@ -1,206 +0,0 @@
1047-/*
1048- This file is part of quick-memo
1049- Copyright (C) 2014-2015 Stefano Verzegnassi
1050-
1051- This program is free software: you can redistribute it and/or modify
1052- it under the terms of the GNU General Public License 3 as published by
1053- the Free Software Foundation.
1054-
1055- This program is distributed in the hope that it will be useful,
1056- but WITHOUT ANY WARRANTY; without even the implied warranty of
1057- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1058- GNU General Public License for more details.
1059-
1060- You should have received a copy of the GNU General Public License
1061- along with this program. If not, see http://www.gnu.org/licenses/.
1062-*/
1063-
1064-import QtQuick 2.0
1065-import Ubuntu.Components 1.1
1066-import Ubuntu.Components.ListItems 1.0 as ListItem
1067-import Ubuntu.Components.Popups 1.0
1068-
1069-Page {
1070- id: aboutPage
1071-
1072- title: i18n.tr("About")
1073- head.sections.model: [i18n.tr("About"), i18n.tr("Credits"), i18n.tr("Copyright")]
1074-
1075- property string version
1076-
1077- Loader {
1078- id: view
1079-
1080- anchors {
1081- fill: parent
1082- margins: units.gu(2)
1083- }
1084-
1085- sourceComponent: {
1086- if (aboutPage.head.sections.selectedIndex == 0)
1087- return aboutSection
1088-
1089- if (aboutPage.head.sections.selectedIndex == 1)
1090- return creditSection
1091-
1092- if (aboutPage.head.sections.selectedIndex == 2)
1093- return copyrightSection
1094- }
1095- }
1096-
1097- // ABOUT SECTION
1098- Component {
1099- id: aboutSection
1100- Column {
1101- anchors.centerIn: parent
1102- width: root.width > units.gu(50) ? units.gu(50) : parent.width
1103- spacing: units.gu(4)
1104-
1105- UbuntuShape {
1106- id: logo
1107-
1108- width: root.width > units.gu(50) ? units.gu(25) : parent.width / 2
1109- height: width
1110- radius: "medium"
1111-
1112- image: Image {
1113- source: "../../graphics/quick-memo.png"
1114- }
1115-
1116- anchors.horizontalCenter: parent.horizontalCenter
1117- }
1118-
1119- Column {
1120- width: parent.width
1121-
1122- Label {
1123- fontSize: "x-large"
1124- font.weight: Font.DemiBold
1125- text: "Quick Memo"
1126-
1127- anchors.horizontalCenter: parent.horizontalCenter
1128- }
1129-
1130- Label {
1131- // TRANSLATORS: Version of the software (e.g. "Version 0.3.51")
1132- text: i18n.tr("Version ") + aboutPage.version
1133-
1134- anchors.horizontalCenter: parent.horizontalCenter
1135-
1136- Component.onCompleted: {
1137- // Extract version info from manifest.json
1138- var doc = new XMLHttpRequest();
1139- var json_string;
1140- doc.onreadystatechange = function() {
1141- if (doc.readyState == XMLHttpRequest.DONE) {
1142- json_string = doc.responseText;
1143-
1144- if (json_string) {
1145- var obj = JSON.parse(json_string)
1146- aboutPage.version = obj.version
1147- } else {
1148- /* TRANSLATORS: This is shown where it's impossible to get
1149- the version number (e.g. "Version UNKNOWN") */
1150- aboutPage.version = i18n.tr("UNKNOWN")
1151- }
1152- }
1153- }
1154- doc.open("get", Qt.resolvedUrl("../../app_info.json"));
1155-
1156- doc.setRequestHeader("Content-Encoding", "UTF-8");
1157- doc.send();
1158- }
1159- }
1160- }
1161-
1162- Column {
1163- width: parent.width
1164-
1165- Label {
1166- text: "(C) 2014-2015 Stefano Verzegnassi"
1167- anchors.horizontalCenter: parent.horizontalCenter
1168- }
1169-
1170- Label {
1171- fontSize: "small"
1172- text: i18n.tr("Released under the terms of the GNU GPL v3")
1173-
1174- anchors.horizontalCenter: parent.horizontalCenter
1175- }
1176- }
1177-
1178- Column {
1179- width: parent.width
1180- spacing: units.gu(2)
1181-
1182- Label {
1183- fontSize: "small"
1184- text: i18n.tr("Source code available on ") + "<a href=\"https://launchpad.net/quick-memo\">launchpad.net</a>"
1185-
1186- anchors.horizontalCenter: parent.horizontalCenter
1187-
1188- onLinkActivated: Qt.openUrlExternally(link)
1189- }
1190- }
1191- }
1192- } // END ABOUT SECTION
1193-
1194- // CREDITS SECTION
1195- Component {
1196- id: creditSection
1197-
1198- Column {
1199- anchors.fill: parent
1200- width: root.width > units.gu(50) ? units.gu(50) : parent.width
1201-
1202- ListItem.Header {
1203- text: i18n.tr("A big thanks to:")
1204- }
1205-
1206- ListItem.Subtitled {
1207- text: "Nekhelesh Ramananthan"
1208- subText: "Code contribution"
1209- }
1210-
1211- ListItem.Subtitled {
1212- text: "Renato Araujo Oliveira Filho"
1213- subText: "Code contribution"
1214- }
1215- }
1216- } // END CREDIT SECTION
1217-
1218- // COPYRIGHT SECTION
1219- Component {
1220- id: copyrightSection
1221-
1222- Flickable {
1223- anchors.fill: parent
1224-
1225- clip: true
1226- contentHeight: copyrightText.height
1227-
1228- // Indipendent GU flickable speed workaround
1229- flickDeceleration: 1500 * units.gridUnit / 8
1230- maximumFlickVelocity: 2500 * units.gridUnit / 8
1231-
1232- Label {
1233- id: copyrightText
1234- wrapMode: Text.WordWrap
1235- width: parent.width
1236- fontSize: "x-small"
1237-
1238- Component.onCompleted: {
1239- var doc = new XMLHttpRequest();
1240- doc.onreadystatechange = function() {
1241- if (doc.readyState == XMLHttpRequest.DONE) {
1242- text = doc.responseText;
1243- }
1244- }
1245- doc.open("get", Qt.resolvedUrl("../../copyright"));
1246- doc.setRequestHeader("Content-Encoding", "UTF-8");
1247- doc.send();
1248- }
1249- }
1250- }
1251- }
1252-}
1253
1254=== removed file 'app/components/CMakeLists.txt'
1255--- app/components/CMakeLists.txt 2014-11-03 00:21:23 +0000
1256+++ app/components/CMakeLists.txt 1970-01-01 00:00:00 +0000
1257@@ -1,7 +0,0 @@
1258-file(GLOB COMPONENTS_QML_JS_FILES *.qml *.js)
1259-
1260-# make the files visible in the qtcreator tree
1261-add_custom_target(quick-memo_components_QMlFiles ALL SOURCES ${COMPONENTS_QML_JS_FILES})
1262-
1263-install(FILES ${COMPONENTS_QML_JS_FILES} DESTINATION ${APP_DIR}/components)
1264-
1265
1266=== removed file 'app/components/ColorDialog.qml'
1267--- app/components/ColorDialog.qml 2014-09-02 00:16:08 +0000
1268+++ app/components/ColorDialog.qml 1970-01-01 00:00:00 +0000
1269@@ -1,168 +0,0 @@
1270-/*
1271- This file is part of quick-memo
1272- Copyright (C) 2014 Stefano Verzegnassi
1273-
1274- This program is free software: you can redistribute it and/or modify
1275- it under the terms of the GNU General Public License 3 as published by
1276- the Free Software Foundation.
1277-
1278- This program is distributed in the hope that it will be useful,
1279- but WITHOUT ANY WARRANTY; without even the implied warranty of
1280- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1281- GNU General Public License for more details.
1282-
1283- You should have received a copy of the GNU General Public License
1284- along with this program. If not, see http://www.gnu.org/licenses/.
1285-*/
1286-
1287-import QtQuick 2.0
1288-import Ubuntu.Components 1.1
1289-import Ubuntu.Components.Popups 1.0
1290-
1291-Dialog {
1292- id: rootItem
1293-
1294- title: i18n.tr("Pick a color")
1295-
1296- property var colors: ["#fdfdfd", "#e9674d", "#f0a250", "#eec34f", "#aea79f", "#95c253", "#8bbee2", "#e46f8e"]
1297- property color selectedColor: colors[0]
1298-
1299- property bool showTick: true
1300- property bool askConfirmation: false
1301-
1302- signal colorPicked(bool isChanged)
1303-
1304- onSelectedColorChanged: view.setCurrentColor()
1305- Component.onCompleted: internal.oldColor = rootItem.selectedColor
1306-
1307- QtObject {
1308- id: internal
1309-
1310- property color oldColor
1311- }
1312-
1313- Grid {
1314- id: grid
1315- width: parent.width
1316-
1317- columns: (width / cellWidth).toFixed(0)
1318-
1319- property int cellHeight: units.gu(5)
1320- property int cellWidth: units.gu(5)
1321-
1322- Repeater {
1323- id: view
1324-
1325- width: parent.width
1326-
1327- Component.onCompleted: setCurrentColor()
1328-
1329- function setCurrentColor() {
1330- if (rootItem.colors) {
1331- for (var i=0; i<rootItem.colors.length; i++) {
1332- if (rootItem.colors[i] == rootItem.selectedColor) {
1333- view.currentIndex = i
1334- }
1335- }
1336- }
1337- }
1338-
1339- model: rootItem.colors
1340-
1341- property int currentIndex: 0
1342-
1343- delegate: AbstractButton {
1344- id: delegate
1345-
1346- height: grid.cellHeight
1347- width: grid.cellWidth
1348-
1349- onClicked: {
1350- view.currentIndex = model.index
1351-
1352- if (!rootItem.askConfirmation) {
1353- rootItem.selectedColor = rootItem.colors[view.currentIndex]
1354-
1355- console.log ("Old color:", internal.oldColor, "New color:", rootItem.selectedColor)
1356- if (internal.oldColor == rootItem.selectedColor) {
1357- rootItem.colorPicked(false)
1358- } else {
1359- rootItem.colorPicked(true)
1360- }
1361-
1362- rootItem.hide()
1363- }
1364- }
1365-
1366- UbuntuShape {
1367- anchors { fill: parent; margins: units.gu(0.5)}
1368- color: modelData
1369- clip: true
1370-
1371- Icon {
1372- id: tick
1373- anchors { fill: parent; margins: units.gu(0.5) }
1374- name: "tick"
1375- visible: view.currentIndex == model.index && rootItem.showTick
1376- color: getColor()
1377-
1378- function getColor() {
1379- return Qt.rgba(1 - parseInt(modelData.substr(1,2), 16) / 255, 1 - parseInt(modelData.substr(3,2), 16) / 255, 1 - parseInt(modelData.substr(5,2), 16) / 255)
1380- }
1381- }
1382- }
1383- }
1384- }
1385- }
1386-
1387- Column {
1388- width: parent.width
1389- spacing: units.gu(2)
1390-
1391- Loader {
1392- width: parent.width
1393- sourceComponent: if (askConfirmation) return confirmationButtons
1394-
1395- Component {
1396- id: confirmationButtons
1397- Button {
1398- width: parent.width
1399- text: i18n.tr("OK")
1400- color: UbuntuColors.orange
1401-
1402- onClicked: {
1403- rootItem.selectedColor = rootItem.colors[view.currentIndex]
1404-
1405- console.log ("Old color:", internal.oldColor, "New color:", rootItem.selectedColor)
1406- if (internal.oldColor == rootItem.selectedColor) {
1407- rootItem.colorPicked(false)
1408- } else {
1409- rootItem.colorPicked(true)
1410- }
1411-
1412- rootItem.hide()
1413- }
1414- }
1415- }
1416- }
1417-
1418- Button {
1419- width: parent.width
1420- text: i18n.tr("Cancel")
1421-
1422- onClicked: {
1423- rootItem.hide()
1424-
1425- for (var i=0; i<rootItem.colors.length; i++) {
1426- if (rootItem.colors[i] == internal.oldColor) {
1427- view.currentIndex = i
1428- }
1429- }
1430- rootItem.selectedColor = internal.oldColor
1431- }
1432- }
1433- }
1434-
1435-
1436-
1437-}
1438
1439=== removed file 'app/components/Delegate.qml'
1440--- app/components/Delegate.qml 2014-11-06 05:09:59 +0000
1441+++ app/components/Delegate.qml 1970-01-01 00:00:00 +0000
1442@@ -1,291 +0,0 @@
1443-/*
1444- This file is part of quick-memo
1445- Copyright (C) 2014 Stefano Verzegnassi
1446-
1447- This program is free software: you can redistribute it and/or modify
1448- it under the terms of the GNU General Public License 3 as published by
1449- the Free Software Foundation.
1450-
1451- This program is distributed in the hope that it will be useful,
1452- but WITHOUT ANY WARRANTY; without even the implied warranty of
1453- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1454- GNU General Public License for more details.
1455-
1456- You should have received a copy of the GNU General Public License
1457- along with this program. If not, see http://www.gnu.org/licenses/.
1458-*/
1459-
1460-import QtQuick 2.0
1461-import Ubuntu.Components 1.1
1462-import Ubuntu.Thumbnailer 0.1
1463-import "dateHelper.js" as DateHelper
1464-
1465-AbstractButton {
1466- id: rootItem
1467-
1468- height: layout.height + layout.anchors.topMargin
1469- width: parent.width
1470-
1471- property bool selected: false
1472- property int maxListDelegatesNumber: 3
1473-
1474- // RGB channels from 'shape.color' are in [0; 1] range.
1475- property color foregroundColor: ((shape.color.r * 0.30 + shape.color.g * 0.59 + shape.color.b * 0.11) > 0.5) ? UbuntuColors.darkGrey : "#F3F3E7"
1476-
1477- UbuntuShape {
1478- id: shape
1479- anchors.fill: parent
1480-
1481- // Add 70% opacity
1482- color: contents.color.toString().replace("#", "#B3")
1483-
1484- radius: "medium"
1485-
1486- Column {
1487- id: layout
1488- anchors { top: parent.top; left: parent.left; right: parent.right; topMargin: units.gu(2) }
1489-
1490- Column {
1491- id: column
1492- width: parent.width - (spacing * 2)
1493- x: spacing
1494- spacing: units.gu(2)
1495-
1496- Loader {
1497- width: parent.width
1498- sourceComponent: (contents.title == "") ? undefined : titleComponent
1499-
1500- Component {
1501- id: titleComponent
1502-
1503- Label {
1504- width: parent.width
1505- fontSize: "large"
1506- font.weight: Font.Bold
1507- text: contents.title
1508- elide: Text.ElideRight
1509- maximumLineCount: 2
1510- wrapMode: Text.WrapAnywhere
1511- color: rootItem.foregroundColor
1512- }
1513- }
1514-
1515- }
1516-
1517- Loader {
1518- width: parent.width
1519- sourceComponent: (contents.text == "") ? undefined : textComponent
1520-
1521- Component {
1522- id: textComponent
1523-
1524- Label {
1525- width: parent.width
1526- text: contents.text
1527- wrapMode: Text.WrapAnywhere
1528- elide: Text.ElideRight
1529- maximumLineCount: 5
1530- color: rootItem.foregroundColor
1531- }
1532- }
1533- }
1534- }
1535-
1536- // A spacer item
1537- Item {
1538- width: parent.width
1539- height: units.gu(2)
1540- visible: picsRepeater.count > 0
1541- }
1542-
1543- Item {
1544- id: picsItem
1545- width: parent.width
1546- height: picFlow.height
1547-
1548- // TODO: As for listDelegates, limit pics to a number of 9
1549- Flow {
1550- id: picFlow
1551- width: parent.width
1552-
1553- Repeater {
1554- id: picsRepeater
1555-
1556- model: contents.pictures
1557-
1558- delegate: Image {
1559- id: img
1560- width: parent.width
1561- fillMode: Image.PreserveAspectCrop
1562- source: "image://thumbnailer/" + Qt.resolvedUrl(contents.pictures[index].url)
1563-
1564- Connections {
1565- target: picsRepeater
1566- onItemAdded: calculateSize(index)
1567- onItemRemoved: calculateSize(index)
1568- }
1569-
1570- Connections {
1571- target: picFlow
1572- onWidthChanged: calculateSize(index)
1573- }
1574-
1575- Component.onCompleted: calculateSize(index)
1576-
1577- function calculateSize(index) {
1578- var n = picsRepeater.count
1579- var i = n % 3
1580- var m = Math.floor(n / 3)
1581-
1582- height = units.gu(6)
1583-
1584- // Need to be hardcoded because of an issue.
1585- // FIXME: Think it requires a better solution
1586- var picFlowRealWidth = ((root.width - units.gu(4)) * 0.5) - units.gu(1)
1587-
1588- switch(i) {
1589- case 0:
1590- width = picFlowRealWidth / 3
1591- return
1592- case 1:
1593- if (index == 0) {
1594- width = picFlowRealWidth
1595- return
1596- } else {
1597- width = picFlowRealWidth / 3
1598- return
1599- }
1600- case 2:
1601- if (index <= 1) {
1602- width = picFlowRealWidth / 2
1603- return
1604- } else {
1605- width = picFlowRealWidth / 3
1606- return
1607- }
1608- }
1609- }
1610- }
1611- }
1612-
1613- Component.onCompleted: picsRepeater.model = contents.pictures
1614- }
1615- }
1616-
1617- Loader {
1618- id: listLoader
1619- width: parent.width
1620- sourceComponent: (contents.list[0]) ? listComponent : null
1621-
1622- Component {
1623- id: listComponent
1624-
1625- Column {
1626- width: parent.width
1627-
1628- // A spacer item
1629- Item {
1630- width: parent.width
1631- height: units.gu(1)
1632- }
1633-
1634- Repeater {
1635- id: listRepeater
1636- width: parent.width
1637-
1638- model: contents.list
1639-
1640- delegate: Loader {
1641- width: parent.width
1642- sourceComponent: model.index < 4 ? listDelegate : null
1643-
1644- Component {
1645- id: listDelegate
1646-
1647- Row {
1648- id: rootItem
1649- spacing: units.gu(1)
1650- width: parent.width
1651- height: Math.max(checkBox.height, textArea.height)
1652-
1653- Item {
1654- id: checkBox
1655- width: parent.width
1656- height: units.gu(4)
1657-
1658- property bool checked: contents.list[index].checked
1659-
1660- Icon {
1661- id: tick
1662- anchors {
1663- left: parent.left; leftMargin: units.gu(2.25);
1664- top: parent.top; topMargin: units.gu(0.35)
1665- }
1666- width: (source == "../../graphics/select.svg") ? units.gu(2.25) : units.gu(1.5)
1667- height: (source == "../../graphics/select.svg") ? units.gu(2) : units.gu(1.5)
1668-
1669- source: checkBox.checked ? "../../graphics/select.svg" : "../../graphics/unselect.svg"
1670- visible: model.index !== 3
1671- color: foregroundColor
1672- }
1673-
1674- Label {
1675- id: textArea
1676- anchors { left: tick.right; right: parent.right; margins: units.gu(1) }
1677-
1678- font.strikeout: checkBox.checked
1679- text: (model.index == 3) ? ". . ." : contents.list[index].text
1680- elide: Text.ElideRight
1681- maximumLineCount: 2
1682- wrapMode: Text.WrapAnywhere
1683- color: foregroundColor
1684- }
1685- }
1686- }
1687- }
1688- }
1689- }
1690-
1691- Component.onCompleted: listRepeater.model = contents.list
1692- }
1693- }
1694- }
1695-
1696- // A spacer item
1697- Item {
1698- width: parent.width
1699- height: units.gu(2)
1700- }
1701-
1702- Item {
1703- id: date
1704- width: parent.width
1705- height: units.gu(4)
1706-
1707- Label {
1708- anchors { right: parent.right; verticalCenter: parent.verticalCenter; margins: units.gu(2) }
1709- text: Qt.formatDateTime(DateHelper.parseDate(contents.date), "d MMM yyyy, hh:mm")
1710- fontSize: "small"
1711- color: rootItem.foregroundColor
1712- }
1713- }
1714- }
1715- }
1716-
1717- // Visual feedback when pressed. Not listed in official documentation, still useful.
1718- onPressedChanged: {
1719- if (pressed)
1720- shape.borderSource = "radius_pressed.sci"
1721- else
1722- shape.borderSource = "radius_idle.sci"
1723- }
1724-
1725- // Visual feedback when selected.
1726- onSelectedChanged: {
1727- if (selected) {
1728- shape.color = Qt.darker(contents.color)
1729- } else {
1730- shape.color = contents.color.toString().replace("#", "#B3")
1731- }
1732- }
1733-}
1734
1735=== removed file 'app/components/EditMemoPage.qml'
1736--- app/components/EditMemoPage.qml 2015-01-17 20:30:56 +0000
1737+++ app/components/EditMemoPage.qml 1970-01-01 00:00:00 +0000
1738@@ -1,328 +0,0 @@
1739-/*
1740- This file is part of quick-memo
1741- Copyright (C) 2014-2015 Stefano Verzegnassi
1742-
1743- This program is free software: you can redistribute it and/or modify
1744- it under the terms of the GNU General Public License 3 as published by
1745- the Free Software Foundation.
1746-
1747- This program is distributed in the hope that it will be useful,
1748- but WITHOUT ANY WARRANTY; without even the implied warranty of
1749- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1750- GNU General Public License for more details.
1751-
1752- You should have received a copy of the GNU General Public License
1753- along with this program. If not, see http://www.gnu.org/licenses/.
1754-*/
1755-
1756-import QtQuick 2.0
1757-import Ubuntu.Components 1.1
1758-import Ubuntu.Keyboard 0.1
1759-import Ubuntu.Components.Popups 1.0
1760-import Ubuntu.Components.ListItems 1.0 as ListItem
1761-
1762-import "dateHelper.js" as DateHelper
1763-
1764-Page {
1765- id: memoPage
1766- title: editMemo ? i18n.tr("Details") : i18n.tr("Add a new memo")
1767-
1768- /* This page has two modes: NewMemo and EditMemo.
1769- Following properties are used to load the right mode.
1770- */
1771- property bool editMemo: false
1772- property int index
1773-
1774- property bool canSave: (title.text != "") || (desc.text != "") || (listManager.model.count > 0) || (picsView.model.count > 0)
1775- property bool contentChanged: false
1776-
1777- // Load an existent memo if required
1778- Component.onCompleted: { if (editMemo) loadNote() }
1779-
1780- head.backAction: editMemo ? backEditMemo : backNewMemo
1781- head.actions: [colorToolAction, deleteMemo, saveMemo]
1782-
1783- // Background
1784- PageBackground { id: bg }
1785-
1786- // flickable property needs to be explicitly set, to avoid a binding loop for memoPage.height
1787- flickable: flickable
1788- Flickable {
1789- id: flickable
1790- anchors.fill: parent
1791-
1792- // Indipendent GU flickable speed workaround
1793- flickDeceleration: 1500 * units.gridUnit / 8
1794- maximumFlickVelocity: 2500 * units.gridUnit / 8
1795-
1796- // Could this be an SDK-related issue?
1797- contentHeight: layout.height + root.header.height
1798- interactive: contentHeight > height
1799-
1800- Column {
1801- id: layout
1802- anchors { left: parent.left; right: parent.right }
1803- spacing: units.gu(1)
1804-
1805- // Spacing
1806- Item { width: parent.width; height: units.gu(1) }
1807-
1808- NoteTextField {
1809- id: title
1810- x: units.gu(2); width: parent.width - units.gu(4)
1811-
1812- font.weight: Font.Bold
1813- font.pixelSize: FontUtils.sizeToPixels("large")
1814-
1815- placeholderText: i18n.tr("No title")
1816- onFocusLost: flickable.forceActiveFocus()
1817-
1818- // Ubuntu Keyboard
1819- /* TRANSLATORS: This is a custom text for the "enter" key of
1820- the on-screen keyboard (max 4 char, so it's not elided) */
1821- InputMethod.extensions: { "enterKeyText": i18n.tr("Next") }
1822- Keys.onReturnPressed: desc.forceActiveFocus()
1823- }
1824-
1825- NoteTextArea {
1826- id: desc
1827- x: units.gu(2); width: parent.width - units.gu(4)
1828-
1829- placeholderText: i18n.tr("No description")
1830- onFocusLost: flickable.forceActiveFocus()
1831- }
1832-
1833- ListManager {
1834- id: listManager
1835-
1836- width: parent.width
1837- flickable: flickable
1838- }
1839-
1840- PicturesManager { id: picsView; width: parent.width }
1841-
1842- Label {
1843- id: updateLabel
1844- anchors { right: parent.right; rightMargin: units.gu(2) }
1845-
1846- fontSize: "x-small"
1847- visible: editMemo
1848-
1849- function refresh() {
1850- updateLabel.text = i18n.tr("Last update: %1").arg(Qt.formatDateTime(DateHelper.parseDate(notes.model.get(index).contents.date), "d MMM yyyy, hh:mm:ss"))
1851- }
1852- }
1853- }
1854- }
1855-
1856- // Used for auto saving while editing fields
1857- Timer {
1858- id: autoSaveTimer
1859- interval: 1000 // Is this a good timing?
1860-
1861- onTriggered: {
1862- if (!canSave) { // Change timer inteval if can't save?
1863- deleteDialog.emptyMemo = true;
1864- deleteDialog.show();
1865- } else {
1866- console.log("autoSaveTimer triggered... updating the note!")
1867- saveNote()
1868- }
1869- }
1870- }
1871-
1872- function loadNote() {
1873- var memoObj = notes.model.get(index)
1874-
1875- title.text = memoObj.contents.title
1876- desc.text = memoObj.contents.text
1877- bg.color = memoObj.contents.color
1878-
1879- // Append list items provided by NoteModel
1880- listManager.model.clear()
1881- for (var i=0; i<memoObj.contents.list.length; i++) {
1882- listManager.model.append(JSON.parse(JSON.stringify(memoObj.contents.list[i])))
1883- }
1884-
1885- // Append pictures items provided by NoteModel
1886- picsView.model.clear()
1887- for (var i=0; i<memoObj.contents.pictures.length; i++) {
1888- picsView.model.append(JSON.parse(JSON.stringify(memoObj.contents.pictures[i])))
1889- }
1890-
1891- // Connect signals for auto-saving
1892- title.textChanged.connect(updateNote)
1893- desc.textReallyChanged.connect(updateNote)
1894- listManager.listChanged.connect(updateNote)
1895- picsView.picsModelChanged.connect(updateNote)
1896- bg.colorChanged.connect(updateNote)
1897-
1898- updateLabel.refresh()
1899- }
1900-
1901- function updateNote() {
1902- autoSaveTimer.restart()
1903- }
1904-
1905- function saveNote() {
1906- var obj = JSON.parse(JSON.stringify(notes.model.get(index)))
1907-
1908- obj.contents.title = title.text
1909- obj.contents.text = desc.text
1910- // The char '#' from the hex color is not correctly parse by JSON. We add an empty string, so that it works well.
1911- obj.contents.color = "" + bg.color
1912- obj.contents.list = listManager.exportModel()
1913- obj.contents.pictures = picsView.exportModel()
1914-
1915- notes.editNote(memoPage.index, obj)
1916- updateLabel.refresh()
1917-
1918- memoPage.contentChanged = true;
1919- }
1920-
1921- function addNote() {
1922- notes.addNote(title.text,
1923- desc.text,
1924- "" + bg.color, // The char '#' from the hex color is not correctly parse by JSON. We add an empty string, so that it works well.
1925- listManager.exportModel(),
1926- picsView.exportModel())
1927- pageStack.pop()
1928-
1929- root.showNotification(i18n.tr("Memo saved!"))
1930- }
1931-
1932- // *** ACTIONS ***
1933- Action {
1934- id: saveMemo
1935- text: i18n.tr("Save")
1936- iconName: "ok"
1937- onTriggered: addNote()
1938-
1939- visible: !editMemo
1940- enabled: canSave
1941- }
1942- Action {
1943- id: deleteMemo
1944- text: i18n.tr("Delete memo")
1945- iconName: "delete"
1946- onTriggered: deleteDialog.show()
1947- visible: editMemo
1948- }
1949- Action {
1950- id: colorToolAction
1951- text: i18n.tr("Change memo color")
1952- iconSource: "../../graphics/palette.svg"
1953- onTriggered: PopupUtils.open(colorNotePopover)
1954- }
1955-
1956- // *** BACK ACTIONS ***
1957- Action {
1958- id: backEditMemo
1959- iconName: "back"
1960- onTriggered: {
1961- if (!canSave) {
1962- deleteDialog.emptyMemo = true;
1963- deleteDialog.show();
1964- } else {
1965- // Check if a saveNote request was made. If so, stop the timer and save before exiting the page.
1966- if (autoSaveTimer.running) {
1967- console.log("It's ok. Saving the note before closing the page...")
1968- autoSaveTimer.running = false
1969- saveNote()
1970- }
1971- pageStack.pop()
1972-
1973- /* Workaround: see MainPage.qml, comment for mainView.delegate.onClicked().
1974- We simply re-push in the stack what we removed earlier.*/
1975- pageStack.push(mainPage)
1976-
1977- if (memoPage.contentChanged)
1978- root.showNotification(i18n.tr("Memo updated!"))
1979- }
1980- }
1981- }
1982-
1983- Action {
1984- id: backNewMemo
1985- iconName: "close"
1986- onTriggered: {
1987- if (canSave)
1988- PopupUtils.open(dataLosingOnBackDialog)
1989- else {
1990- // Just a pop() because this is called only when the page is loaded through bottomEdge.
1991- pageStack.pop()
1992-
1993- root.showNotification(i18n.tr("Memo aborted!"))
1994- }
1995- }
1996- }
1997-
1998- // *** DIALOGS ***
1999- Dialog {
2000- id: deleteDialog
2001-
2002- property bool emptyMemo: false
2003-
2004- title: emptyMemo ? i18n.tr("Empty memo") : i18n.tr("Delete memo")
2005- text: emptyMemo ? i18n.tr("This memo has no content.") : i18n.tr("Are you sure?")
2006-
2007- Button {
2008- text: i18n.tr("Cancel")
2009- gradient: UbuntuColors.greyGradient
2010- onClicked: deleteDialog.hide()
2011- visible: !emptyMemo
2012- }
2013- Button {
2014- text: i18n.tr("Delete")
2015- color: UbuntuColors.orange
2016- onClicked: {
2017- deleteDialog.hide()
2018- pageStack.pop();
2019- pageStack.push(mainPage)
2020- notes.deleteNote(index)
2021-
2022- root.showNotification(i18n.tr("Memo deleted!"))
2023- }
2024- }
2025- }
2026-
2027- Component {
2028- id: dataLosingOnBackDialog
2029- Dialog {
2030- id: dataLosingOnBackDialogue
2031-
2032- title: i18n.tr("Discard changes?")
2033- text: i18n.tr("Your memo will be PERMANENTLY lost.")
2034-
2035- Button {
2036- text: i18n.tr("Cancel")
2037- gradient: UbuntuColors.greyGradient
2038- onClicked: PopupUtils.close(dataLosingOnBackDialogue)
2039- }
2040- Button {
2041- text: i18n.tr("Go back!")
2042- color: UbuntuColors.orange
2043- onClicked: {
2044- PopupUtils.close(dataLosingOnBackDialogue)
2045- pageStack.pop();
2046- }
2047- }
2048- }
2049- }
2050-
2051- Component {
2052- id: colorNotePopover
2053-
2054- ColorDialog {
2055- id: colorDialog
2056-
2057- selectedColor: bg.color
2058- onColorPicked: {
2059- if (isChanged)
2060- bg.color = selectedColor
2061-
2062- PopupUtils.close(colorDialog)
2063- }
2064- }
2065- }
2066-}
2067
2068=== removed file 'app/components/HorizontalFlowListView.qml'
2069--- app/components/HorizontalFlowListView.qml 2014-10-04 18:40:51 +0000
2070+++ app/components/HorizontalFlowListView.qml 1970-01-01 00:00:00 +0000
2071@@ -1,78 +0,0 @@
2072-/*
2073- * Copyright 2012 Ruediger Gad
2074- * Copyright 2014 Stefano Verzegnassi <stefano92.100@gmail.com>
2075- *
2076- * This file is part of FlowListView.
2077- *
2078- * FlowListView is free software: you can redistribute it and/or modify
2079- * it under the terms of the GNU Lesser General Public License (LGPL)
2080- * as published by the Free Software Foundation, either version 3 of the
2081- * License, or (at your option) any later version.
2082- *
2083- * FlowListView is distributed in the hope that it will be useful,
2084- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2085- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2086- * GNU General Public License for more details.
2087- *
2088- * You should have received a copy of the GNU Lesser General Public License
2089- * along with FlowListView. If not, see <http://www.gnu.org/licenses/>.
2090- *
2091- */
2092-
2093-// A derivative version of FlowListView.qml
2094-import QtQuick 2.0
2095-import Ubuntu.Components 1.1
2096-
2097-Flickable {
2098- id: flowListView
2099-
2100- contentWidth: flow.childrenRect.width
2101-
2102- property alias count: repeater.count
2103- property int currentIndex: -1
2104- property variant currentItem;
2105- property alias delegate: repeater.delegate
2106- property alias model: repeater.model
2107-
2108- property alias spacing: flow.spacing
2109-
2110- property alias add: flow.add
2111- property alias populate: flow.populate
2112- property alias move: flow.move
2113-
2114- // Indipendent GU flickable speed workaround
2115- flickDeceleration: 1500 * units.gridUnit / 8
2116- maximumFlickVelocity: 2500 * units.gridUnit / 8
2117-
2118- onCurrentIndexChanged: {
2119- currentItem = repeater.itemAt(currentIndex)
2120- }
2121-
2122- Flow {
2123- id: flow
2124-
2125- height: parent.height
2126- flow: Flow.TopToBottom
2127-
2128- Item { width: units.gu(1); height: parent.height }
2129-
2130- Repeater {
2131- id: repeater
2132-
2133- onCountChanged: {
2134- if (flowListView.currentIndex === -1 && count > 0) {
2135- flowListView.currentIndex = 0
2136- return
2137- }
2138- if (flowListView.currentIndex >= count) {
2139- flowListView.currentIndex = count - 1
2140- return
2141- }
2142-
2143- flowListView.currentIndex = -1
2144- }
2145- }
2146-
2147- Item { width: units.gu(1); height: parent.height }
2148- }
2149-}
2150
2151=== removed file 'app/components/IconButton.qml'
2152--- app/components/IconButton.qml 2014-08-24 18:35:14 +0000
2153+++ app/components/IconButton.qml 1970-01-01 00:00:00 +0000
2154@@ -1,45 +0,0 @@
2155-/*
2156- This file is part of quick-memo
2157- Copyright (C) 2014 Stefano Verzegnassi
2158-
2159- This program is free software: you can redistribute it and/or modify
2160- it under the terms of the GNU General Public License 3 as published by
2161- the Free Software Foundation.
2162-
2163- This program is distributed in the hope that it will be useful,
2164- but WITHOUT ANY WARRANTY; without even the implied warranty of
2165- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2166- GNU General Public License for more details.
2167-
2168- You should have received a copy of the GNU General Public License
2169- along with this program. If not, see http://www.gnu.org/licenses/.
2170-*/
2171-
2172-import QtQuick 2.0
2173-import Ubuntu.Components 1.1
2174-import QtGraphicalEffects 1.0
2175-
2176-AbstractButton {
2177- id: rootItem
2178- height: units.gu(4)
2179- width: height
2180-
2181- property alias source: image.name
2182-
2183- Icon {
2184- id: image
2185- anchors.fill: parent
2186- visible: false
2187- }
2188-
2189- ColorOverlay {
2190- id: co
2191- anchors { fill: image; margins: units.gu(0.5) }
2192- source: image
2193- color: rootItem.pressed ? UbuntuColors.orange : Theme.palette.selected.backgroundText
2194-
2195- Behavior on color {
2196- ColorAnimation { duration: UbuntuAnimation.SnapDuration }
2197- }
2198- }
2199-}
2200
2201=== removed file 'app/components/ImageViewer.qml'
2202--- app/components/ImageViewer.qml 2014-10-04 18:40:51 +0000
2203+++ app/components/ImageViewer.qml 1970-01-01 00:00:00 +0000
2204@@ -1,130 +0,0 @@
2205-/*
2206- This file is part of quick-memo
2207- Copyright (C) 2014 Stefano Verzegnassi
2208-
2209- This program is free software: you can redistribute it and/or modify
2210- it under the terms of the GNU General Public License 3 as published by
2211- the Free Software Foundation.
2212-
2213- This program is distributed in the hope that it will be useful,
2214- but WITHOUT ANY WARRANTY; without even the implied warranty of
2215- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2216- GNU General Public License for more details.
2217-
2218- You should have received a copy of the GNU General Public License
2219- along with this program. If not, see http://www.gnu.org/licenses/.
2220-*/
2221-
2222-import QtQuick 2.0
2223-import Ubuntu.Components 1.1
2224-// Following are used by the custom header
2225-import Ubuntu.Components.ListItems 1.0 as ListItem
2226-import QtGraphicalEffects 1.0
2227-
2228-Page {
2229- id: imageViewer
2230-
2231- property alias source: image.source
2232-
2233- // Don't use Ubuntu header. Use a custom one.
2234- Item {
2235- id: header
2236-
2237- anchors { left: parent.left; top: parent.top; right: parent.right }
2238- height: units.gu(6)
2239-
2240- Rectangle {
2241- anchors.fill: parent
2242- color: "black"
2243- opacity: 0.3
2244-
2245- ListItem.Divider {
2246- anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
2247- }
2248- }
2249-
2250- AbstractButton {
2251- id: backButton
2252- anchors { left: parent.left; top: parent.top; bottom: parent.bottom; leftMargin: units.gu(2); }
2253- width: backImg.width + title.width + title.anchors.margins
2254-
2255- onClicked: pageStack.pop()
2256-
2257- Icon {
2258- id: backImg
2259- anchors { left: parent.left; verticalCenter: parent.verticalCenter }
2260- height: units.gu(2)
2261- width: height
2262- visible: false
2263- name: "back"
2264- }
2265-
2266- ColorOverlay {
2267- id: co
2268- anchors.fill: backImg
2269- source: backImg
2270- color: backButton.pressed ? UbuntuColors.orange : "white"
2271- Behavior on color {
2272- ColorAnimation { duration: UbuntuAnimation.SnapDuration }
2273- }
2274- }
2275-
2276- Label {
2277- id: title
2278- anchors { left: co.right; verticalCenter: parent.verticalCenter; margins: units.gu(1) }
2279- text: i18n.tr("Back")
2280-
2281- fontSize: "large"
2282- font.weight: Font.DemiBold
2283- color: backButton.pressed ? UbuntuColors.orange : "white"
2284-
2285- Behavior on color {
2286- ColorAnimation { duration: UbuntuAnimation.SnapDuration }
2287- }
2288- }
2289- }
2290- }
2291-
2292- Rectangle {
2293- anchors.fill: parent
2294- color: "black"
2295- z:-10
2296- }
2297-
2298- Flickable {
2299- id: flickable
2300- anchors { left: parent.left; top: header.bottom; right: parent.right; bottom: parent.bottom }
2301-
2302- contentWidth: Math.max(container.width, width)
2303- contentHeight: Math.max(container.height, height)
2304-
2305- // Indipendent GU flickable speed workaround
2306- flickDeceleration: 1500 * units.gridUnit / 8
2307- maximumFlickVelocity: 2500 * units.gridUnit / 8
2308-
2309- Item {
2310- id: container
2311- anchors.centerIn: parent
2312- width: image.paintedWidth * image.scale
2313- height: image.paintedHeight * image.scale
2314-
2315- Image {
2316- id: image
2317- anchors.centerIn: parent
2318- width: flickable.width
2319- height: flickable.height
2320- fillMode: Image.PreserveAspectFit
2321- }
2322- }
2323-
2324- PinchArea {
2325- anchors.fill: parent
2326- pinch.target: image
2327- pinch.minimumScale: 1.0
2328- pinch.maximumScale: 5.0
2329- }
2330-
2331- // Go below the custom header
2332- z: -1
2333- }
2334-}
2335
2336=== removed file 'app/components/ListManager.qml'
2337--- app/components/ListManager.qml 2015-01-07 18:27:48 +0000
2338+++ app/components/ListManager.qml 1970-01-01 00:00:00 +0000
2339@@ -1,311 +0,0 @@
2340-/*
2341- This file is part of quick-memo
2342- Copyright (C) 2014 Stefano Verzegnassi
2343-
2344- This program is free software: you can redistribute it and/or modify
2345- it under the terms of the GNU General Public License 3 as published by
2346- the Free Software Foundation.
2347-
2348- This program is distributed in the hope that it will be useful,
2349- but WITHOUT ANY WARRANTY; without even the implied warranty of
2350- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2351- GNU General Public License for more details.
2352-
2353- You should have received a copy of the GNU General Public License
2354- along with this program. If not, see http://www.gnu.org/licenses/.
2355-*/
2356-
2357-import QtQuick 2.0
2358-import Ubuntu.Components 1.1
2359-import Ubuntu.Keyboard 0.1
2360-import Ubuntu.Components.ListItems 1.0 as ListItem
2361-
2362-Column {
2363- id: rootItem
2364-
2365- width: parent.width
2366- spacing: units.gu(0.25)
2367-
2368- property Flickable flickable
2369- property alias model: repeater.model
2370- property alias delegate: repeater.delegate
2371- property alias footer: footerLoader.sourceComponent
2372- readonly property bool focusOnLastItem: (model.focusedIndex === -1) || (model.focusedIndex === (model.count - 1))
2373-
2374- signal listChanged()
2375-
2376- ListItem.Header {
2377- text: i18n.tr("List:")
2378- }
2379-
2380- Repeater {
2381- id: repeater
2382- width: parent.width
2383-
2384- model: ListModel {
2385- id: dataModel
2386-
2387- property int focusedIndex: -1
2388- }
2389-
2390- delegate: delegate
2391- }
2392-
2393- // TODO: When user adds an element in the list, the new element should gain focus.
2394- Loader {
2395- id: footerLoader
2396- width: parent.width
2397-
2398- sourceComponent: ListItem.Empty {
2399- width: parent.width
2400- opacity: enabled ? 1.0 : 0.5
2401- showDivider: false
2402-
2403- enabled: {
2404- if (rootItem.model.count > 0) {
2405- if (rootItem.model.get(rootItem.model.count - 1).text !== "") {
2406- return true
2407- } else {
2408- return false
2409- }
2410- } else {
2411- return true
2412- }
2413- }
2414-
2415- Row {
2416- spacing: units.gu(2)
2417- anchors {
2418- left: parent.left; leftMargin: units.gu(2);
2419- right: parent.right;
2420- verticalCenter: parent.verticalCenter
2421- }
2422-
2423- Item {
2424- id: addListBtnImage
2425- implicitWidth: units.gu(4.25)
2426- implicitHeight: units.gu(4)
2427-
2428- Icon {
2429- anchors { fill: parent; margins: units.gu(0.5) }
2430- name: "add"
2431- }
2432- }
2433-
2434- Label {
2435- id: addListBtnLabel
2436- // TRANSLATORS: Text of a button used for add an item in the To-do list.
2437- text: i18n.tr("Add item")
2438- anchors.verticalCenter: addListBtnImage.verticalCenter
2439- }
2440- }
2441-
2442- onClicked: {
2443- rootItem.addItem({"checked": false, "text": ""})
2444- // Here we don't send listChanged signal, since it is an empty item that should not be saved
2445- }
2446- }
2447- }
2448-
2449-
2450- function exportModel() {
2451- var list = []
2452-
2453- if (rootItem.model.count > 0 && rootItem.model.get(0).text !== "") {
2454- for (var i=0; i<rootItem.model.count; i++) {
2455- if (i != rootItem.model.count && rootItem.model.get(i).text != "") {
2456- list[i] = rootItem.model.get(i)
2457- }
2458- }
2459- }
2460-
2461- return list
2462- }
2463-
2464- function addItem(args) {
2465- rootItem.model.append(args)
2466- var newItem = repeater.itemAt(repeater.count - 1)
2467- newItem.textArea.forceActiveFocus()
2468- autoScrollAnimation.makeMeVisible(newItem)
2469- }
2470-
2471- SequentialAnimation {
2472- id: autoScrollAnimation
2473-
2474- property var targetItem: null
2475- alwaysRunToEnd: true
2476-
2477- // wait item be moved to correct place
2478- PauseAnimation {
2479- duration: 100
2480- }
2481- // scroll to new item position
2482- ScriptAction {
2483- script: {
2484- if (autoScrollAnimation.targetItem) {
2485- autoScrollAnimation.makeMeVisibleImpl(autoScrollAnimation.targetItem)
2486- autoScrollAnimation.targetItem = null
2487- }
2488- }
2489- }
2490-
2491- function makeMeVisible(newItem) {
2492- autoScrollAnimation.targetItem = newItem
2493- autoScrollAnimation.restart()
2494- }
2495-
2496- function makeMeVisibleImpl(newItem) {
2497- if (!newItem) {
2498- return
2499- }
2500-
2501- var positionY = rootItem.y + repeater.y + newItem.y
2502-
2503- // check if the item is already visible
2504- var bottomY = flickable.contentY + flickable.height
2505- var itemBottom = positionY + (newItem.height *3) // margin
2506- if (positionY >= flickable.contentY && itemBottom <= bottomY) {
2507- return;
2508- }
2509-
2510- // if it is not, try to scroll and make it visible
2511- var targetY = itemBottom - flickable.height
2512- if (targetY >= 0 && positionY) {
2513- flickable.contentY = targetY
2514- } else if (positionY < flickable.contentY) {
2515- // if it is hidden at the top, also show it
2516- flickable.contentY = positionY
2517- }
2518- flickable.returnToBounds()
2519- }
2520- }
2521-
2522-
2523- // *** DELEGATE ***
2524- Component {
2525- id: delegate
2526-
2527- ListItem.Empty {
2528- id: item
2529- width: parent ? parent.width : undefined
2530- height: (layoutDelegate.height > item.__height) ? layoutDelegate.height : item.__height
2531-
2532- showDivider: false
2533-
2534- property alias textArea: textArea
2535-
2536- Rectangle {
2537- anchors.fill: parent
2538- opacity: 0.1
2539- visible: textArea.activeFocus
2540- color: "black"
2541- }
2542-
2543- backgroundIndicator: Rectangle {
2544- anchors.fill: parent
2545- color: "red"
2546-
2547- Icon {
2548- anchors.centerIn: parent
2549- name: "delete"
2550- color: Theme.palette.selected.field
2551- height: units.gu(3)
2552- width: units.gu(3)
2553- }
2554- }
2555-
2556- // ListItem is removable for all items, except the first when the text field is empty.
2557- //confirmRemoval: true
2558- removable: rootItem.model.count > 1 || (rootItem.model.get(0).text !== "")
2559- confirmRemoval: true
2560- onItemRemoved: {
2561- // Send the signal before removing the item. This avoids a ReferenceError.
2562- rootItem.listChanged()
2563- rootItem.model.remove(model.index)
2564- }
2565-
2566- Row {
2567- id: layoutDelegate
2568-
2569- anchors {
2570- left: parent.left
2571- right: parent.right
2572- margins: units.gu(2)
2573- verticalCenter: parent.verticalCenter
2574- }
2575-
2576- spacing: units.gu(1)
2577- height: Math.max(checkBox.height, textArea.height)
2578-
2579- CheckBox {
2580- id: checkBox
2581-
2582- checked: model.checked
2583- onCheckedChanged: layoutDelegate.updateModel()
2584-
2585- style: Item {
2586- implicitWidth: units.gu(4.25)
2587- implicitHeight: units.gu(4)
2588-
2589- Image {
2590- anchors { fill: parent; margins: units.gu(0.5) }
2591-
2592- source: checkBox.checked ? "../../graphics/select.svg" : "../../graphics/unselect.svg"
2593- }
2594- }
2595- }
2596-
2597- NoteTextField {
2598- id: textArea
2599-
2600- width: parent.width - (checkBox.width + (parent.spacing * 2))
2601- anchors.verticalCenter: parent.verticalCenter
2602-
2603- font.strikeout: checkBox.checked
2604-
2605- onFocusReceived: {
2606- rootItem.model.focusedIndex = model.index
2607- }
2608-
2609- text: model.text
2610- onTextChanged: {
2611- layoutDelegate.updateModel()
2612-
2613- /* This requires some test. No problem when TextField is used, but it seems to break dataModel when
2614- TextArea is used. Could be related to NoteTextArea.qml, line 39.*/
2615- if (text === "") {
2616- rootItem.model.remove(model.index)
2617- }
2618- }
2619-
2620- //hasClearButton: false
2621- focus: true
2622-
2623- // Ubuntu Keyboard
2624- // TODO: Disable Enter key if model.text is empty.
2625- InputMethod.extensions: {
2626- "enterKeyText": rootItem.focusOnLastItem ? i18n.tr("Add") : i18n.tr("Next")
2627- }
2628-
2629- Keys.onReturnPressed: {
2630- if (rootItem.focusOnLastItem && (model.text !== "")) {
2631- // Create a new item.
2632- rootItem.addItem({"checked": false, "text": ""})
2633- } else if (!rootItem.focusOnLastItem) {
2634- var nextItem = repeater.itemAt(model.index + 1)
2635- if (nextItem) {
2636- nextItem.textArea.forceActiveFocus()
2637- autoScrollAnimation.makeMeVisible(nextItem)
2638- }
2639- }
2640- }
2641- }
2642-
2643- function updateModel() {
2644- rootItem.model.set(model.index, {"checked": checkBox.checked, "text": textArea.text})
2645- rootItem.listChanged()
2646- }
2647- }
2648- }
2649- }
2650-}
2651
2652=== removed file 'app/components/ListViewDelegate.qml'
2653--- app/components/ListViewDelegate.qml 2014-11-06 05:09:59 +0000
2654+++ app/components/ListViewDelegate.qml 1970-01-01 00:00:00 +0000
2655@@ -1,299 +0,0 @@
2656-/*
2657- This file is part of quick-memo
2658- Copyright (C) 2014 Stefano Verzegnassi
2659-
2660- This program is free software: you can redistribute it and/or modify
2661- it under the terms of the GNU General Public License 3 as published by
2662- the Free Software Foundation.
2663-
2664- This program is distributed in the hope that it will be useful,
2665- but WITHOUT ANY WARRANTY; without even the implied warranty of
2666- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2667- GNU General Public License for more details.
2668-
2669- You should have received a copy of the GNU General Public License
2670- along with this program. If not, see http://www.gnu.org/licenses/.
2671-*/
2672-
2673-import QtQuick 2.0
2674-import Ubuntu.Components 1.1
2675-import Ubuntu.Thumbnailer 0.1
2676-import "dateHelper.js" as DateHelper
2677-
2678-AbstractButton {
2679- id: rootItem
2680-
2681- height: layout.height + layout.anchors.topMargin
2682- width: parent.width
2683-
2684- property bool selected: false
2685- property int maxListDelegatesNumber: 3
2686-
2687- // RGB channels from 'shape.color' are in [0; 1] range.
2688- property color foregroundColor: ((shape.color.r * 0.30 + shape.color.g * 0.59 + shape.color.b * 0.11) > 0.5) ? UbuntuColors.darkGrey : "#F3F3E7"
2689-
2690- UbuntuShape {
2691- id: shape
2692- anchors.fill: parent
2693-
2694- // Add 70% opacity
2695- color: contents.color.toString().replace("#", "#B3")
2696-
2697- radius: "medium"
2698-
2699- Column {
2700- id: layout
2701- anchors { top: parent.top; left: parent.left; right: parent.right; topMargin: units.gu(2) }
2702-
2703- Loader {
2704- x: units.gu(2)
2705- width: parent.width - x
2706- sourceComponent: (contents.title == "") ? undefined : titleComponent
2707-
2708- Component {
2709- id: titleComponent
2710-
2711- Label {
2712- width: parent.width
2713- fontSize: "large"
2714- font.weight: Font.Bold
2715- text: contents.title
2716- elide: Text.ElideRight
2717- maximumLineCount: 2
2718- wrapMode: Text.WrapAnywhere
2719- color: rootItem.foregroundColor
2720- }
2721- }
2722- }
2723-
2724- // A spacer item
2725- Item {
2726- width: parent.width
2727- height: units.gu(1)
2728- }
2729-
2730- Item {
2731- x: (column1.width > 0) ? units.gu(2) : 0
2732- width: parent.width - units.gu(4)
2733- height: Math.max(column1.height, column2.height)
2734-
2735- Column {
2736- id: column1
2737- anchors { left: parent.left; top: parent.top }
2738- width: ((contents.text == "") && (picsRepeater.count == 0)) ? 0
2739- : (listRepeater.count > 0) ? (parent.width * 0.5)
2740- : parent.width
2741- spacing: units.gu(2)
2742-
2743- Loader {
2744- width: parent.width
2745- sourceComponent: (contents.text == "") ? undefined : textComponent
2746-
2747- Component {
2748- id: textComponent
2749-
2750- Label {
2751- width: parent.width
2752- text: contents.text
2753- wrapMode: Text.WrapAnywhere
2754- elide: Text.ElideRight
2755- maximumLineCount: 5
2756- color: rootItem.foregroundColor
2757- }
2758- }
2759- }
2760-
2761- Item {
2762- id: picsItem
2763- width: parent.width
2764- height: picFlow.height
2765-
2766- // TODO: As for listDelegates, limit pics to a number of 9
2767- Flow {
2768- id: picFlow
2769- width: parent.width
2770-
2771- Repeater {
2772- id: picsRepeater
2773-
2774- model: contents.pictures
2775-
2776- delegate: Image {
2777- id: img
2778- width: parent.width
2779- fillMode: Image.PreserveAspectCrop
2780- source: "image://thumbnailer/" + Qt.resolvedUrl(contents.pictures[index].url)
2781-
2782- Connections {
2783- target: picsRepeater
2784- onItemAdded: calculateSize(index)
2785- onItemRemoved: calculateSize(index)
2786- }
2787-
2788- Connections {
2789- target: picFlow
2790- onWidthChanged: calculateSize(index)
2791- }
2792-
2793- Component.onCompleted: calculateSize(index)
2794-
2795- function calculateSize(index) {
2796- var n = picsRepeater.count
2797- var i = n % 3
2798- var m = Math.floor(n / 3)
2799-
2800- height = units.gu(6)
2801-
2802- // Need to be hardcoded because of an issue.
2803- // FIXME: Think it requires a better solution
2804- var picFlowRealWidth = column1.width - units.gu(1)
2805-
2806- switch(i) {
2807- case 0:
2808- width = picFlowRealWidth / 3
2809- return
2810- case 1:
2811- if (index == 0) {
2812- width = picFlowRealWidth
2813- return
2814- } else {
2815- width = picFlowRealWidth / 3
2816- return
2817- }
2818- case 2:
2819- if (index <= 1) {
2820- width = picFlowRealWidth / 2
2821- return
2822- } else {
2823- width = picFlowRealWidth / 3
2824- return
2825- }
2826- }
2827- }
2828- }
2829- }
2830-
2831- Component.onCompleted: picsRepeater.model = contents.pictures
2832- }
2833- }
2834- }
2835-
2836- Loader {
2837- anchors { right: column2.left; top: parent.top; bottom: parent.bottom; rightMargin: -units.gu(1) }
2838- sourceComponent: ((column2.width > 0) && (column1.width > 0)) ? divider : null
2839- width: 1
2840-
2841- Component {
2842- id: divider
2843- Rectangle {
2844- anchors.fill: parent
2845- color: foregroundColor
2846- opacity: 0.3
2847- }
2848- }
2849- }
2850-
2851- Column {
2852- id: column2
2853- anchors { left: column1.right; top: parent.top }
2854- width: (listRepeater.count > 0) ? ((contents.text == "") && (picsRepeater.count == 0)) ? parent.width
2855- : (parent.width * 0.5)
2856- : 0
2857-
2858- Repeater {
2859- id: listRepeater
2860- width: parent.width
2861-
2862- model: contents.list
2863-
2864- delegate: Loader {
2865- width: parent.width
2866- sourceComponent: model.index < 4 ? listDelegate : null
2867-
2868- Component {
2869- id: listDelegate
2870-
2871- Row {
2872- id: rootItem
2873- spacing: units.gu(1)
2874- width: parent.width
2875- height: Math.max(checkBox.height, textArea.height)
2876-
2877- Item {
2878- id: checkBox
2879- width: parent.width
2880- height: units.gu(4)
2881-
2882- property bool checked: contents.list[index].checked
2883-
2884- Icon {
2885- id: tick
2886- anchors {
2887- left: parent.left; leftMargin: units.gu(2.25);
2888- top: parent.top; topMargin: units.gu(0.35)
2889- }
2890- width: (source == "../../graphics/select.svg") ? units.gu(2.25) : units.gu(1.5)
2891- height: (source == "../../graphics/select.svg") ? units.gu(2) : units.gu(1.5)
2892-
2893- source: checkBox.checked ? "../../graphics/select.svg" : "../../graphics/unselect.svg"
2894- visible: model.index !== 3
2895- color: foregroundColor
2896- }
2897-
2898- Label {
2899- id: textArea
2900- anchors { left: tick.right; right: parent.right; margins: units.gu(1) }
2901-
2902- font.strikeout: checkBox.checked
2903- text: (model.index == 3) ? ". . ." : contents.list[index].text
2904- elide: Text.ElideRight
2905- maximumLineCount: 2
2906- wrapMode: Text.WrapAnywhere
2907- color: foregroundColor
2908- }
2909- }
2910- }
2911- }
2912- }
2913- }
2914- }
2915- }
2916-
2917- // A spacer item
2918- Item {
2919- width: parent.width
2920- height: units.gu(1)
2921- }
2922-
2923- Item {
2924- id: date
2925- width: parent.width
2926- height: units.gu(4)
2927-
2928- Label {
2929- anchors { right: parent.right; verticalCenter: parent.verticalCenter; margins: units.gu(2) }
2930- text: Qt.formatDateTime(DateHelper.parseDate(contents.date), "d MMM yyyy, hh:mm")
2931- fontSize: "small"
2932- color: rootItem.foregroundColor
2933- }
2934- }
2935- }
2936- }
2937-
2938- // Visual feedback when pressed. Not listed in official documentation, still useful.
2939- onPressedChanged: {
2940- if (pressed)
2941- shape.borderSource = "radius_pressed.sci"
2942- else
2943- shape.borderSource = "radius_idle.sci"
2944- }
2945-
2946- // Visual feedback when selected.
2947- onSelectedChanged: {
2948- if (selected) {
2949- shape.color = Qt.darker(contents.color)
2950- } else {
2951- shape.color = contents.color.toString().replace("#", "#B3")
2952- }
2953- }
2954-}
2955
2956=== renamed file 'app/components/MainPage.qml' => 'app/components/MainPage.qml.THIS'
2957=== removed file 'app/components/MultiSelectionHandler.qml'
2958--- app/components/MultiSelectionHandler.qml 2014-11-03 00:21:23 +0000
2959+++ app/components/MultiSelectionHandler.qml 1970-01-01 00:00:00 +0000
2960@@ -1,106 +0,0 @@
2961-/*
2962- This file is part of quick-memo
2963- Copyright (C) 2014 Stefano Verzegnassi
2964-
2965- This program is free software: you can redistribute it and/or modify
2966- it under the terms of the GNU General Public License 3 as published by
2967- the Free Software Foundation.
2968-
2969- This program is distributed in the hope that it will be useful,
2970- but WITHOUT ANY WARRANTY; without even the implied warranty of
2971- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2972- GNU General Public License for more details.
2973-
2974- You should have received a copy of the GNU General Public License
2975- along with this program. If not, see http://www.gnu.org/licenses/.
2976-*/
2977-
2978-import QtQuick 2.0
2979-import Ubuntu.Components 1.1
2980-
2981-PageHeadState {
2982- id: rootItem
2983-
2984- property string title
2985-
2986- property var indexes: []
2987- property int count: rootItem.indexes.length
2988- property Page targetPage
2989-
2990- head: targetPage.head
2991-
2992- backAction: Action {
2993- text: i18n.tr("Cancel")
2994- iconName: "back"
2995- onTriggered: targetPage.state = "default"
2996- }
2997-
2998- contents: Item {
2999- anchors.fill: parent
3000-
3001- Connections {
3002- target: targetPage
3003- onStateChanged: {
3004- if (targetPage.state !== "multiSelection") {
3005- // Clean the model
3006- rootItem.indexes = []
3007- }
3008- }
3009- }
3010-
3011- Label {
3012- fontSize: "x-large"
3013-
3014- // See LP:1184810
3015- text: (rootItem.count == 0) ? i18n.tr("No item selected")
3016- : i18n.tr("%1 item selected", "%1 items selected", rootItem.count).arg(rootItem.count)
3017-
3018- anchors.verticalCenter: parent.verticalCenter
3019- }
3020-
3021- // Provide a visual feedback when active
3022- Rectangle {
3023- id: headerBg
3024- parent: targetPage.header
3025- z: -10
3026-
3027- width: targetPage.width
3028- height: targetPage.header.height
3029- color: "#19B6EE" // Cyan
3030- visible: mainPage.state == "multiSelection"
3031- }
3032- }
3033-
3034- signal indexAdded(var index)
3035- signal indexRemoved(var index)
3036-
3037- function selectUnselectItem(index) {
3038- for (var i=0; i<rootItem.indexes.length; i++) {
3039- // Search for index in the model
3040- if (rootItem.indexes[i] === index) {
3041- // That means it's already in, so remove it.
3042- rootItem.indexes.splice(i, 1);
3043-
3044- // Update count and header
3045- rootItem.count = rootItem.indexes.length
3046-
3047- // Return false if the index is removed.
3048- rootItem.indexRemoved(index)
3049- return false
3050- }
3051- }
3052-
3053- // Otherwise, the item is not in the model, so add it.
3054- rootItem.indexes.push(index)
3055-
3056- // Update count
3057- rootItem.count = rootItem.indexes.length
3058-
3059- // Sort indexes, so that it's easier to use the indexes we collect.
3060- indexes.sort(function(a,b) {return a-b})
3061-
3062- // Return true if the index is added
3063- rootItem.indexAdded(index)
3064- return true
3065- }
3066-}
3067
3068=== removed file 'app/components/NoteModel.qml'
3069--- app/components/NoteModel.qml 2014-08-21 20:09:02 +0000
3070+++ app/components/NoteModel.qml 1970-01-01 00:00:00 +0000
3071@@ -1,119 +0,0 @@
3072-/*
3073- This file is part of quick-memo
3074- Copyright (C) 2014 Stefano Verzegnassi
3075-
3076- This program is free software: you can redistribute it and/or modify
3077- it under the terms of the GNU General Public License 3 as published by
3078- the Free Software Foundation.
3079-
3080- This program is distributed in the hope that it will be useful,
3081- but WITHOUT ANY WARRANTY; without even the implied warranty of
3082- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3083- GNU General Public License for more details.
3084-
3085- You should have received a copy of the GNU General Public License
3086- along with this program. If not, see http://www.gnu.org/licenses/.
3087-*/
3088-
3089-import QtQuick 2.0
3090-import U1db 1.0 as U1db
3091-import Ubuntu.Components 1.1
3092-
3093-Item {
3094- id: rootItem
3095- property alias model: model
3096-
3097- signal initialized()
3098-
3099- // *** functions
3100- function addNote(noteTitle, noteText, noteColor, noteList, notePictures) {
3101- // Get the current date
3102- var dateString = new Date().valueOf()
3103-
3104- db.putDoc(JSON.stringify({memos: {title: noteTitle, text: noteText, color: noteColor, date: dateString, list: noteList, pictures: notePictures}}))
3105- }
3106-
3107- // Function used for changing a single value of the note
3108- function setNoteProperty(index, field, value) {
3109- var obj = JSON.parse(JSON.stringify(model.get(index)))
3110-
3111- // Edit the required property
3112- switch(field) {
3113- case "title":
3114- obj.contents.title = value
3115- break
3116- case "text":
3117- obj.contents.text = value
3118- break
3119- case "color":
3120- // The char '#' from the hex color is not correctly parse by JSON. We add an empty string, so that it works well.
3121- obj.contents.color = "" + value
3122- break
3123- case "list":
3124- obj.contents.list = value
3125- break
3126- case "pictures":
3127- obj.contents.pictures = value
3128- }
3129-
3130- // Get the current date and update the time of the last update
3131- obj.contents.date = new Date().valueOf()
3132-
3133- db.putDoc(JSON.stringify({memos: obj.contents}), obj.docId)
3134- }
3135-
3136- // Function used for rewriting the whole content of the note. json variant is a JSON object.
3137- function editNote(index, json) {
3138- var obj = json
3139-
3140- // Get the current date and update the time of the last update
3141- obj.contents.date = new Date().valueOf()
3142-
3143- console.log(JSON.stringify({memos: obj.contents}))
3144- db.putDoc(JSON.stringify({memos: obj.contents}), obj.docId)
3145- }
3146-
3147-
3148- function deleteNote(index) {
3149- db.deleteDoc(model.get(index).docId)
3150- }
3151-
3152- function deleteNotes(indexes) {
3153- var deletedItemNumber = 0;
3154- for (var i=0; i<indexes.length; i++) {
3155- db.deleteDoc(model.get(indexes[i] - deletedItemNumber).docId)
3156- deletedItemNumber++
3157- }
3158- }
3159-
3160- // *** U1db database
3161- U1db.Database {
3162- id: db
3163- path: "quick-memo"
3164- Component.onCompleted: {
3165- // TODO: Delete pictures that are not used by the notes at startup.
3166- rootItem.initialized()
3167- }
3168- }
3169-
3170- // TODO: More queries, more pages, a more powerful app.
3171- // TODO: Search feature. Use "filter" from SortFilterModel?
3172- SortFilterModel {
3173- id: model
3174- sort {
3175- property: "date"
3176- order: Qt.DescendingOrder
3177- }
3178-
3179- model: U1db.Query {
3180- id: query
3181- index: U1db.Index {
3182- database: db
3183- expression: ["memos.docId", "memos.title", "memos.text", "memos.color", "memos.date", "memos.list", "memos.pictures"]
3184- }
3185- query: ["*", "*", "*", "*", "*", "*", "*"]
3186- }
3187- }
3188-
3189-
3190-}
3191
3192=== removed file 'app/components/NoteTextArea.qml'
3193--- app/components/NoteTextArea.qml 2014-10-04 00:46:31 +0000
3194+++ app/components/NoteTextArea.qml 1970-01-01 00:00:00 +0000
3195@@ -1,59 +0,0 @@
3196-/*
3197- This file is part of quick-memo
3198- Copyright (C) 2014 Stefano Verzegnassi
3199-
3200- This program is free software: you can redistribute it and/or modify
3201- it under the terms of the GNU General Public License 3 as published by
3202- the Free Software Foundation.
3203-
3204- This program is distributed in the hope that it will be useful,
3205- but WITHOUT ANY WARRANTY; without even the implied warranty of
3206- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3207- GNU General Public License for more details.
3208-
3209- You should have received a copy of the GNU General Public License
3210- along with this program. If not, see http://www.gnu.org/licenses/.
3211-*/
3212-
3213-import QtQuick 2.0
3214-import Ubuntu.Components 1.1
3215-import Ubuntu.Components.Themes.Ambiance 0.1
3216-
3217-TextArea {
3218- id: rootItem
3219- width: parent.width
3220-
3221- autoSize: true
3222- maximumLineCount: 0
3223-
3224- // Prevent data loss
3225- inputMethodHints: Qt.ImhNoPredictiveText
3226-
3227- opacity: 1.0
3228-
3229- signal focusLost()
3230- signal textReallyChanged
3231-
3232- property string __oldText: ""
3233- onTextChanged: {
3234- //WORKAROUND: textChanged seems to be emitted also when TextArea has the activeFocus (and text does not change).
3235- if (__oldText !== text) {
3236- rootItem.textReallyChanged()
3237- __oldText = text;
3238- }
3239- }
3240-
3241- InverseMouseArea {
3242- visible: parent.activeFocus
3243- anchors.fill: parent
3244- onClicked: {
3245- rootItem.focusLost()
3246- mouse.accepted = false
3247- }
3248- }
3249-
3250- style: TextAreaStyle {
3251- frameSpacing: 0
3252- background: Item { anchors.fill: parent }
3253- }
3254-}
3255
3256=== removed file 'app/components/NoteTextField.qml'
3257--- app/components/NoteTextField.qml 2015-01-07 18:27:48 +0000
3258+++ app/components/NoteTextField.qml 1970-01-01 00:00:00 +0000
3259@@ -1,53 +0,0 @@
3260-/*
3261- This file is part of quick-memo
3262- Copyright (C) 2014 Stefano Verzegnassi
3263-
3264- This program is free software: you can redistribute it and/or modify
3265- it under the terms of the GNU General Public License 3 as published by
3266- the Free Software Foundation.
3267-
3268- This program is distributed in the hope that it will be useful,
3269- but WITHOUT ANY WARRANTY; without even the implied warranty of
3270- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3271- GNU General Public License for more details.
3272-
3273- You should have received a copy of the GNU General Public License
3274- along with this program. If not, see http://www.gnu.org/licenses/.
3275-*/
3276-
3277-import QtQuick 2.0
3278-import Ubuntu.Components 1.1
3279-import Ubuntu.Components.Themes.Ambiance 0.1
3280-
3281-import "../ubuntucomponents" as UbuntuComponents
3282-
3283-// WORKAROUND: We need a 'custom' version of TextField in wait of LP:1376510 to be fixed.
3284-// FIXME: Some issue with InputHandler (e.g. Keys.Down or Keys.PgDown) but we don't care it, since at the moment the main focus is not desktop.
3285-UbuntuComponents.TextField {
3286- id: textArea
3287- width: parent.width - (checkBox.width + (parent.spacing * 2))
3288-
3289- // Dynamic height: units.gu(3) = implicitHeight - (frameSpacing * 2)
3290- height: (contentHeight > units.gu(3)) ? contentHeight : units.gu(3)
3291-
3292- wrapMode: TextInput.Wrap
3293-
3294- // Prevent data loss
3295- inputMethodHints: Qt.ImhNoPredictiveText
3296-
3297- signal focusLost()
3298- signal focusReceived()
3299-
3300- onActiveFocusChanged: {
3301- if (activeFocus) {
3302- focusReceived()
3303- } else {
3304- focusLost()
3305- }
3306- }
3307-
3308- style: TextFieldStyle {
3309- frameSpacing: 0
3310- background: Item { anchors.fill: parent }
3311- }
3312-}
3313
3314=== removed file 'app/components/PageBackground.qml'
3315--- app/components/PageBackground.qml 2014-09-28 23:58:26 +0000
3316+++ app/components/PageBackground.qml 1970-01-01 00:00:00 +0000
3317@@ -1,25 +0,0 @@
3318-import QtQuick 2.0
3319-
3320-// Background
3321-Rectangle {
3322- id: bg
3323- anchors.fill: parent
3324- z: -10; opacity: 0.5
3325-
3326- property bool __parentPageAboutToBeClosed: false
3327-
3328- /* MainView clips its content, so that it does not overlap the header.
3329- We need to bypass this, using another Rectangle that specifically overlap the header. */
3330- Rectangle {
3331- parent: root.header
3332- z: -10; opacity: 0.5
3333-
3334- width: root.width
3335- height: root.header.height
3336- color: bg.color
3337-
3338- // FIXME: Header background should progressively change opacity to 0.0 when the BottomEdge page is dismissed.
3339- visible: !bg.__parentPageAboutToBeClosed
3340- }
3341-}
3342-
3343
3344=== removed file 'app/components/PageWithBottomEdge.qml'
3345--- app/components/PageWithBottomEdge.qml 2014-10-21 16:01:52 +0000
3346+++ app/components/PageWithBottomEdge.qml 1970-01-01 00:00:00 +0000
3347@@ -1,407 +0,0 @@
3348-/*
3349- * Copyright (C) 2014 Canonical, Ltd.
3350- *
3351- * This program is free software; you can redistribute it and/or modify
3352- * it under the terms of the GNU General Public License as published by
3353- * the Free Software Foundation; version 3.
3354- *
3355- * This program is distributed in the hope that it will be useful,
3356- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3357- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3358- * GNU General Public License for more details.
3359- *
3360- * You should have received a copy of the GNU General Public License
3361- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3362- */
3363-
3364-/*
3365- Example:
3366-
3367- MainView {
3368- objectName: "mainView"
3369-
3370- applicationName: "com.ubuntu.developer.boiko.bottomedge"
3371-
3372- width: units.gu(100)
3373- height: units.gu(75)
3374-
3375- Component {
3376- id: pageComponent
3377-
3378- PageWithBottomEdge {
3379- id: mainPage
3380- title: i18n.tr("Main Page")
3381-
3382- Rectangle {
3383- anchors.fill: parent
3384- color: "white"
3385- }
3386-
3387- bottomEdgePageComponent: Page {
3388- title: "Contents"
3389- anchors.fill: parent
3390- //anchors.topMargin: contentsPage.flickable.contentY
3391-
3392- ListView {
3393- anchors.fill: parent
3394- model: 50
3395- delegate: ListItems.Standard {
3396- text: "One Content Item: " + index
3397- }
3398- }
3399- }
3400- bottomEdgeTitle: i18n.tr("Bottom edge action")
3401- }
3402- }
3403-
3404- PageStack {
3405- id: stack
3406- Component.onCompleted: stack.push(pageComponent)
3407- }
3408- }
3409-
3410-*/
3411-
3412-import QtQuick 2.2
3413-import Ubuntu.Components 1.1
3414-
3415-Page {
3416- id: page
3417-
3418- property alias bottomEdgePageComponent: edgeLoader.sourceComponent
3419- property alias bottomEdgePageSource: edgeLoader.source
3420- property alias bottomEdgeTitle: tipLabel.text
3421- property bool bottomEdgeEnabled: true
3422- property int bottomEdgeExpandThreshold: page.height * 0.2
3423- property int bottomEdgeExposedArea: bottomEdge.state !== "expanded" ? (page.height - bottomEdge.y - bottomEdge.tipHeight) : _areaWhenExpanded
3424- property bool reloadBottomEdgePage: true
3425-
3426- readonly property alias bottomEdgePage: edgeLoader.item
3427- readonly property bool isReady: ((bottomEdge.y === 0) && bottomEdgePageLoaded && edgeLoader.item.active)
3428- readonly property bool isCollapsed: (bottomEdge.y === page.height)
3429- readonly property bool bottomEdgePageLoaded: (edgeLoader.status == Loader.Ready)
3430-
3431- property bool _showEdgePageWhenReady: false
3432- property int _areaWhenExpanded: 0
3433-
3434- signal bottomEdgeReleased()
3435- signal bottomEdgeDismissed()
3436-
3437-
3438- function showBottomEdgePage(source, properties)
3439- {
3440- edgeLoader.setSource(source, properties)
3441- _showEdgePageWhenReady = true
3442- }
3443-
3444- function setBottomEdgePage(source, properties)
3445- {
3446- edgeLoader.setSource(source, properties)
3447- }
3448-
3449- function _pushPage()
3450- {
3451- if (edgeLoader.status === Loader.Ready) {
3452- edgeLoader.item.active = true
3453- page.pageStack.push(edgeLoader.item)
3454- if (edgeLoader.item.flickable) {
3455- edgeLoader.item.flickable.contentY = -page.header.height
3456- edgeLoader.item.flickable.returnToBounds()
3457- }
3458- if (edgeLoader.item.ready)
3459- edgeLoader.item.ready()
3460- }
3461- }
3462-
3463-
3464- Component.onCompleted: {
3465- // avoid a binding on the expanded height value
3466- var expandedHeight = height;
3467- _areaWhenExpanded = expandedHeight;
3468- }
3469-
3470- onActiveChanged: {
3471- if (active) {
3472- bottomEdge.state = "collapsed"
3473- }
3474- }
3475-
3476- onBottomEdgePageLoadedChanged: {
3477- if (_showEdgePageWhenReady && bottomEdgePageLoaded) {
3478- bottomEdge.state = "expanded"
3479- _showEdgePageWhenReady = false
3480- }
3481- }
3482-
3483- Rectangle {
3484- id: bgVisual
3485-
3486- color: "black"
3487- anchors.fill: page
3488- opacity: 0.7 * ((page.height - bottomEdge.y) / page.height)
3489- z: 1
3490- }
3491-
3492- UbuntuShape {
3493- id: tip
3494- objectName: "bottomEdgeTip"
3495-
3496- property bool hidden: (activeFocus === false) || ((bottomEdge.y - units.gu(1)) < tip.y)
3497-
3498- enabled: mouseArea.enabled
3499- visible: page.bottomEdgeEnabled
3500- anchors {
3501- bottom: parent.bottom
3502- horizontalCenter: bottomEdge.horizontalCenter
3503- bottomMargin: hidden ? - height + units.gu(1) : -units.gu(1)
3504- Behavior on bottomMargin {
3505- SequentialAnimation {
3506- // wait some msecs in case of the focus change again, to avoid flickering
3507- PauseAnimation {
3508- duration: 300
3509- }
3510- UbuntuNumberAnimation {
3511- duration: UbuntuAnimation.SnapDuration
3512- }
3513- }
3514- }
3515- }
3516-
3517- z: 1
3518- width: tipLabel.paintedWidth + units.gu(6)
3519- height: bottomEdge.tipHeight + units.gu(1)
3520- color: Theme.palette.normal.overlay
3521- Label {
3522- id: tipLabel
3523-
3524- anchors {
3525- top: parent.top
3526- left: parent.left
3527- right: parent.right
3528- }
3529- height: bottomEdge.tipHeight
3530- verticalAlignment: Text.AlignVCenter
3531- horizontalAlignment: Text.AlignHCenter
3532- opacity: tip.hidden ? 0.0 : 1.0
3533- Behavior on opacity {
3534- UbuntuNumberAnimation {
3535- duration: UbuntuAnimation.SnapDuration
3536- }
3537- }
3538- }
3539- }
3540-
3541- Rectangle {
3542- id: shadow
3543-
3544- anchors {
3545- left: parent.left
3546- right: parent.right
3547- bottom: parent.bottom
3548- }
3549- height: units.gu(1)
3550- z: 1
3551- opacity: 0.0
3552- gradient: Gradient {
3553- GradientStop { position: 0.0; color: "transparent" }
3554- GradientStop { position: 1.0; color: Qt.rgba(0, 0, 0, 0.2) }
3555- }
3556- }
3557-
3558- MouseArea {
3559- id: mouseArea
3560-
3561- property real previousY: -1
3562- property string dragDirection: "None"
3563-
3564- preventStealing: true
3565- drag {
3566- axis: Drag.YAxis
3567- target: bottomEdge
3568- minimumY: bottomEdge.pageStartY
3569- maximumY: page.height
3570- }
3571- enabled: edgeLoader.status == Loader.Ready
3572- visible: page.bottomEdgeEnabled
3573-
3574- anchors {
3575- left: parent.left
3576- right: parent.right
3577- bottom: parent.bottom
3578-
3579- }
3580- height: bottomEdge.tipHeight
3581- z: 1
3582-
3583- onReleased: {
3584- page.bottomEdgeReleased()
3585- if ((dragDirection === "BottomToTop") &&
3586- bottomEdge.y < (page.height - bottomEdgeExpandThreshold - bottomEdge.tipHeight)) {
3587- bottomEdge.state = "expanded"
3588- } else {
3589- bottomEdge.state = "collapsed"
3590- }
3591- previousY = -1
3592- dragDirection = "None"
3593- }
3594-
3595- onPressed: {
3596- previousY = mouse.y
3597- tip.forceActiveFocus()
3598- }
3599-
3600- onMouseYChanged: {
3601- var yOffset = previousY - mouseY
3602- // skip if was a small move
3603- if (Math.abs(yOffset) <= units.gu(2)) {
3604- return
3605- }
3606- previousY = mouseY
3607- dragDirection = yOffset > 0 ? "BottomToTop" : "TopToBottom"
3608- }
3609- }
3610-
3611- Rectangle {
3612- id: bottomEdge
3613- objectName: "bottomEdge"
3614-
3615- readonly property int tipHeight: units.gu(3)
3616- readonly property int pageStartY: 0
3617-
3618- z: 1
3619- color: Theme.palette.normal.background
3620- clip: true
3621- anchors {
3622- left: parent.left
3623- right: parent.right
3624- }
3625- height: page.height
3626- y: height
3627- visible: !page.isCollapsed
3628- state: "collapsed"
3629- states: [
3630- State {
3631- name: "collapsed"
3632- PropertyChanges {
3633- target: bottomEdge
3634- y: bottomEdge.height
3635- }
3636- },
3637- State {
3638- name: "expanded"
3639- PropertyChanges {
3640- target: bottomEdge
3641- y: bottomEdge.pageStartY
3642- }
3643- },
3644- State {
3645- name: "floating"
3646- when: mouseArea.drag.active
3647- PropertyChanges {
3648- target: shadow
3649- opacity: 1.0
3650- }
3651- }
3652- ]
3653-
3654- transitions: [
3655- Transition {
3656- to: "expanded"
3657- SequentialAnimation {
3658- alwaysRunToEnd: true
3659-
3660- SmoothedAnimation {
3661- target: bottomEdge
3662- property: "y"
3663- duration: UbuntuAnimation.FastDuration
3664- easing.type: Easing.Linear
3665- }
3666- SmoothedAnimation {
3667- target: edgeLoader
3668- property: "anchors.topMargin"
3669- to: - units.gu(4)
3670- duration: UbuntuAnimation.FastDuration
3671- easing.type: Easing.Linear
3672- }
3673- SmoothedAnimation {
3674- target: edgeLoader
3675- property: "anchors.topMargin"
3676- to: 0
3677- duration: UbuntuAnimation.FastDuration
3678- easing: UbuntuAnimation.StandardEasing
3679- }
3680- ScriptAction {
3681- script: page._pushPage()
3682- }
3683- }
3684- },
3685- Transition {
3686- from: "expanded"
3687- to: "collapsed"
3688- SequentialAnimation {
3689- alwaysRunToEnd: true
3690-
3691- ScriptAction {
3692- script: {
3693- Qt.inputMethod.hide()
3694- edgeLoader.item.parent = edgeLoader
3695- edgeLoader.item.anchors.fill = edgeLoader
3696- edgeLoader.item.active = false
3697- }
3698- }
3699- SmoothedAnimation {
3700- target: bottomEdge
3701- property: "y"
3702- duration: UbuntuAnimation.SlowDuration
3703- }
3704- ScriptAction {
3705- script: {
3706- // destroy current bottom page
3707- if (page.reloadBottomEdgePage) {
3708- edgeLoader.active = false
3709- // tip will receive focus on page active true
3710- } else {
3711- tip.forceActiveFocus()
3712- }
3713-
3714- // notify
3715- page.bottomEdgeDismissed()
3716-
3717- edgeLoader.active = true
3718- }
3719- }
3720- }
3721- },
3722- Transition {
3723- from: "floating"
3724- to: "collapsed"
3725- SmoothedAnimation {
3726- target: bottomEdge
3727- property: "y"
3728- duration: UbuntuAnimation.FastDuration
3729- }
3730- }
3731- ]
3732-
3733- Loader {
3734- id: edgeLoader
3735-
3736- asynchronous: true
3737- anchors.fill: parent
3738- //WORKAROUND: The SDK move the page contents down to allocate space for the header we need to avoid that during the page dragging
3739- Binding {
3740- target: edgeLoader.status === Loader.Ready ? edgeLoader : null
3741- property: "anchors.topMargin"
3742- value: edgeLoader.item && edgeLoader.item.flickable ? edgeLoader.item.flickable.contentY : 0
3743- when: !page.isReady
3744- }
3745-
3746- onLoaded: {
3747- tip.forceActiveFocus()
3748- if (page.isReady && edgeLoader.item.active !== true) {
3749- page._pushPage()
3750- }
3751- }
3752- }
3753- }
3754-}
3755
3756=== removed file 'app/components/PictureButton.qml'
3757--- app/components/PictureButton.qml 2014-10-04 17:44:08 +0000
3758+++ app/components/PictureButton.qml 1970-01-01 00:00:00 +0000
3759@@ -1,40 +0,0 @@
3760-/*
3761- This file is part of quick-memo
3762- Copyright (C) 2014 Stefano Verzegnassi
3763-
3764- This program is free software: you can redistribute it and/or modify
3765- it under the terms of the GNU General Public License 3 as published by
3766- the Free Software Foundation.
3767-
3768- This program is distributed in the hope that it will be useful,
3769- but WITHOUT ANY WARRANTY; without even the implied warranty of
3770- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3771- GNU General Public License for more details.
3772-
3773- You should have received a copy of the GNU General Public License
3774- along with this program. If not, see http://www.gnu.org/licenses/.
3775-*/
3776-
3777-import QtQuick 2.0
3778-import Ubuntu.Components 1.1
3779-
3780-AbstractButton {
3781- id: rootItem
3782- width: units.gu(8)
3783- height: units.gu(8)
3784-
3785- property alias image: shape.image
3786- default property alias contentsItem: shape.data
3787-
3788- onPressedChanged: {
3789- if (pressed)
3790- shape.borderSource = "radius_pressed.sci"
3791- else
3792- shape.borderSource = "radius_idle.sci"
3793- }
3794-
3795- UbuntuShape {
3796- id: shape
3797- anchors.fill: parent
3798- }
3799-}
3800
3801=== removed file 'app/components/PicturesManager.qml'
3802--- app/components/PicturesManager.qml 2014-10-21 18:21:13 +0000
3803+++ app/components/PicturesManager.qml 1970-01-01 00:00:00 +0000
3804@@ -1,162 +0,0 @@
3805-/*
3806- This file is part of quick-memo
3807- Copyright (C) 2014 Stefano Verzegnassi
3808-
3809- This program is free software: you can redistribute it and/or modify
3810- it under the terms of the GNU General Public License 3 as published by
3811- the Free Software Foundation.
3812-
3813- This program is distributed in the hope that it will be useful,
3814- but WITHOUT ANY WARRANTY; without even the implied warranty of
3815- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3816- GNU General Public License for more details.
3817-
3818- You should have received a copy of the GNU General Public License
3819- along with this program. If not, see http://www.gnu.org/licenses/.
3820-*/
3821-
3822-import QtQuick 2.0
3823-import Ubuntu.Components 1.1
3824-import Ubuntu.Thumbnailer 0.1
3825-import Ubuntu.Content 0.1
3826-import Ubuntu.Components.Popups 1.0
3827-import Ubuntu.Components.ListItems 1.0 as ListItem
3828-
3829-Item {
3830- id: rootItem
3831-
3832- property alias model: repeater.model
3833-
3834- width: parent.width
3835- height: childrenRect.height
3836-
3837- signal picsModelChanged()
3838-
3839- function exportModel() {
3840- var list = []
3841- for (var i=0; i<picModel.count; i++) {
3842- list[i] = picModel.get(i)
3843- }
3844-
3845- return list
3846- }
3847-
3848- ListItem.Header { id: header; text: i18n.tr("Related pictures:") }
3849-
3850- Flow {
3851- id: flow
3852-
3853- anchors {
3854- top: header.bottom; topMargin: units.gu(1)
3855- left: parent.left
3856- right: parent.right
3857- margins: units.gu(2)
3858- }
3859- spacing: units.gu(2)
3860-
3861- Repeater {
3862- id: repeater
3863-
3864- model: ListModel { id: picModel; onRowsRemoved: rootItem.picsModelChanged() }
3865- delegate: PictureButton {
3866- image: Image {
3867- source: "image://thumbnailer/" + Qt.resolvedUrl(model.url)
3868- fillMode: Image.PreserveAspectCrop
3869- }
3870-
3871- //TODO: Add right click support
3872- onClicked: pageStack.push(Qt.resolvedUrl("./ImageViewer.qml"), {source: Qt.resolvedUrl(model.url)})
3873- onPressAndHold: PopupUtils.open(pictureMenuPopover, this, {index: model.index})
3874- }
3875- }
3876-
3877- PictureButton {
3878- Icon {
3879- anchors.centerIn: parent
3880- height: parent.height / 2
3881- width: height
3882- name: "add"
3883- }
3884-
3885- onClicked: rootItem.importImageFromContentHub()
3886- }
3887- }
3888-
3889- // *** CONTENT HANDLER ***
3890- //This should be probably moved in main.qml
3891- property var activeTransfer
3892-
3893- function importImageFromContentHub() {
3894- pageStack.push(picker)
3895- }
3896-
3897- Page {
3898- id: picker
3899- visible: false
3900-
3901- ContentPeerPicker {
3902- visible: parent.visible
3903-
3904- contentType: ContentType.Pictures
3905- handler: ContentHandler.Source
3906-
3907- onPeerSelected: {
3908- rootItem.activeTransfer = peer.request(appStore);
3909- pageStack.pop();
3910- }
3911-
3912- onCancelPressed: {
3913- pageStack.pop();
3914- }
3915- }
3916- }
3917-
3918- ContentTransferHint {
3919- id: transferHint
3920- anchors.fill: parent
3921- activeTransfer: rootItem.activeTransfer
3922- }
3923-
3924- ContentStore {
3925- id: appStore
3926- scope: ContentScope.App
3927- }
3928-
3929- Connections {
3930- target: rootItem.activeTransfer ? rootItem.activeTransfer : null
3931- onStateChanged: {
3932- if (rootItem.activeTransfer.state === ContentTransfer.Charged) {
3933- for (var i=0; i<rootItem.activeTransfer.items.length; i++) {
3934- picModel.append({url: rootItem.activeTransfer.items[i].url.toString().replace("file://", "")})
3935- console.log("CONTENT IMPORTED:", rootItem.activeTransfer.items[i].url.toString().replace("file://", ""))
3936- rootItem.picsModelChanged()
3937- }
3938- }
3939- }
3940- }
3941-
3942- // *** PICTURE POPOVER ***
3943- Component {
3944- id: pictureMenuPopover
3945- ActionSelectionPopover {
3946- id: popover
3947- property int index
3948-
3949- actions: ActionList {
3950- Action {
3951- text: i18n.tr("Remove picture from selection")
3952- onTriggered: {
3953- PopupUtils.close(popover)
3954- rootItem.model.remove(popover.index)
3955- }
3956- }
3957- }
3958-
3959- delegate: ListItem.Standard {
3960- // ForegroundColor is not correctly set
3961- __foregroundColor: Theme.palette.normal.overlayText
3962- showDivider: false
3963- }
3964- }
3965- }
3966-}
3967
3968=== removed file 'app/components/Toaster.qml'
3969--- app/components/Toaster.qml 2014-10-22 12:43:11 +0000
3970+++ app/components/Toaster.qml 1970-01-01 00:00:00 +0000
3971@@ -1,81 +0,0 @@
3972-/*
3973- This file is part of quick-memo
3974- Copyright (C) 2014 Stefano Verzegnassi
3975-
3976- This program is free software: you can redistribute it and/or modify
3977- it under the terms of the GNU General Public License 3 as published by
3978- the Free Software Foundation.
3979-
3980- This program is distributed in the hope that it will be useful,
3981- but WITHOUT ANY WARRANTY; without even the implied warranty of
3982- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3983- GNU General Public License for more details.
3984-
3985- You should have received a copy of the GNU General Public License
3986- along with this program. If not, see http://www.gnu.org/licenses/.
3987-*/
3988-
3989-import QtQuick 2.0
3990-import Ubuntu.Components 1.1
3991-
3992-Rectangle {
3993- id: rootItem
3994-
3995- property alias text: label.text
3996-
3997- width: parent.width
3998- height: units.gu(8)
3999-
4000- color: "#131313"
4001- opacity: 0.85
4002-
4003- anchors {
4004- horizontalCenter: parent.horizontalCenter
4005- bottom: parent.bottom; bottomMargin: - height
4006- }
4007-
4008- Label {
4009- id: label
4010- anchors.centerIn: parent
4011-
4012- font.weight: Font.DemiBold
4013- color: "white"
4014- }
4015-
4016- MouseArea {
4017- anchors.fill: parent
4018-
4019- onClicked: {
4020- showAnimation.stop()
4021- destroyAnimation.restart()
4022- }
4023- }
4024-
4025- Rectangle {
4026- anchors {
4027- bottom: parent.bottom
4028- left: parent.left
4029- right: parent.right
4030- }
4031-
4032- height: units.dp(2)
4033- color: UbuntuColors.orange
4034- }
4035-
4036- SequentialAnimation {
4037- id: showAnimation
4038- running: true
4039-
4040- NumberAnimation { target: rootItem; property: "anchors.bottomMargin"; to: 0; duration: 300 }
4041- PauseAnimation { duration: 2000 }
4042- ScriptAction { script: destroyAnimation.restart() }
4043- }
4044-
4045- SequentialAnimation {
4046- id: destroyAnimation
4047-
4048- NumberAnimation { target: rootItem; property: "opacity"; to: 0; duration: 500 }
4049- ScriptAction { script: rootItem.destroy() }
4050- }
4051-}
4052-
4053
4054=== removed file 'app/components/dateHelper.js'
4055--- app/components/dateHelper.js 2014-08-04 17:05:04 +0000
4056+++ app/components/dateHelper.js 1970-01-01 00:00:00 +0000
4057@@ -1,23 +0,0 @@
4058-/*
4059- This file is part of quick-memo
4060- Copyright (C) 2014 Stefano Verzegnassi
4061-
4062- This program is free software: you can redistribute it and/or modify
4063- it under the terms of the GNU General Public License 3 as published by
4064- the Free Software Foundation.
4065-
4066- This program is distributed in the hope that it will be useful,
4067- but WITHOUT ANY WARRANTY; without even the implied warranty of
4068- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4069- GNU General Public License for more details.
4070-
4071- You should have received a copy of the GNU General Public License
4072- along with this program. If not, see http://www.gnu.org/licenses/.
4073-*/
4074-
4075-function parseDate(value) {
4076- var d = new Date();
4077- d.setTime(value)
4078-
4079- return d
4080-}
4081
4082=== added directory 'app/editPage'
4083=== added file 'app/editPage/ListManager.qml'
4084--- app/editPage/ListManager.qml 1970-01-01 00:00:00 +0000
4085+++ app/editPage/ListManager.qml 2015-04-26 16:57:43 +0000
4086@@ -0,0 +1,313 @@
4087+/*
4088+ This file is part of quick-memo
4089+ Copyright (C) 2014, 2015 Stefano Verzegnassi
4090+
4091+ This program is free software: you can redistribute it and/or modify
4092+ it under the terms of the GNU General Public License 3 as published by
4093+ the Free Software Foundation.
4094+
4095+ This program is distributed in the hope that it will be useful,
4096+ but WITHOUT ANY WARRANTY; without even the implied warranty of
4097+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4098+ GNU General Public License for more details.
4099+
4100+ You should have received a copy of the GNU General Public License
4101+ along with this program. If not, see http://www.gnu.org/licenses/.
4102+*/
4103+
4104+import QtQuick 2.0
4105+import Ubuntu.Components 1.1
4106+import Ubuntu.Keyboard 0.1
4107+import Ubuntu.Components.ListItems 1.0 as ListItem
4108+
4109+import "../common"
4110+
4111+Column {
4112+ id: rootItem
4113+
4114+ width: parent.width
4115+ spacing: units.gu(0.25)
4116+
4117+ property Flickable flickable
4118+ property alias model: repeater.model
4119+ property alias delegate: repeater.delegate
4120+ property alias footer: footerLoader.sourceComponent
4121+ readonly property bool focusOnLastItem: (model.focusedIndex === -1) || (model.focusedIndex === (model.count - 1))
4122+
4123+ signal listChanged()
4124+
4125+ ListItem.Header {
4126+ text: i18n.tr("List:")
4127+ }
4128+
4129+ Repeater {
4130+ id: repeater
4131+ width: parent.width
4132+
4133+ model: ListModel {
4134+ id: dataModel
4135+
4136+ property int focusedIndex: -1
4137+ }
4138+
4139+ delegate: delegate
4140+ }
4141+
4142+ // TODO: When user adds an element in the list, the new element should gain focus.
4143+ Loader {
4144+ id: footerLoader
4145+ width: parent.width
4146+
4147+ sourceComponent: ListItem.Empty {
4148+ width: parent.width
4149+ opacity: enabled ? 1.0 : 0.5
4150+ showDivider: false
4151+
4152+ enabled: {
4153+ if (rootItem.model.count > 0) {
4154+ if (rootItem.model.get(rootItem.model.count - 1).text !== "") {
4155+ return true
4156+ } else {
4157+ return false
4158+ }
4159+ } else {
4160+ return true
4161+ }
4162+ }
4163+
4164+ Row {
4165+ spacing: units.gu(2)
4166+ anchors {
4167+ left: parent.left; leftMargin: units.gu(2);
4168+ right: parent.right;
4169+ verticalCenter: parent.verticalCenter
4170+ }
4171+
4172+ Item {
4173+ id: addListBtnImage
4174+ implicitWidth: units.gu(4.25)
4175+ implicitHeight: units.gu(4)
4176+
4177+ Icon {
4178+ anchors { fill: parent; margins: units.gu(0.5) }
4179+ name: "add"
4180+ }
4181+ }
4182+
4183+ Label {
4184+ id: addListBtnLabel
4185+ // TRANSLATORS: Text of a button used for add an item in the To-do list.
4186+ text: i18n.tr("Add item")
4187+ anchors.verticalCenter: addListBtnImage.verticalCenter
4188+ }
4189+ }
4190+
4191+ onClicked: {
4192+ rootItem.addItem({"checked": false, "text": ""})
4193+ // Here we don't send listChanged signal, since it is an empty item that should not be saved
4194+ }
4195+ }
4196+ }
4197+
4198+
4199+ function exportModel() {
4200+ var list = []
4201+
4202+ if (rootItem.model.count > 0 && rootItem.model.get(0).text !== "") {
4203+ for (var i=0; i<rootItem.model.count; i++) {
4204+ if (i != rootItem.model.count && rootItem.model.get(i).text != "") {
4205+ list[i] = rootItem.model.get(i)
4206+ }
4207+ }
4208+ }
4209+
4210+ return list
4211+ }
4212+
4213+ function addItem(args) {
4214+ rootItem.model.append(args)
4215+ var newItem = repeater.itemAt(repeater.count - 1)
4216+ newItem.textArea.forceActiveFocus()
4217+ autoScrollAnimation.makeMeVisible(newItem)
4218+ }
4219+
4220+ SequentialAnimation {
4221+ id: autoScrollAnimation
4222+
4223+ property var targetItem: null
4224+ alwaysRunToEnd: true
4225+
4226+ // wait item be moved to correct place
4227+ PauseAnimation {
4228+ duration: 100
4229+ }
4230+ // scroll to new item position
4231+ ScriptAction {
4232+ script: {
4233+ if (autoScrollAnimation.targetItem) {
4234+ autoScrollAnimation.makeMeVisibleImpl(autoScrollAnimation.targetItem)
4235+ autoScrollAnimation.targetItem = null
4236+ }
4237+ }
4238+ }
4239+
4240+ function makeMeVisible(newItem) {
4241+ autoScrollAnimation.targetItem = newItem
4242+ autoScrollAnimation.restart()
4243+ }
4244+
4245+ function makeMeVisibleImpl(newItem) {
4246+ if (!newItem) {
4247+ return
4248+ }
4249+
4250+ var positionY = rootItem.y + repeater.y + newItem.y
4251+
4252+ // check if the item is already visible
4253+ var bottomY = flickable.contentY + flickable.height
4254+ var itemBottom = positionY + (newItem.height *3) // margin
4255+ if (positionY >= flickable.contentY && itemBottom <= bottomY) {
4256+ return;
4257+ }
4258+
4259+ // if it is not, try to scroll and make it visible
4260+ var targetY = itemBottom - flickable.height
4261+ if (targetY >= 0 && positionY) {
4262+ flickable.contentY = targetY
4263+ } else if (positionY < flickable.contentY) {
4264+ // if it is hidden at the top, also show it
4265+ flickable.contentY = positionY
4266+ }
4267+ flickable.returnToBounds()
4268+ }
4269+ }
4270+
4271+
4272+ // *** DELEGATE ***
4273+ Component {
4274+ id: delegate
4275+
4276+ ListItem.Empty {
4277+ id: item
4278+ width: parent ? parent.width : undefined
4279+ height: (layoutDelegate.height > item.__height) ? layoutDelegate.height : item.__height
4280+
4281+ showDivider: false
4282+
4283+ property alias textArea: textArea
4284+
4285+ Rectangle {
4286+ anchors.fill: parent
4287+ opacity: 0.1
4288+ visible: textArea.activeFocus
4289+ color: "black"
4290+ }
4291+
4292+ backgroundIndicator: Rectangle {
4293+ anchors.fill: parent
4294+ color: "red"
4295+
4296+ Icon {
4297+ anchors.centerIn: parent
4298+ name: "delete"
4299+ color: Theme.palette.selected.field
4300+ height: units.gu(3)
4301+ width: units.gu(3)
4302+ }
4303+ }
4304+
4305+ // ListItem is removable for all items, except the first when the text field is empty.
4306+ //confirmRemoval: true
4307+ removable: rootItem.model.count > 1 || (rootItem.model.get(0).text !== "")
4308+ confirmRemoval: true
4309+ onItemRemoved: {
4310+ // Send the signal before removing the item. This avoids a ReferenceError.
4311+ rootItem.listChanged()
4312+ rootItem.model.remove(model.index)
4313+ }
4314+
4315+ Row {
4316+ id: layoutDelegate
4317+
4318+ anchors {
4319+ left: parent.left
4320+ right: parent.right
4321+ margins: units.gu(2)
4322+ verticalCenter: parent.verticalCenter
4323+ }
4324+
4325+ spacing: units.gu(1)
4326+ height: Math.max(checkBox.height, textArea.height)
4327+
4328+ CheckBox {
4329+ id: checkBox
4330+
4331+ checked: model.checked
4332+ onCheckedChanged: layoutDelegate.updateModel()
4333+
4334+ style: Item {
4335+ implicitWidth: units.gu(4.25)
4336+ implicitHeight: units.gu(4)
4337+
4338+ Image {
4339+ anchors { fill: parent; margins: units.gu(0.5) }
4340+
4341+ source: checkBox.checked ? "../../graphics/select.svg" : "../../graphics/unselect.svg"
4342+ }
4343+ }
4344+ }
4345+
4346+ NoteTextField {
4347+ id: textArea
4348+
4349+ width: parent.width - (checkBox.width + (parent.spacing * 2))
4350+ anchors.verticalCenter: parent.verticalCenter
4351+
4352+ font.strikeout: checkBox.checked
4353+
4354+ onFocusReceived: {
4355+ rootItem.model.focusedIndex = model.index
4356+ }
4357+
4358+ text: model.text
4359+ onTextChanged: {
4360+ layoutDelegate.updateModel()
4361+
4362+ /* This requires some test. No problem when TextField is used, but it seems to break dataModel when
4363+ TextArea is used. Could be related to NoteTextArea.qml, line 39.*/
4364+ if (text === "") {
4365+ rootItem.model.remove(model.index)
4366+ }
4367+ }
4368+
4369+ //hasClearButton: false
4370+ focus: true
4371+
4372+ // Ubuntu Keyboard
4373+ // TODO: Disable Enter key if model.text is empty.
4374+ InputMethod.extensions: {
4375+ "enterKeyText": rootItem.focusOnLastItem ? i18n.tr("Add") : i18n.tr("Next")
4376+ }
4377+
4378+ Keys.onReturnPressed: {
4379+ if (rootItem.focusOnLastItem && (model.text !== "")) {
4380+ // Create a new item.
4381+ rootItem.addItem({"checked": false, "text": ""})
4382+ } else if (!rootItem.focusOnLastItem) {
4383+ var nextItem = repeater.itemAt(model.index + 1)
4384+ if (nextItem) {
4385+ nextItem.textArea.forceActiveFocus()
4386+ autoScrollAnimation.makeMeVisible(nextItem)
4387+ }
4388+ }
4389+ }
4390+ }
4391+
4392+ function updateModel() {
4393+ rootItem.model.set(model.index, {"checked": checkBox.checked, "text": textArea.text})
4394+ rootItem.listChanged()
4395+ }
4396+ }
4397+ }
4398+ }
4399+}
4400
4401=== added file 'app/editPage/PictureButton.qml'
4402--- app/editPage/PictureButton.qml 1970-01-01 00:00:00 +0000
4403+++ app/editPage/PictureButton.qml 2015-04-26 16:57:43 +0000
4404@@ -0,0 +1,40 @@
4405+/*
4406+ This file is part of quick-memo
4407+ Copyright (C) 2014 Stefano Verzegnassi
4408+
4409+ This program is free software: you can redistribute it and/or modify
4410+ it under the terms of the GNU General Public License 3 as published by
4411+ the Free Software Foundation.
4412+
4413+ This program is distributed in the hope that it will be useful,
4414+ but WITHOUT ANY WARRANTY; without even the implied warranty of
4415+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4416+ GNU General Public License for more details.
4417+
4418+ You should have received a copy of the GNU General Public License
4419+ along with this program. If not, see http://www.gnu.org/licenses/.
4420+*/
4421+
4422+import QtQuick 2.0
4423+import Ubuntu.Components 1.1
4424+
4425+AbstractButton {
4426+ id: rootItem
4427+ width: units.gu(8)
4428+ height: units.gu(8)
4429+
4430+ property alias image: shape.image
4431+ default property alias contentsItem: shape.data
4432+
4433+ onPressedChanged: {
4434+ if (pressed)
4435+ shape.borderSource = "radius_pressed.sci"
4436+ else
4437+ shape.borderSource = "radius_idle.sci"
4438+ }
4439+
4440+ UbuntuShape {
4441+ id: shape
4442+ anchors.fill: parent
4443+ }
4444+}
4445
4446=== added file 'app/editPage/PicturesManager.qml'
4447--- app/editPage/PicturesManager.qml 1970-01-01 00:00:00 +0000
4448+++ app/editPage/PicturesManager.qml 2015-04-26 16:57:43 +0000
4449@@ -0,0 +1,162 @@
4450+/*
4451+ This file is part of quick-memo
4452+ Copyright (C) 2014, 2015 Stefano Verzegnassi
4453+
4454+ This program is free software: you can redistribute it and/or modify
4455+ it under the terms of the GNU General Public License 3 as published by
4456+ the Free Software Foundation.
4457+
4458+ This program is distributed in the hope that it will be useful,
4459+ but WITHOUT ANY WARRANTY; without even the implied warranty of
4460+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4461+ GNU General Public License for more details.
4462+
4463+ You should have received a copy of the GNU General Public License
4464+ along with this program. If not, see http://www.gnu.org/licenses/.
4465+*/
4466+
4467+import QtQuick 2.0
4468+import Ubuntu.Components 1.1
4469+import Ubuntu.Thumbnailer 0.1
4470+import Ubuntu.Content 0.1
4471+import Ubuntu.Components.Popups 1.0
4472+import Ubuntu.Components.ListItems 1.0 as ListItem
4473+
4474+Item {
4475+ id: rootItem
4476+
4477+ property alias model: repeater.model
4478+
4479+ width: parent.width
4480+ height: childrenRect.height
4481+
4482+ signal picsModelChanged()
4483+
4484+ function exportModel() {
4485+ var list = []
4486+ for (var i=0; i<picModel.count; i++) {
4487+ list[i] = picModel.get(i)
4488+ }
4489+
4490+ return list
4491+ }
4492+
4493+ ListItem.Header { id: header; text: i18n.tr("Related pictures:") }
4494+
4495+ Flow {
4496+ id: flow
4497+
4498+ anchors {
4499+ top: header.bottom; topMargin: units.gu(1)
4500+ left: parent.left
4501+ right: parent.right
4502+ margins: units.gu(2)
4503+ }
4504+ spacing: units.gu(2)
4505+
4506+ Repeater {
4507+ id: repeater
4508+
4509+ model: ListModel { id: picModel; onRowsRemoved: rootItem.picsModelChanged() }
4510+ delegate: PictureButton {
4511+ image: Image {
4512+ source: "image://thumbnailer/" + Qt.resolvedUrl(model.url)
4513+ fillMode: Image.PreserveAspectCrop
4514+ }
4515+
4516+ //TODO: Add right click support
4517+ onClicked: pageStack.push(Qt.resolvedUrl("../ui/ImageViewer.qml"), {source: Qt.resolvedUrl(model.url)})
4518+ onPressAndHold: PopupUtils.open(pictureMenuPopover, this, {index: model.index})
4519+ }
4520+ }
4521+
4522+ PictureButton {
4523+ Icon {
4524+ anchors.centerIn: parent
4525+ height: parent.height / 2
4526+ width: height
4527+ name: "add"
4528+ }
4529+
4530+ onClicked: rootItem.importImageFromContentHub()
4531+ }
4532+ }
4533+
4534+ // *** CONTENT HANDLER ***
4535+ //This should be probably moved in main.qml
4536+ property var activeTransfer
4537+
4538+ function importImageFromContentHub() {
4539+ pageStack.push(picker)
4540+ }
4541+
4542+ Page {
4543+ id: picker
4544+ visible: false
4545+
4546+ ContentPeerPicker {
4547+ visible: parent.visible
4548+
4549+ contentType: ContentType.Pictures
4550+ handler: ContentHandler.Source
4551+
4552+ onPeerSelected: {
4553+ rootItem.activeTransfer = peer.request(appStore);
4554+ pageStack.pop();
4555+ }
4556+
4557+ onCancelPressed: {
4558+ pageStack.pop();
4559+ }
4560+ }
4561+ }
4562+
4563+ ContentTransferHint {
4564+ id: transferHint
4565+ anchors.fill: parent
4566+ activeTransfer: rootItem.activeTransfer
4567+ }
4568+
4569+ ContentStore {
4570+ id: appStore
4571+ scope: ContentScope.App
4572+ }
4573+
4574+ Connections {
4575+ target: rootItem.activeTransfer ? rootItem.activeTransfer : null
4576+ onStateChanged: {
4577+ if (rootItem.activeTransfer.state === ContentTransfer.Charged) {
4578+ for (var i=0; i<rootItem.activeTransfer.items.length; i++) {
4579+ picModel.append({url: rootItem.activeTransfer.items[i].url.toString().replace("file://", "")})
4580+ console.log("CONTENT IMPORTED:", rootItem.activeTransfer.items[i].url.toString().replace("file://", ""))
4581+ rootItem.picsModelChanged()
4582+ }
4583+ }
4584+ }
4585+ }
4586+
4587+ // *** PICTURE POPOVER ***
4588+ Component {
4589+ id: pictureMenuPopover
4590+ ActionSelectionPopover {
4591+ id: popover
4592+ property int index
4593+
4594+ actions: ActionList {
4595+ Action {
4596+ text: i18n.tr("Remove picture from selection")
4597+ onTriggered: {
4598+ PopupUtils.close(popover)
4599+ rootItem.model.remove(popover.index)
4600+ }
4601+ }
4602+ }
4603+
4604+ delegate: ListItem.Standard {
4605+ // ForegroundColor is not correctly set
4606+ __foregroundColor: Theme.palette.normal.overlayText
4607+ showDivider: false
4608+ }
4609+ }
4610+ }
4611+}
4612
4613=== modified file 'app/main.qml'
4614--- app/main.qml 2014-10-21 16:01:52 +0000
4615+++ app/main.qml 2015-04-26 16:57:43 +0000
4616@@ -1,6 +1,6 @@
4617 /*
4618 This file is part of quick-memo
4619- Copyright (C) 2014 Stefano Verzegnassi
4620+ Copyright (C) 2014, 2015 Stefano Verzegnassi
4621
4622 This program is free software: you can redistribute it and/or modify
4623 it under the terms of the GNU General Public License 3 as published by
4624@@ -18,7 +18,7 @@
4625 import QtQuick 2.0
4626 import Ubuntu.Components 1.1
4627 import Qt.labs.settings 1.0
4628-import "components"
4629+import "common"
4630
4631 MainView {
4632 id: root
4633@@ -42,28 +42,15 @@
4634 }
4635
4636 // This is where we manage the pages of the application.
4637- PageStack {
4638- id: pageStack
4639-
4640- Component {
4641- id: mainPage
4642- MainPage {}
4643- }
4644-
4645- Component {
4646- id: memoPage
4647- EditMemoPage {}
4648- }
4649- }
4650+ PageStack { id: pageStack }
4651
4652 NoteModel {
4653 id: notes
4654- onInitialized: pageStack.push(mainPage)
4655+ onInitialized: pageStack.push(Qt.resolvedUrl("./ui/MainPage.qml"))
4656 }
4657
4658-
4659 function showNotification(text) {
4660- var component = Qt.createComponent("components/Toaster.qml")
4661+ var component = Qt.createComponent("./common/Toaster.qml")
4662 var toast = component.createObject(root, {"text" : text});
4663 }
4664
4665
4666=== added directory 'app/mainPage'
4667=== added file 'app/mainPage/Delegate.qml'
4668--- app/mainPage/Delegate.qml 1970-01-01 00:00:00 +0000
4669+++ app/mainPage/Delegate.qml 2015-04-26 16:57:43 +0000
4670@@ -0,0 +1,291 @@
4671+/*
4672+ This file is part of quick-memo
4673+ Copyright (C) 2014, 2015 Stefano Verzegnassi
4674+
4675+ This program is free software: you can redistribute it and/or modify
4676+ it under the terms of the GNU General Public License 3 as published by
4677+ the Free Software Foundation.
4678+
4679+ This program is distributed in the hope that it will be useful,
4680+ but WITHOUT ANY WARRANTY; without even the implied warranty of
4681+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4682+ GNU General Public License for more details.
4683+
4684+ You should have received a copy of the GNU General Public License
4685+ along with this program. If not, see http://www.gnu.org/licenses/.
4686+*/
4687+
4688+import QtQuick 2.0
4689+import Ubuntu.Components 1.1
4690+import Ubuntu.Thumbnailer 0.1
4691+import "../common/dateHelper.js" as DateHelper
4692+
4693+AbstractButton {
4694+ id: rootItem
4695+
4696+ height: layout.height + layout.anchors.topMargin
4697+ width: parent.width
4698+
4699+ property bool selected: false
4700+ property int maxListDelegatesNumber: 3
4701+
4702+ // RGB channels from 'shape.color' are in [0; 1] range.
4703+ property color foregroundColor: ((shape.color.r * 0.30 + shape.color.g * 0.59 + shape.color.b * 0.11) > 0.5) ? UbuntuColors.darkGrey : "#F3F3E7"
4704+
4705+ UbuntuShape {
4706+ id: shape
4707+ anchors.fill: parent
4708+
4709+ // Add 70% opacity
4710+ color: contents.color.toString().replace("#", "#B3")
4711+
4712+ radius: "medium"
4713+
4714+ Column {
4715+ id: layout
4716+ anchors { top: parent.top; left: parent.left; right: parent.right; topMargin: units.gu(2) }
4717+
4718+ Column {
4719+ id: column
4720+ width: parent.width - (spacing * 2)
4721+ x: spacing
4722+ spacing: units.gu(2)
4723+
4724+ Loader {
4725+ width: parent.width
4726+ sourceComponent: (contents.title == "") ? undefined : titleComponent
4727+
4728+ Component {
4729+ id: titleComponent
4730+
4731+ Label {
4732+ width: parent.width
4733+ fontSize: "large"
4734+ font.weight: Font.Bold
4735+ text: contents.title
4736+ elide: Text.ElideRight
4737+ maximumLineCount: 2
4738+ wrapMode: Text.WrapAnywhere
4739+ color: rootItem.foregroundColor
4740+ }
4741+ }
4742+
4743+ }
4744+
4745+ Loader {
4746+ width: parent.width
4747+ sourceComponent: (contents.text == "") ? undefined : textComponent
4748+
4749+ Component {
4750+ id: textComponent
4751+
4752+ Label {
4753+ width: parent.width
4754+ text: contents.text
4755+ wrapMode: Text.WrapAnywhere
4756+ elide: Text.ElideRight
4757+ maximumLineCount: 5
4758+ color: rootItem.foregroundColor
4759+ }
4760+ }
4761+ }
4762+ }
4763+
4764+ // A spacer item
4765+ Item {
4766+ width: parent.width
4767+ height: units.gu(2)
4768+ visible: picsRepeater.count > 0
4769+ }
4770+
4771+ Item {
4772+ id: picsItem
4773+ width: parent.width
4774+ height: picFlow.height
4775+
4776+ // TODO: As for listDelegates, limit pics to a number of 9
4777+ Flow {
4778+ id: picFlow
4779+ width: parent.width
4780+
4781+ Repeater {
4782+ id: picsRepeater
4783+
4784+ model: contents.pictures
4785+
4786+ delegate: Image {
4787+ id: img
4788+ width: parent.width
4789+ fillMode: Image.PreserveAspectCrop
4790+ source: "image://thumbnailer/" + Qt.resolvedUrl(contents.pictures[index].url)
4791+
4792+ Connections {
4793+ target: picsRepeater
4794+ onItemAdded: calculateSize(index)
4795+ onItemRemoved: calculateSize(index)
4796+ }
4797+
4798+ Connections {
4799+ target: picFlow
4800+ onWidthChanged: calculateSize(index)
4801+ }
4802+
4803+ Component.onCompleted: calculateSize(index)
4804+
4805+ function calculateSize(index) {
4806+ var n = picsRepeater.count
4807+ var i = n % 3
4808+ var m = Math.floor(n / 3)
4809+
4810+ height = units.gu(6)
4811+
4812+ // Need to be hardcoded because of an issue.
4813+ // FIXME: Think it requires a better solution
4814+ var picFlowRealWidth = ((root.width - units.gu(4)) * 0.5) - units.gu(1)
4815+
4816+ switch(i) {
4817+ case 0:
4818+ width = picFlowRealWidth / 3
4819+ return
4820+ case 1:
4821+ if (index == 0) {
4822+ width = picFlowRealWidth
4823+ return
4824+ } else {
4825+ width = picFlowRealWidth / 3
4826+ return
4827+ }
4828+ case 2:
4829+ if (index <= 1) {
4830+ width = picFlowRealWidth / 2
4831+ return
4832+ } else {
4833+ width = picFlowRealWidth / 3
4834+ return
4835+ }
4836+ }
4837+ }
4838+ }
4839+ }
4840+
4841+ Component.onCompleted: picsRepeater.model = contents.pictures
4842+ }
4843+ }
4844+
4845+ Loader {
4846+ id: listLoader
4847+ width: parent.width
4848+ sourceComponent: (contents.list[0]) ? listComponent : null
4849+
4850+ Component {
4851+ id: listComponent
4852+
4853+ Column {
4854+ width: parent.width
4855+
4856+ // A spacer item
4857+ Item {
4858+ width: parent.width
4859+ height: units.gu(1)
4860+ }
4861+
4862+ Repeater {
4863+ id: listRepeater
4864+ width: parent.width
4865+
4866+ model: contents.list
4867+
4868+ delegate: Loader {
4869+ width: parent.width
4870+ sourceComponent: model.index < 4 ? listDelegate : null
4871+
4872+ Component {
4873+ id: listDelegate
4874+
4875+ Row {
4876+ id: rootItem
4877+ spacing: units.gu(1)
4878+ width: parent.width
4879+ height: Math.max(checkBox.height, textArea.height)
4880+
4881+ Item {
4882+ id: checkBox
4883+ width: parent.width
4884+ height: units.gu(4)
4885+
4886+ property bool checked: contents.list[index].checked
4887+
4888+ Icon {
4889+ id: tick
4890+ anchors {
4891+ left: parent.left; leftMargin: units.gu(2.25);
4892+ top: parent.top; topMargin: units.gu(0.35)
4893+ }
4894+ width: (source == "../../graphics/select.svg") ? units.gu(2.25) : units.gu(1.5)
4895+ height: (source == "../../graphics/select.svg") ? units.gu(2) : units.gu(1.5)
4896+
4897+ source: checkBox.checked ? "../../graphics/select.svg" : "../../graphics/unselect.svg"
4898+ visible: model.index !== 3
4899+ color: foregroundColor
4900+ }
4901+
4902+ Label {
4903+ id: textArea
4904+ anchors { left: tick.right; right: parent.right; margins: units.gu(1) }
4905+
4906+ font.strikeout: checkBox.checked
4907+ text: (model.index == 3) ? ". . ." : contents.list[index].text
4908+ elide: Text.ElideRight
4909+ maximumLineCount: 2
4910+ wrapMode: Text.WrapAnywhere
4911+ color: foregroundColor
4912+ }
4913+ }
4914+ }
4915+ }
4916+ }
4917+ }
4918+
4919+ Component.onCompleted: listRepeater.model = contents.list
4920+ }
4921+ }
4922+ }
4923+
4924+ // A spacer item
4925+ Item {
4926+ width: parent.width
4927+ height: units.gu(2)
4928+ }
4929+
4930+ Item {
4931+ id: date
4932+ width: parent.width
4933+ height: units.gu(4)
4934+
4935+ Label {
4936+ anchors { right: parent.right; verticalCenter: parent.verticalCenter; margins: units.gu(2) }
4937+ text: Qt.formatDateTime(DateHelper.parseDate(contents.date), "d MMM yyyy, hh:mm")
4938+ fontSize: "small"
4939+ color: rootItem.foregroundColor
4940+ }
4941+ }
4942+ }
4943+ }
4944+
4945+ // Visual feedback when pressed. Not listed in official documentation, still useful.
4946+ onPressedChanged: {
4947+ if (pressed)
4948+ shape.borderSource = "radius_pressed.sci"
4949+ else
4950+ shape.borderSource = "radius_idle.sci"
4951+ }
4952+
4953+ // Visual feedback when selected.
4954+ onSelectedChanged: {
4955+ if (selected) {
4956+ shape.color = Qt.darker(contents.color)
4957+ } else {
4958+ shape.color = contents.color.toString().replace("#", "#B3")
4959+ }
4960+ }
4961+}
4962
4963=== added file 'app/mainPage/HorizontalFlowListView.qml'
4964--- app/mainPage/HorizontalFlowListView.qml 1970-01-01 00:00:00 +0000
4965+++ app/mainPage/HorizontalFlowListView.qml 2015-04-26 16:57:43 +0000
4966@@ -0,0 +1,78 @@
4967+/*
4968+ * Copyright 2012 Ruediger Gad
4969+ * Copyright 2014 Stefano Verzegnassi <stefano92.100@gmail.com>
4970+ *
4971+ * This file is part of FlowListView.
4972+ *
4973+ * FlowListView is free software: you can redistribute it and/or modify
4974+ * it under the terms of the GNU Lesser General Public License (LGPL)
4975+ * as published by the Free Software Foundation, either version 3 of the
4976+ * License, or (at your option) any later version.
4977+ *
4978+ * FlowListView is distributed in the hope that it will be useful,
4979+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4980+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4981+ * GNU General Public License for more details.
4982+ *
4983+ * You should have received a copy of the GNU Lesser General Public License
4984+ * along with FlowListView. If not, see <http://www.gnu.org/licenses/>.
4985+ *
4986+ */
4987+
4988+// A derivative version of FlowListView.qml
4989+import QtQuick 2.0
4990+import Ubuntu.Components 1.1
4991+
4992+Flickable {
4993+ id: flowListView
4994+
4995+ contentWidth: flow.childrenRect.width
4996+
4997+ property alias count: repeater.count
4998+ property int currentIndex: -1
4999+ property variant currentItem;
5000+ property alias delegate: repeater.delegate
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: