Merge lp:~renatofilho/address-book-app/fix-1377334 into lp:~phablet-team/address-book-app/staging

Proposed by Renato Araujo Oliveira Filho
Status: Rejected
Rejected by: Renato Araujo Oliveira Filho
Proposed branch: lp:~renatofilho/address-book-app/fix-1377334
Merge into: lp:~phablet-team/address-book-app/staging
Diff against target: 380 lines (+142/-128)
4 files modified
src/imports/ContactEdit/AvatarImport.qml (+96/-91)
src/imports/ContactEdit/ContactDetailAvatarEditor.qml (+14/-17)
src/imports/ContactList/ContactExporter.qml (+28/-2)
src/imports/ContactList/ContactListPage.qml (+4/-18)
To merge this branch: bzr merge lp:~renatofilho/address-book-app/fix-1377334
Reviewer Review Type Date Requested Status
Ken VanDine Approve
PS Jenkins bot continuous-integration Needs Fixing
Review via email: mp+237480@code.launchpad.net

Commit message

Implement AvatarImport as a Page.

Does not use dialog on content hub component, to avoid application to get stuck.
Handle operation aborted in pick mode.

To post a comment you must log in.
Revision history for this message
Ken VanDine (ken-vandine) wrote :

I haven't done a full review yet, but I would suggest perhaps it's worth talking about adding the title to ContentTransferHint rather than reimplementing it here. I worry about needing to maintain a copy of that code, and it seems like a nice feature for ContentTransferHint.

Revision history for this message
Ken VanDine (ken-vandine) wrote :

I haven't run it yet, I'll wait for a CI build for that. But from the code review it looks good, see a couple inline comments.

Also, unrelated to this MP, I see there is a copyImage function to copy the file. There is now an API for that in content-hub, ContentItem.move(). Now that content-hub provides an API for that, you could consider switching to that.

315. By Renato Araujo Oliveira Filho

Fixed contact export.

Revision history for this message
Renato Araujo Oliveira Filho (renatofilho) wrote :

> I haven't run it yet, I'll wait for a CI build for that. But from the code
> review it looks good, see a couple inline comments.
>
> Also, unrelated to this MP, I see there is a copyImage function to copy the
> file. There is now an API for that in content-hub, ContentItem.move(). Now
> that content-hub provides an API for that, you could consider switching to
> that.

The copyImage not only copy the image it resize it to a small size to be used as avatar.

Revision history for this message
Renato Araujo Oliveira Filho (renatofilho) :
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ken VanDine (ken-vandine) wrote :

Works well on my mako, I tested the full path including adding the avatar from gallery as well as aborting the transfer. All worked well.

review: Approve

Unmerged revisions

315. By Renato Araujo Oliveira Filho

Fixed contact export.

314. By Renato Araujo Oliveira Filho

Implement AvatarImport as a Page.

Does not use dialogs on content hub component, to avoid application to get stuck.
Handle operation aborted in pick mode.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/imports/ContactEdit/AvatarImport.qml'
2--- src/imports/ContactEdit/AvatarImport.qml 2014-08-13 20:52:57 +0000
3+++ src/imports/ContactEdit/AvatarImport.qml 2014-10-07 20:52:25 +0000
4@@ -18,103 +18,108 @@
5
6 import Ubuntu.Components 1.1
7 import Ubuntu.Components.Popups 1.0
8-import Ubuntu.Content 0.1
9+import Ubuntu.Content 1.1
10
11-Item {
12+Page {
13 id: root
14
15- property var importDialog: null
16+ property var avatarListener: null
17+ property alias activeTransfer: signalConnections.target
18+ property alias isTransferRunning: activityIndicator.running
19
20 signal avatarReceived(string avatarUrl)
21
22- function requestNewAvatar()
23- {
24- if (!root.importDialog) {
25- root.importDialog = PopupUtils.open(contentHubDialog, null)
26- } else {
27- console.warn("Import dialog already running")
28- }
29- }
30-
31- Component {
32- id: contentHubDialog
33-
34- PopupBase {
35- id: dialogue
36-
37- property alias activeTransfer: signalConnections.target
38-
39- parent: QuickUtils.rootItem(this)
40- focus: true
41-
42- Rectangle {
43- anchors.fill: parent
44-
45- ContentTransferHint {
46- anchors.fill: parent
47- activeTransfer: dialogue.activeTransfer
48- }
49-
50- ContentPeerPicker {
51- id: peerPicker
52-
53- anchors.fill: parent
54- visible: dialogue.done
55- contentType: ContentType.Pictures
56- handler: ContentHandler.Source
57-
58- onPeerSelected: {
59- peer.selectionType = ContentTransfer.Single
60- dialogue.activeTransfer = peer.request()
61- }
62-
63- onCancelPressed: {
64- PopupUtils.close(root.importDialog)
65- }
66- }
67- }
68-
69- Connections {
70- id: signalConnections
71-
72- target: dialogue.activeTransfer
73- onStateChanged: {
74- var done = ((dialogue.activeTransfer.state === ContentTransfer.Charged) ||
75- (dialogue.activeTransfer.state === ContentTransfer.Aborted))
76-
77- if (dialogue.activeTransfer.state === ContentTransfer.Charged) {
78- dialogue.hide()
79- if (dialogue.activeTransfer.items.length > 0) {
80- root.avatarReceived(dialogue.activeTransfer.items[0].url)
81- }
82- }
83-
84- if (done) {
85- acceptTimer.restart()
86- }
87- }
88- }
89-
90- // WORKAROUND: Work around for application becoming insensitive to touch events
91- // if the dialog is dismissed while the application is inactive.
92- // Just listening for changes to Qt.application.active doesn't appear
93- // to be enough to resolve this, so it seems that something else needs
94- // to be happening first. As such there's a potential for a race
95- // condition here, although as yet no problem has been encountered.
96- Timer {
97- id: acceptTimer
98-
99- interval: 100
100- repeat: true
101- running: false
102- onTriggered: {
103- if(Qt.application.active) {
104- PopupUtils.close(root.importDialog)
105- }
106- }
107- }
108-
109- Component.onDestruction: root.importDialog = null
110+ title: i18n.tr("Import avatar from...")
111+
112+ Item {
113+ id: transferHint
114+
115+ anchors.fill: parent
116+ visible: root.isTransferRunning
117+
118+ ActivityIndicator {
119+ id: activityIndicator
120+
121+ anchors {
122+ horizontalCenter: parent.horizontalCenter
123+ verticalCenter: parent.verticalCenter
124+ verticalCenterOffset: units.gu(-4)
125+ }
126+ running: root.activeTransfer
127+ }
128+
129+ Label {
130+ anchors {
131+ top: activityIndicator.bottom
132+ topMargin: units.gu(2)
133+ horizontalCenter: parent.horizontalCenter
134+ }
135+ // TRANSLATORS: This message appear while waiting for a external application content,
136+ // %1 refers to the the name of source application
137+ text: i18n.tr("Waiting for content from %1...").arg(peerPicker.peer.name)
138+ }
139+
140+ Button {
141+ id: cancelButton
142+
143+ enabled: root.activeTransfer && (root.activeTransfer.state === ContentTransfer.InProgress)
144+ anchors {
145+ bottom: parent.bottom
146+ left: parent.left
147+ right: parent.right
148+ margins: units.gu(2)
149+ }
150+ text: i18n.tr("Cancel")
151+ onClicked: root.activeTransfer.state = ContentTransfer.Aborted
152+ }
153+ }
154+
155+ ContentPeerPicker {
156+ id: peerPicker
157+
158+ anchors.fill: parent
159+ contentType: ContentType.Pictures
160+ handler: ContentHandler.Source
161+ showTitle: false
162+ visible: !root.isTransferRunning
163+
164+ onPeerSelected: {
165+ peer.selectionType = ContentTransfer.Single
166+ root.activeTransfer = peer.request()
167+ }
168+
169+ onCancelPressed: pageStack.pop()
170+ }
171+
172+ Connections {
173+ id: signalConnections
174+
175+ target: null
176+ onStateChanged: {
177+ var done = ((root.activeTransfer.state === ContentTransfer.Charged) ||
178+ (root.activeTransfer.state === ContentTransfer.Aborted))
179+ transferHint.enabled = !done
180+ if (root.activeTransfer.state === ContentTransfer.Charged) {
181+ if (( root.activeTransfer.items.length > 0) && root.avatarListener) {
182+ root.avatarListener.avatarReceived( root.activeTransfer.items[0].url)
183+ }
184+ }
185+
186+ if (done) {
187+ pageStack.pop()
188+ }
189+ }
190+ }
191+
192+ Component.onDestruction: {
193+ if (root.avatarListener) {
194+ root.avatarListener.busy = false
195+ }
196+ }
197+
198+ Component.onCompleted: {
199+ if (root.avatarListener) {
200+ root.avatarListener.busy = true
201 }
202 }
203 }
204
205=== modified file 'src/imports/ContactEdit/ContactDetailAvatarEditor.qml'
206--- src/imports/ContactEdit/ContactDetailAvatarEditor.qml 2014-09-29 13:20:08 +0000
207+++ src/imports/ContactEdit/ContactDetailAvatarEditor.qml 2014-10-07 20:52:25 +0000
208@@ -23,7 +23,7 @@
209 ContactDetailBase {
210 id: root
211
212- readonly property alias busy: activityIndicator.running
213+ property alias busy: activityIndicator.running
214 readonly property string defaultAvatar: "image://theme/add"
215
216 function isEmpty() {
217@@ -61,6 +61,16 @@
218 return avatarUrl
219 }
220
221+ function avatarReceived(avatarUrl)
222+ {
223+ // remove the previous image, this is nessary to make sure that the new image
224+ // get updated otherwise if the new image has the same name the image will not
225+ // be updated
226+ avatarImage.source = ""
227+ // Update with the new value
228+ avatarImage.source = application.copyImage(root.contact, avatarUrl);
229+ }
230+
231 detail: contact ? contact.detail(ContactDetail.Avatar) : null
232 implicitHeight: units.gu(8)
233 implicitWidth: units.gu(8)
234@@ -81,7 +91,7 @@
235 anchors.centerIn: visible ? avatar : undefined
236 height: units.gu(3)
237 width: units.gu(3)
238- visible: source == defaultAvatar
239+ visible: source == defaultAvatar && !root.busy
240
241 // When updating the avatar using the content picker the temporary file returned
242 // can contain the same name as the previous one and if the cache is enabled this
243@@ -94,29 +104,16 @@
244 id: activityIndicator
245
246 anchors.centerIn: avatar
247- running: (avatarImport.importDialog != null)
248 visible: running
249 }
250
251- AvatarImport {
252- id: avatarImport
253-
254- onAvatarReceived: {
255- // remove the previous image, this is nessary to make sure that the new image
256- // get updated otherwise if the new image has the same name the image will not
257- // be updated
258- avatarImage.source = ""
259- // Update with the new value
260- avatarImage.source = application.copyImage(root.contact, avatarUrl);
261- }
262- }
263-
264 MouseArea {
265 anchors.fill: parent
266 onClicked: {
267 // make sure the OSK disappear
268 root.forceActiveFocus()
269- avatarImport.requestNewAvatar()
270+ root.busy = true
271+ pageStack.push(Qt.resolvedUrl("AvatarImport.qml"), {avatarListener: root})
272 }
273 }
274 }
275
276=== modified file 'src/imports/ContactList/ContactExporter.qml'
277--- src/imports/ContactList/ContactExporter.qml 2014-09-30 21:17:25 +0000
278+++ src/imports/ContactList/ContactExporter.qml 2014-10-07 20:52:25 +0000
279@@ -16,15 +16,17 @@
280
281 import QtQuick 2.2
282 import QtContacts 5.0
283+import Ubuntu.Content 1.1
284
285 Item {
286 id: root
287
288 property var contactModel
289 property var outputFile
290+ property var activeTransfer: null
291
292- signal contactExported(int error, string url)
293 signal contactsFetched(var contacts)
294+ signal done()
295
296 function start(contacts) {
297 if (!contactModel) {
298@@ -59,7 +61,20 @@
299
300 onExportCompleted: {
301 priv.currentQueryId = -1
302- root.contactExported(error, root.outputFile)
303+
304+ // send contacts back to source app (pick mode)
305+ if (error === ContactModel.ExportNoError) {
306+ var obj = Qt.createQmlObject("import Ubuntu.Content 1.1; ContentItem { url: '" + url + "' }", root)
307+ if (root.activeTransfer) {
308+ root.activeTransfer.items = [obj]
309+ root.activeTransfer.state = ContentTransfer.Charged
310+ } else {
311+ console.error("No active transfer")
312+ }
313+ } else {
314+ console.error("Fail to export contacts:" + error)
315+ }
316+ root.done()
317 }
318
319 onContactsFetched: {
320@@ -74,5 +89,16 @@
321 }
322 }
323 }
324+
325+ Connections {
326+ target: root.activeTransfer
327+
328+ onStateChanged: {
329+ if (root.activeTransfer.state === ContentTransfer.Aborted) {
330+ root.activeTransfer = null
331+ root.done()
332+ }
333+ }
334+ }
335 }
336 }
337
338=== modified file 'src/imports/ContactList/ContactListPage.qml'
339--- src/imports/ContactList/ContactListPage.qml 2014-10-03 21:45:23 +0000
340+++ src/imports/ContactList/ContactListPage.qml 2014-10-07 20:52:25 +0000
341@@ -21,7 +21,7 @@
342 import Ubuntu.Components.ListItems 1.0 as ListItem
343 import Ubuntu.Components.Popups 1.0 as Popups
344 import Ubuntu.Contacts 0.1 as ContactsUI
345-import Ubuntu.Content 0.1 as ContentHub
346+import Ubuntu.Content 1.1 as ContentHub
347
348 import "../Common"
349
350@@ -622,27 +622,13 @@
351 ContactExporter {
352 id: contactExporter
353
354- property var activeTransfer: null
355-
356 contactModel: contactList.listModel
357 outputFile: mainPage.pickMode ? "file:///tmp/address_book_app_export.vcf" : ""
358- onContactExported: {
359- // send contacts back to source app (pick mode)
360- if (error === ContactModel.ExportNoError) {
361- var obj = Qt.createQmlObject("import Ubuntu.Content 0.1; ContentItem { url: '" + url + "' }", contactExporter)
362- if (activeTransfer) {
363- activeTransfer.items = [obj]
364- activeTransfer.state = ContentHub.ContentTransfer.Charged
365- } else {
366- console.error("No active transfer")
367- }
368- } else {
369- console.error("Fail to export contacts:" + error)
370- }
371- activeTransfer = null
372+
373+ onDone: {
374 mainPage.pickMode = false
375 mainPage.state = "default"
376- application.returnVcard(url)
377+ application.returnVcard(contactExporter.outputFile)
378 }
379
380 onContactsFetched: {

Subscribers

People subscribed via source and target branches