Merge lp:~canonical-platform-qa/gallery-app/gallery-app-new_header-autopilot2 into lp:gallery-app

Proposed by Leo Arias
Status: Superseded
Proposed branch: lp:~canonical-platform-qa/gallery-app/gallery-app-new_header-autopilot2
Merge into: lp:gallery-app
Diff against target: 2678 lines (+641/-1105)
31 files modified
rc/qml/AlbumEditor/AlbumEditor.qml (+9/-12)
rc/qml/AlbumViewer/AlbumViewer.qml (+37/-34)
rc/qml/AlbumsOverview.qml (+5/-6)
rc/qml/Components/MediaSelector.qml (+12/-17)
rc/qml/EventsOverview.qml (+1/-1)
rc/qml/GalleryApplication.qml (+2/-3)
rc/qml/MainScreen.qml (+2/-0)
rc/qml/MediaViewer/GalleryPhotoComponent.qml (+2/-4)
rc/qml/MediaViewer/MediaViewer.qml (+103/-149)
rc/qml/MediaViewer/PhotoViewerDelegate.qml (+0/-129)
rc/qml/MediaViewer/PopupPhotoViewer.qml (+16/-14)
rc/qml/MediaViewer/SingleMediaViewer.qml (+246/-0)
rc/qml/MediaViewer/VideoViewerDelegate.qml (+0/-125)
rc/qml/MediaViewer/ZoomablePhotoComponent.qml (+0/-409)
rc/qml/OrganicView/OrganicView.qml (+1/-1)
rc/qml/PhotosOverview.qml (+1/-1)
rc/qml/PickerScreen.qml (+15/-20)
rc/qml/Utility/PhotosToolbarActions.qml (+19/-13)
rc/qml/Utility/SelectionToolbarAction.qml (+32/-22)
tests/autopilot/gallery_app/emulators/album_view.py (+4/-6)
tests/autopilot/gallery_app/emulators/gallery_utils.py (+3/-3)
tests/autopilot/gallery_app/emulators/main_screen.py (+27/-12)
tests/autopilot/gallery_app/emulators/photo_viewer.py (+4/-5)
tests/autopilot/gallery_app/emulators/picker_screen.py (+3/-3)
tests/autopilot/gallery_app/tests/__init__.py (+6/-5)
tests/autopilot/gallery_app/tests/test_album_editor.py (+14/-18)
tests/autopilot/gallery_app/tests/test_album_view.py (+17/-26)
tests/autopilot/gallery_app/tests/test_albums_view.py (+16/-11)
tests/autopilot/gallery_app/tests/test_events_view.py (+17/-14)
tests/autopilot/gallery_app/tests/test_photo_viewer.py (+8/-23)
tests/autopilot/gallery_app/tests/test_photos_view.py (+19/-19)
To merge this branch: bzr merge lp:~canonical-platform-qa/gallery-app/gallery-app-new_header-autopilot2
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Ubuntu Phablet Team Pending
Review via email: mp+233273@code.launchpad.net

This proposal has been superseded by a proposal from 2014-09-04.

Commit message

Not ready, just trying jenkins.

Description of the change

NOT READY.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1077. By Leo Arias

Slow down the swipe.

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

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'rc/qml/AlbumEditor/AlbumEditor.qml'
--- rc/qml/AlbumEditor/AlbumEditor.qml 2014-06-10 00:13:50 +0000
+++ rc/qml/AlbumEditor/AlbumEditor.qml 2014-09-03 23:54:36 +0000
@@ -20,7 +20,7 @@
2020
21import QtQuick 2.021import QtQuick 2.0
22import Gallery 1.022import Gallery 1.0
23import Ubuntu.Components 0.123import Ubuntu.Components 1.1
24import "../../js/GalleryUtility.js" as GalleryUtility24import "../../js/GalleryUtility.js" as GalleryUtility
25import "../../js/GraphicsRoutines.js" as GraphicsRoutines25import "../../js/GraphicsRoutines.js" as GraphicsRoutines
26import "../AlbumViewer"26import "../AlbumViewer"
@@ -33,17 +33,14 @@
33 objectName: "mainAlbumEditor"33 objectName: "mainAlbumEditor"
3434
35 title: "Edit album"35 title: "Edit album"
36 tools: ToolbarItems {36 head.backAction: Action {
37 back: Button {37 objectName: "cancelButton"
38 objectName: "cancelButton"38 text: i18n.tr("Cancel")
39 anchors.verticalCenter: parent.verticalCenter39 iconName: "back"
40 text: i18n.tr("Cancel")40 onTriggered: {
41 width: units.gu(10)41 if(album.newAlbum)
42 onClicked: {42 albumModel.destroyAlbum(album);
43 if(album.newAlbum)43 albumEditor.closeRequested(albumEditor.album, false);
44 albumModel.destroyAlbum(album);
45 albumEditor.closeRequested(albumEditor.album, false);
46 }
47 }44 }
48 }45 }
4946
5047
=== modified file 'rc/qml/AlbumViewer/AlbumViewer.qml'
--- rc/qml/AlbumViewer/AlbumViewer.qml 2014-06-18 17:43:41 +0000
+++ rc/qml/AlbumViewer/AlbumViewer.qml 2014-09-03 23:54:36 +0000
@@ -19,7 +19,7 @@
19 */19 */
2020
21import QtQuick 2.021import QtQuick 2.0
22import Ubuntu.Components 0.122import Ubuntu.Components 1.1
23import Gallery 1.023import Gallery 1.0
24import "../../js/Gallery.js" as Gallery24import "../../js/Gallery.js" as Gallery
25import "../../js/GalleryUtility.js" as GalleryUtility25import "../../js/GalleryUtility.js" as GalleryUtility
@@ -74,10 +74,6 @@
7474
75 onVisibleChanged: {75 onVisibleChanged: {
76 if (visible) reopenPicture();76 if (visible) reopenPicture();
77
78 if (albumViewer.header) {
79 albumViewer.header.visible = !visible;
80 }
81 }77 }
8278
83 onCloseRequested: {79 onCloseRequested: {
@@ -135,6 +131,11 @@
135 overview.pushPage(component_mediaSelector);131 overview.pushPage(component_mediaSelector);
136 }132 }
137133
134 function toggleHeaderVisibility()
135 {
136 header.visible = !header.visible;
137 }
138
138 AlbumSpreadViewer {139 AlbumSpreadViewer {
139 id: albumSpreadViewer140 id: albumSpreadViewer
140 objectName: "spreadViewer"141 objectName: "spreadViewer"
@@ -188,8 +189,10 @@
188 if (hit.objectName === "addButton")189 if (hit.objectName === "addButton")
189 showMediaSelector();190 showMediaSelector();
190191
191 if (!hit.mediaSource)192 if (!hit.mediaSource) {
193 albumViewer.toggleHeaderVisibility();
192 return;194 return;
195 }
193196
194 albumViewer.mediaCurrentlyInView = hit.mediaSource.path;197 albumViewer.mediaCurrentlyInView = hit.mediaSource.path;
195 photoViewerLoader.fadeOpen(hit.mediaSource);198 photoViewerLoader.fadeOpen(hit.mediaSource);
@@ -302,6 +305,7 @@
302305
303 onOpened: {306 onOpened: {
304 overview.pushPage(target);307 overview.pushPage(target);
308 header.visible = false;
305 }309 }
306 onCloseRequested: {310 onCloseRequested: {
307 albumViewer.mediaCurrentlyInView = "";311 albumViewer.mediaCurrentlyInView = "";
@@ -353,36 +357,35 @@
353 }357 }
354358
355 /// Contains the actions for the toolbar in the album view359 /// Contains the actions for the toolbar in the album view
356 tools: ToolbarItems {360 head.actions: [
357 ToolbarButton {361 Action {
358 objectName: "addButton"362 objectName: "addButton"
359 action: Action {363 text: i18n.tr("Add to album") // text in HUD
360 text: i18n.tr("Add to album") // text in HUD364 iconName: "add"
361 iconSource: Qt.resolvedUrl("../../img/add.png")365 onTriggered: showMediaSelector();
362 onTriggered: {366 },
363 showMediaSelector();367 Action {
364 }
365 }
366 text: i18n.tr("Add") // text in toolbar
367 }
368 ToolbarButton {
369 id: deleteButton
370 objectName: "deleteButton"368 objectName: "deleteButton"
371 text: i18n.tr("Delete")369 text: i18n.tr("Delete")
372 iconSource: Qt.resolvedUrl("../../img/delete.png")370 iconName: "delete"
373 onTriggered: {371 onTriggered: {
374 albumTrashDialog.album = album372 albumTrashDialog.album = album;
375 albumTrashDialog.caller = deleteButton373 albumTrashDialog.show();
376 albumTrashDialog.show()374 }
377 }375 }
378 }376 ]
379 back: ToolbarButton {377
380 text: i18n.tr("Back")378 head.backAction: Action {
381 objectName: "backButton"379 iconName: "back"
382 iconSource: Qt.resolvedUrl("../../img/back.png")380 onTriggered: __close();
383 onTriggered: {381 }
384 __close()382
385 }383 Rectangle {
386 }384 id: headerBackground
385
386 width: parent.width
387 height: header.height
388
389 visible: header.visible
387 }390 }
388}391}
389392
=== modified file 'rc/qml/AlbumsOverview.qml'
--- rc/qml/AlbumsOverview.qml 2014-06-10 16:56:56 +0000
+++ rc/qml/AlbumsOverview.qml 2014-09-03 23:54:36 +0000
@@ -169,10 +169,9 @@
169 root.visible = false;169 root.visible = false;
170170
171 if (albumViewer.origin) {171 if (albumViewer.origin) {
172 if (header.visible)
173 header.visible = false;
174 albumViewer.visible = true;172 albumViewer.visible = true;
175 overview.pushPage(albumViewer);173 overview.pushPage(albumViewer);
174 header.visible = false;
176 }175 }
177 else176 else
178 albumViewer.visible = true177 albumViewer.visible = true
@@ -221,10 +220,10 @@
221 tools: ToolbarItems {220 tools: ToolbarItems {
222 id: albumOverviewTools221 id: albumOverviewTools
223 ToolbarButton {222 ToolbarButton {
224 objectName: "addButton"
225 action: Action {223 action: Action {
224 objectName: "addButton"
226 text: i18n.tr("Add new album") // Text in HUD225 text: i18n.tr("Add new album") // Text in HUD
227 iconSource: Qt.resolvedUrl("../img/add.png")226 iconName: "add"
228 onTriggered: {227 onTriggered: {
229 var album = albumCollectionModel.createOrphan();228 var album = albumCollectionModel.createOrphan();
230 albumCollectionModel.addOrphan(album);229 albumCollectionModel.addOrphan(album);
@@ -238,10 +237,10 @@
238 text: "Add" // text in toolbar237 text: "Add" // text in toolbar
239 }238 }
240 ToolbarButton {239 ToolbarButton {
241 objectName: "cameraButton"
242 visible: !APP.desktopMode
243 action: Action {240 action: Action {
241 objectName: "cameraButton"
244 text: i18n.tr("Camera")242 text: i18n.tr("Camera")
243 visible: !APP.desktopMode
245 iconSource: Qt.resolvedUrl("../img/camera.png")244 iconSource: Qt.resolvedUrl("../img/camera.png")
246 onTriggered: Qt.openUrlExternally("appid://com.ubuntu.camera/camera/current-user-version")245 onTriggered: Qt.openUrlExternally("appid://com.ubuntu.camera/camera/current-user-version")
247 }246 }
248247
=== modified file 'rc/qml/Components/MediaSelector.qml'
--- rc/qml/Components/MediaSelector.qml 2014-05-23 08:24:38 +0000
+++ rc/qml/Components/MediaSelector.qml 2014-09-03 23:54:36 +0000
@@ -16,7 +16,7 @@
1616
17import QtQuick 2.017import QtQuick 2.0
18import Gallery 1.018import Gallery 1.0
19import Ubuntu.Components 0.119import Ubuntu.Components 1.1
20import "../../js/Gallery.js" as Gallery20import "../../js/Gallery.js" as Gallery
21import "../OrganicView"21import "../OrganicView"
22import "../Utility"22import "../Utility"
@@ -74,31 +74,26 @@
74 selection: mediaSelector.selection74 selection: mediaSelector.selection
75 }75 }
7676
77 tools: ToolbarItems {77 head.actions: [
78 Button {78 Action {
79 anchors.verticalCenter: parent.verticalCenter79 objectName: "addButton"
80 text: i18n.tr("Add to Album")80 text: i18n.tr("Add to Album")
81 objectName: "addButton"81 iconName: "add"
82 color: Gallery.HIGHLIGHT_BUTTON_COLOR
83 width: units.gu(16)
84 enabled: mediaSelector.selection.selectedCount82 enabled: mediaSelector.selection.selectedCount
85 onTriggered: {83 onTriggered: {
86 mediaSelector.addClicked();84 mediaSelector.addClicked();
87 mediaSelector.hide();85 mediaSelector.hide();
88 }86 }
89 }87 }
88 ]
9089
91 back: Button {90 head.backAction: Action {
92 anchors.verticalCenter: parent.verticalCenter91 objectName: "cancelButton"
93 text: i18n.tr("Cancel")92 text: i18n.tr("Cancel")
94 objectName: "cancelButton"93 iconName: "back"
95 width: units.gu(10)94 onTriggered: {
96 onClicked: {95 mediaSelector.hide();
97 mediaSelector.hide();
98 }
99 }96 }
100 opened: true
101 locked: true
102 }97 }
10398
104 PropertyAnimation {99 PropertyAnimation {
105100
=== modified file 'rc/qml/EventsOverview.qml'
--- rc/qml/EventsOverview.qml 2014-03-10 17:20:03 +0000
+++ rc/qml/EventsOverview.qml 2014-09-03 23:54:36 +0000
@@ -94,7 +94,7 @@
94 }94 }
95 onAddClicked: {95 onAddClicked: {
96 __albumPicker = PopupUtils.open(Qt.resolvedUrl("Components/PopupAlbumPicker.qml"),96 __albumPicker = PopupUtils.open(Qt.resolvedUrl("Components/PopupAlbumPicker.qml"),
97 caller,97 null,
98 {contentHeight: organicEventView.__pickerContentHeight});98 {contentHeight: organicEventView.__pickerContentHeight});
99 }99 }
100 onDeleteClicked: {100 onDeleteClicked: {
101101
=== modified file 'rc/qml/GalleryApplication.qml'
--- rc/qml/GalleryApplication.qml 2014-08-14 21:53:31 +0000
+++ rc/qml/GalleryApplication.qml 2014-09-03 23:54:36 +0000
@@ -190,6 +190,7 @@
190190
191 Loader {191 Loader {
192 id: loadingScreen192 id: loadingScreen
193 objectName: 'loadingScreen'
193 anchors.fill: parent194 anchors.fill: parent
194 visible: mainScreenLoader.status !== Loader.Ready195 visible: mainScreenLoader.status !== Loader.Ready
195 source: visible ? Qt.resolvedUrl("LoadingScreen.qml") : ""196 source: visible ? Qt.resolvedUrl("LoadingScreen.qml") : ""
@@ -201,9 +202,7 @@
201 source: allLoaded ? ((APP.pickModeEnabled) ? Qt.resolvedUrl("PickerScreen.qml") :202 source: allLoaded ? ((APP.pickModeEnabled) ? Qt.resolvedUrl("PickerScreen.qml") :
202 Qt.resolvedUrl("MainScreen.qml")) : ""203 Qt.resolvedUrl("MainScreen.qml")) : ""
203 visible: status === Loader.Ready204 visible: status === Loader.Ready
204 // FIXME: this causes https://bugs.launchpad.net/bugs/1356841 205 asynchronous: true
205 // even though it fixes the spinner loading animation, comment out for now
206 //asynchronous: true
207 }206 }
208207
209 Component.onCompleted: {208 Component.onCompleted: {
210209
=== modified file 'rc/qml/MainScreen.qml'
--- rc/qml/MainScreen.qml 2014-06-10 18:54:21 +0000
+++ rc/qml/MainScreen.qml 2014-09-03 23:54:36 +0000
@@ -31,6 +31,8 @@
31 id: overview31 id: overview
32 objectName: "overview"32 objectName: "overview"
3333
34 useDeprecatedToolbar: false
35
34 anchors.fill: parent36 anchors.fill: parent
35 applicationName: "gallery-app"37 applicationName: "gallery-app"
36 automaticOrientation: application.automaticOrientation38 automaticOrientation: application.automaticOrientation
3739
=== modified file 'rc/qml/MediaViewer/GalleryPhotoComponent.qml'
--- rc/qml/MediaViewer/GalleryPhotoComponent.qml 2014-08-11 20:34:23 +0000
+++ rc/qml/MediaViewer/GalleryPhotoComponent.qml 2014-09-03 23:54:36 +0000
@@ -108,10 +108,8 @@
108 // prevent this segfault & crash from occurring.108 // prevent this segfault & crash from occurring.
109 visible: isLoaded;109 visible: isLoaded;
110110
111 sourceSize: {111 sourceSize.width: width
112 width: width112 sourceSize.height: height
113 height: height
114 }
115113
116 // use cache: !isAnimate setting for flicker-free animations and reflows114 // use cache: !isAnimate setting for flicker-free animations and reflows
117 asynchronous: !isAnimate115 asynchronous: !isAnimate
118116
=== modified file 'rc/qml/MediaViewer/MediaViewer.qml'
--- rc/qml/MediaViewer/MediaViewer.qml 2014-07-04 11:29:31 +0000
+++ rc/qml/MediaViewer/MediaViewer.qml 2014-09-03 23:54:36 +0000
@@ -20,7 +20,7 @@
2020
21import QtQuick 2.021import QtQuick 2.0
22import Gallery 1.022import Gallery 1.0
23import Ubuntu.Components 0.123import Ubuntu.Components 1.1
24import Ubuntu.Components.Popups 0.124import Ubuntu.Components.Popups 0.1
25import Ubuntu.Components.ListItems 0.1 as ListItem25import Ubuntu.Components.ListItems 0.1 as ListItem
26import Ubuntu.Content 0.126import Ubuntu.Content 0.1
@@ -60,13 +60,14 @@
60 //60 //
61 // Since there is no current item if there are no more photo objects left in the model,61 // Since there is no current item if there are no more photo objects left in the model,
62 // the check catches this before we can inadvertently follow a stale pointer.62 // the check catches this before we can inadvertently follow a stale pointer.
63 property bool isReady: model != null && model.count > 0 &&63 property bool isReady: model != null && model.count > 0 && galleryPhotoViewer.currentItem
64 (galleryPhotoViewer.currentItem ? galleryPhotoViewer.currentItem.isLoaded : false)
6564
66 // tooolbar actions for the full view65 // tooolbar actions for the full view
67 property Item tools: (media && !sharePicker.visible) ? (media.type === MediaSource.Photo ?66 property variant actions: (media && !sharePicker.visible) ? (media.type === MediaSource.Photo ?
68 d.photoToolbar : d.videoToolbar)67 d.photoActions : d.videoActions)
69 : null68 : []
69
70 property variant backAction: d.backAction
7071
71 /*!72 /*!
72 */73 */
@@ -113,6 +114,16 @@
113 galleryPhotoViewer.currentItem.togglePlayPause();114 galleryPhotoViewer.currentItem.togglePlayPause();
114 }115 }
115116
117 function setHeaderVisibility(visible)
118 {
119 header.visible = visible;
120 }
121
122 function toggleHeaderVisibility()
123 {
124 setHeaderVisibility(!header.visible);
125 }
126
116 Rectangle{127 Rectangle{
117 color: "black"128 color: "black"
118 anchors.fill: parent129 anchors.fill: parent
@@ -152,37 +163,19 @@
152 media = model.getAt(currentIndex);163 media = model.getAt(currentIndex);
153 }164 }
154165
155 delegate: Item {166 delegate: SingleMediaViewer {
156 /// Is true while the media content is loaded167 id: media
157 property bool isLoaded: delegateView.item.isLoaded168 objectName: "openedMedia" + index
158 /// Is true when the view is in a state, where the user possibly169 mediaFileURL: model.mediaSource.path
159 /// interacts with the media (and not swipe to another media)170 mediaFileType: model.mediaSource.type
160 property bool userInteracting: delegateView.item.state === "zoomed"171 maxDimension: Math.max(galleryPhotoViewer.width, galleryPhotoViewer.height)
161 /// Needed as ListView.isCurrentItem can't be used directly
162 property bool isActive: ListView.isCurrentItem
163 /// True if a video is currently played
164 property bool isPlayingVideo: galleryPhotoViewer.currentItem ?
165 galleryPhotoViewer.currentItem.state === "playing"
166 : false
167
168 // set the view to it's original state
169 function reset() {
170 delegateView.item.reset();
171 }
172 /// Toggles between play and pause - only usful when a video is shown
173 function togglePlayPause() {
174 if (model.mediaSource.type === MediaSource.Video)
175 delegateView.item.togglePlayPause();
176 }
177
178 onIsActiveChanged: {
179 if (!isActive)
180 reset()
181 }
182172
183 width: galleryPhotoViewer.width173 width: galleryPhotoViewer.width
184 height: galleryPhotoViewer.height174 height: galleryPhotoViewer.height
185 state: delegateView.item.state175
176 // Needed as ListView.isCurrentItem can't be used directly in a change handler
177 property bool isActive: ListView.isCurrentItem
178 onIsActiveChanged: if (!isActive) reset();
186179
187 opacity: {180 opacity: {
188 if (!galleryPhotoViewer.moving || galleryPhotoViewer.contentX < 0181 if (!galleryPhotoViewer.moving || galleryPhotoViewer.contentX < 0
@@ -192,26 +185,12 @@
192 return 1.0 - Math.abs((galleryPhotoViewer.contentX - x) / width);185 return 1.0 - Math.abs((galleryPhotoViewer.contentX - x) / width);
193 }186 }
194187
195 Component {188 onClicked: viewerWrapper.toggleHeaderVisibility()
196 id: component_delegatePhotoView
197 PhotoViewerDelegate {
198 useInteractivePreview: false
199 mediaSource: model.mediaSource
200 }
201 }
202 Component {
203 id: component_delegateVideoView
204 VideoViewerDelegate {
205 mediaSource: model.mediaSource
206 }
207 }
208 Loader {
209 id: delegateView
210 anchors.fill: parent
211 sourceComponent: model.mediaSource.type === MediaSource.Photo ?
212 component_delegatePhotoView : component_delegateVideoView
213 }
214189
190 Connections {
191 target: model.mediaSource
192 onDataChanged: media.reload()
193 }
215 }194 }
216195
217 // Don't allow flicking while the chrome is actively displaying a popup196 // Don't allow flicking while the chrome is actively displaying a popup
@@ -233,6 +212,8 @@
233 anchors.fill: parent212 anchors.fill: parent
234 visible: false213 visible: false
235214
215 onVisibleChanged: viewerWrapper.setHeaderVisibility(!visible)
216
236 ContentPeerPicker {217 ContentPeerPicker {
237 objectName: "sharePicker"218 objectName: "sharePicker"
238 anchors.fill: parent219 anchors.fill: parent
@@ -488,123 +469,96 @@
488 Item {469 Item {
489 id: d470 id: d
490471
491 property Item photoToolbar: ToolbarItems {472 property list<Action> photoActions: [
492 ToolbarButton {473 Action {
493 id: photoEditButton
494 objectName: "editButton"474 objectName: "editButton"
495 action: Action {475 text: i18n.tr("Edit")
496 text: i18n.tr("Edit")476 iconSource: "../../img/edit.png"
497 iconSource: "../../img/edit.png"477 onTriggered: PopupUtils.open(editPopoverComponent, null);
498 onTriggered: {478 },
499 PopupUtils.open(editPopoverComponent, photoEditButton);479 Action {
500 }
501 }
502 }
503 ToolbarButton {
504 id: photoAddButton
505 objectName: "addButton"480 objectName: "addButton"
506 action: Action {481 text: i18n.tr("Add to album")
507 text: i18n.tr("Add photo to album")482 iconName: "add"
508 iconSource: "../../img/add.png"483 onTriggered: {
509 onTriggered: {484 __albumPicker = PopupUtils.open(Qt.resolvedUrl("../Components/PopupAlbumPicker.qml"),
510 __albumPicker = PopupUtils.open(Qt.resolvedUrl("../Components/PopupAlbumPicker.qml"),485 null,
511 photoAddButton,486 {contentHeight: viewerWrapper.__pickerContentHeight});
512 {contentHeight: viewerWrapper.__pickerContentHeight});
513 }
514 }487 }
515 text: i18n.tr("Add")488 },
516 }489 Action {
517 ToolbarButton {
518 objectName: "deleteButton"490 objectName: "deleteButton"
519 action: Action {
520 text: i18n.tr("Delete")
521 iconSource: "../../img/delete.png"
522 onTriggered: {
523 if (album)
524 PopupUtils.open(removeFromAlbumDialog, null);
525 else
526 PopupUtils.open(deleteDialog, null);
527 }
528 }
529 text: i18n.tr("Delete")491 text: i18n.tr("Delete")
530 }492 iconName: "delete"
531 ToolbarButton {493 onTriggered: {
532 id: photoShareButton494 if (album)
495 PopupUtils.open(removeFromAlbumDialog, null);
496 else
497 PopupUtils.open(deleteDialog, null);
498 }
499 },
500 Action {
533 objectName: "shareButton"501 objectName: "shareButton"
502 text: i18n.tr("Share photo")
503 iconName: "share"
534 visible: !APP.desktopMode504 visible: !APP.desktopMode
535 action: Action {505 onTriggered: sharePicker.visible = true;
536 text: i18n.tr("Share photo")506 }
537 iconSource: "../../img/share.png"507 ]
538 onTriggered: {508
539 sharePicker.visible = true;
540 }
541 }
542 text: i18n.tr("Share")
543 }
544 back: ToolbarButton {
545 objectName: "backButton"
546 text: i18n.tr("Back")
547 iconSource: "../../img/back.png"
548 onTriggered: {
549 galleryPhotoViewer.currentItem.reset();
550 closeRequested();
551 }
552 }
553 }
554509
555 property Item videoToolbar: ToolbarItems {510 property list<Action> videoActions: [
556 ToolbarButton {511 Action {
557 text: galleryPhotoViewer.currentItem ?512 text: galleryPhotoViewer.currentItem ?
558 (galleryPhotoViewer.currentItem.isPlayingVideo ?513 (galleryPhotoViewer.currentItem.isPlayingVideo ?
559 i18n.tr("Pause") : i18n.tr("Play"))514 i18n.tr("Pause") : i18n.tr("Play"))
560 : ""515 : ""
561 iconSource: galleryPhotoViewer.currentItem ?516 iconSource: galleryPhotoViewer.currentItem ?
562 (galleryPhotoViewer.currentItem.isPlayingVideo ?517 (galleryPhotoViewer.currentItem.isPlayingVideo ?
563 "../../img/icon_pause.png" : "../../img/icon_play.png")518 "../../img/icon_pause.png" : "../../img/icon_play.png")
564 : ""519 : ""
565 onTriggered: {520 onTriggered: galleryPhotoViewer.currentItem.togglePlayPause();
566 galleryPhotoViewer.currentItem.togglePlayPause();521 },
567 }522 Action {
568 }523 text: i18n.tr("Add to album")
569 ToolbarButton {524 iconName: "add"
570 id: videoAddButton
571 objectName: "addButton"
572 text: i18n.tr("Add")
573 iconSource: "../../img/add.png"
574 onTriggered: {525 onTriggered: {
575 __albumPicker = PopupUtils.open(Qt.resolvedUrl("../Components/PopupAlbumPicker.qml"),526 __albumPicker = PopupUtils.open(Qt.resolvedUrl("../Components/PopupAlbumPicker.qml"),
576 videoAddButton,527 null,
577 {contentHeight: viewerWrapper.__pickerContentHeight});528 {contentHeight: viewerWrapper.__pickerContentHeight});
578 }529 }
579 }530 },
580 ToolbarButton {531 Action {
581 objectName: "deleteButton"
582 text: i18n.tr("Delete")532 text: i18n.tr("Delete")
583 iconSource: "../../img/delete.png"533 iconName: "delete"
584 onTriggered: {534 onTriggered: {
585 PopupUtils.open(deleteDialog, null);535 if (album)
536 PopupUtils.open(removeFromAlbumDialog, null);
537 else
538 PopupUtils.open(deleteDialog, null);
586 }539 }
587 }540 },
588 ToolbarButton {541 Action {
589 id: videoShareButton542 text: i18n.tr("Share photo")
590 objectName: "shareButton"543 iconName: "share"
591 visible: !APP.desktopMode544 visible: !APP.desktopMode
592 text: i18n.tr("Share")545 onTriggered: sharePicker.visible = true;
593 iconSource: "../../img/share.png"
594 onTriggered: {
595 sharePicker.visible = true;
596 }
597 }546 }
547 ]
598548
599 back: ToolbarButton {549 property Action backAction: Action {
600 objectName: "backButton"550 iconName: "back"
601 text: i18n.tr("Back")551 onTriggered: {
602 iconSource: "../../img/back.png"552 galleryPhotoViewer.currentItem.reset();
603 onTriggered: {553 closeRequested();
604 galleryPhotoViewer.currentItem.reset();
605 closeRequested();
606 }
607 }554 }
608 }555 }
609 }556 }
557
558 Rectangle{
559 id: headerBackground
560 width: parent.width
561 height: header.height
562 visible: header.visible
563 }
610}564}
611565
=== removed file 'rc/qml/MediaViewer/PhotoViewerDelegate.qml'
--- rc/qml/MediaViewer/PhotoViewerDelegate.qml 2014-03-19 20:01:31 +0000
+++ rc/qml/MediaViewer/PhotoViewerDelegate.qml 1970-01-01 00:00:00 +0000
@@ -1,129 +0,0 @@
1/*
2 * Copyright (C) 2011-2012 Canonical Ltd
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Lucas Beeler <lucas@yorba.org>
18 */
19
20import QtQuick 2.0
21import Gallery 1.0
22import Ubuntu.Components 0.1
23import Ubuntu.Components.Popups 0.1
24import Ubuntu.Components.ListItems 0.1 as ListItem
25import "../../js/Gallery.js" as Gallery
26
27/*!
28*/
29Item {
30 id: photoViewerDelegate
31
32 /// The photo to show
33 property MediaSource mediaSource
34 /*!
35 */
36 property bool useInteractivePreview
37 /*!
38 */
39 property alias isLoaded: fullPhotoComponentLoader.isLoaded
40
41 /*!
42 */
43 signal clicked()
44 /*!
45 */
46 signal zoomed()
47 /*!
48 */
49 signal unzoomed()
50
51 /// Resets the view to it's initial state
52 function reset() {
53 if (!isLoaded)
54 return;
55
56 fullPhotoComponentLoader.item.unzoom();
57 }
58
59 Connections {
60 target: mediaSource
61 onDataChanged: {
62 // Force the image to be reloaded, to pick up the new thumbnail
63 interactivePreviewImage.active = false;
64 interactivePreviewImage.active = true;
65 }
66 }
67
68 // Note that we haven't defined a state set in this component, even though
69 // we bind the "state" property here. This is intentional and is necessary
70 // to work around a binding issue on Qt 5.0 beta 1. Given a later version
71 // of Qt, this treatment might not be necessary.
72 state: (fullPhotoComponentLoader.item &&
73 !fullPhotoComponentLoader.item.fullyUnzoomed) ? "zoomed" :
74 "unzoomed";
75 Component {
76 id: interactivePreviewImageSource
77 Image {
78 fillMode: Image.PreserveAspectFit
79
80 source: mediaSource ? mediaSource.galleryPreviewPath : ""
81 sourceSize.width: 256
82 cache: false
83 }
84 }
85
86 Loader {
87 id: interactivePreviewImage
88 z: 0
89 anchors.fill: parent
90
91 visible: photoViewerDelegate.state == "unzoomed"
92 sourceComponent: interactivePreviewImageSource
93 }
94
95 Loader {
96 id: fullPhotoComponentLoader
97
98 property bool isLoaded: status == Loader.Ready
99
100 z: 1
101 asynchronous: true
102 anchors.fill: parent
103 opacity: (isLoaded && !useInteractivePreview) ? 1.0 : 0.0
104
105 sourceComponent: (!useInteractivePreview && !sourceComponent) ?
106 fullPhotoComponent : sourceComponent;
107
108 Component {
109 id: fullPhotoComponent
110
111 ZoomablePhotoComponent {
112 id: galleryPhotoComponent
113 objectName: "openedPhoto" + index
114
115 anchors.fill: parent
116 color: "transparent"
117
118 mediaSource: photoViewerDelegate.mediaSource
119 load: true;
120
121 ownerName: "photoViewerDelegate"
122
123 onZoomed: photoViewerDelegate.zoomed()
124 onUnzoomed: photoViewerDelegate.unzoomed()
125 onClicked: photoViewerDelegate.clicked()
126 }
127 }
128 }
129}
1300
=== modified file 'rc/qml/MediaViewer/PopupPhotoViewer.qml'
--- rc/qml/MediaViewer/PopupPhotoViewer.qml 2014-06-10 15:26:17 +0000
+++ rc/qml/MediaViewer/PopupPhotoViewer.qml 2014-09-03 23:54:36 +0000
@@ -18,7 +18,7 @@
18 */18 */
1919
20import QtQuick 2.020import QtQuick 2.0
21import Ubuntu.Components 0.121import Ubuntu.Components 1.1
22import "../Utility"22import "../Utility"
2323
24// A PhotoViewer that is opened and closed with the PhotoViewerTransition.24// A PhotoViewer that is opened and closed with the PhotoViewerTransition.
@@ -40,18 +40,18 @@
40 property bool isPoppedUp: popupPhotoViewer.visible && viewer.visible && !animationRunning40 property bool isPoppedUp: popupPhotoViewer.visible && viewer.visible && !animationRunning
4141
42 // updating active will automatically set the tools of the toolbar when activating.42 // updating active will automatically set the tools of the toolbar when activating.
43 onActiveChanged: {43 //onActiveChanged: {
44 if (active && popupPhotoViewer.header) {44 // if (active && popupPhotoViewer.header) {
45 popupPhotoViewer.header.hide();45 // popupPhotoViewer.header.hide();
46 // FIXME: The hide function of header is not hiding it sometimes.46 // // FIXME: The hide function of header is not hiding it sometimes.
47 // The issue started after we changed the page title47 // // The issue started after we changed the page title
48 popupPhotoViewer.header.visible = false;48 // popupPhotoViewer.header.visible = false;
49 }49 // }
5050 //
51 if (!active && popupPhotoViewer.header && popupPhotoViewer.header.visible == false) {51 // if (!active && popupPhotoViewer.header && popupPhotoViewer.header.visible == false) {
52 popupPhotoViewer.header.visible = true;52 // popupPhotoViewer.header.visible = true;
53 }53 // }
54 }54 //}
5555
56 title: i18n.tr("Gallery")56 title: i18n.tr("Gallery")
5757
@@ -95,7 +95,8 @@
95 closed();95 closed();
96 }96 }
9797
98 tools: viewer.tools98 head.actions: viewer.actions
99 head.backAction: viewer.backAction
99100
100 MediaViewer {101 MediaViewer {
101 id: viewer102 id: viewer
@@ -133,6 +134,7 @@
133 setCurrentPhoto(forMediaSource);134 setCurrentPhoto(forMediaSource);
134 viewer.openCompleted = true;135 viewer.openCompleted = true;
135 overview.pushPage(popupPhotoViewer);136 overview.pushPage(popupPhotoViewer);
137 header.visible = false;
136 opened();138 opened();
137 viewer.playVideo();139 viewer.playVideo();
138 }140 }
139141
=== added file 'rc/qml/MediaViewer/SingleMediaViewer.qml'
--- rc/qml/MediaViewer/SingleMediaViewer.qml 1970-01-01 00:00:00 +0000
+++ rc/qml/MediaViewer/SingleMediaViewer.qml 2014-09-03 23:54:36 +0000
@@ -0,0 +1,246 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.2
18import QtMultimedia 5.0
19import Ubuntu.Components 1.0
20import Ubuntu.Components.ListItems 1.0 as ListItems
21import Ubuntu.Components.Popups 1.0
22import Ubuntu.Content 0.1
23import Ubuntu.Thumbnailer 0.1
24import Gallery 1.0
25import "../Components"
26
27Item {
28 id: viewer
29 property bool pinchInProgress: zoomPinchArea.active
30 property var mediaFileType
31 property string mediaFileURL
32 property real maxDimension
33
34 property bool isVideo: mediaFileType === MediaSource.Video
35 property bool isPlayingVideo: isVideo && video.isPlaying
36 property bool userInteracting: pinchInProgress || flickable.sizeScale != 1.0
37 property bool fullyZoomed: flickable.sizeScale == zoomPinchArea.maximumZoom
38 property bool fullyUnzoomed: flickable.sizeScale == zoomPinchArea.minimumZoom
39
40 property alias paintedHeight: image.paintedHeight
41 property alias paintedWidth: image.paintedWidth
42
43 signal clicked()
44
45 function zoomIn(centerX, centerY, factor) {
46 flickable.scaleCenterX = centerX / (flickable.sizeScale * flickable.width);
47 flickable.scaleCenterY = centerY / (flickable.sizeScale * flickable.height);
48 flickable.sizeScale = factor;
49 }
50
51 function zoomOut() {
52 if (flickable.sizeScale != 1.0) {
53 flickable.scaleCenterX = flickable.contentX / flickable.width / (flickable.sizeScale - 1);
54 flickable.scaleCenterY = flickable.contentY / flickable.height / (flickable.sizeScale - 1);
55 flickable.sizeScale = 1.0;
56 }
57 }
58
59 function reload() {
60 if (!viewer.isVideo) {
61 var src = image.source
62 image.asynchronous = false
63 image.source = ""
64 image.asynchronous = true
65 image.source = src;
66
67 src = highResolutionImage.source
68 highResolutionImage.asynchronous = false
69 highResolutionImage.source = ""
70 highResolutionImage.asynchronous = true
71 highResolutionImage.source = src
72 }
73 }
74
75 function reset() {
76 if (viewer.isVideo) {
77 if (video.item) {
78 video.item.stop();
79 video.sourceComponent = null;
80 }
81 } else zoomOut()
82 }
83
84 function togglePlayPause() {
85 if (video.isPlaying) video.pause();
86 else video.play();
87 }
88
89 ActivityIndicator {
90 anchors.centerIn: parent
91 visible: running
92 running: image.status != Image.Ready
93 }
94
95 PinchArea {
96 id: zoomPinchArea
97 anchors.fill: parent
98
99 property real initialZoom
100 property real maximumScale: 3.0
101 property real minimumZoom: 1.0
102 property real maximumZoom: 3.0
103 property bool active: false
104 property var center
105
106 onPinchStarted: {
107 active = true;
108 initialZoom = flickable.sizeScale;
109 center = zoomPinchArea.mapToItem(media, pinch.startCenter.x, pinch.startCenter.y);
110 zoomIn(center.x, center.y, initialZoom);
111 }
112 onPinchUpdated: {
113 var zoomFactor = MathUtils.clamp(initialZoom * pinch.scale, minimumZoom, maximumZoom);
114 flickable.sizeScale = zoomFactor;
115 }
116 onPinchFinished: {
117 active = false;
118 }
119
120 Flickable {
121 id: flickable
122 anchors.fill: parent
123 contentWidth: media.width
124 contentHeight: media.height
125 contentX: (sizeScale - 1) * scaleCenterX * width
126 contentY: (sizeScale - 1) * scaleCenterY * height
127 interactive: !viewer.pinchInProgress
128
129 property real sizeScale: 1.0
130 property real scaleCenterX: 0.0
131 property real scaleCenterY: 0.0
132 Behavior on sizeScale {
133 enabled: !viewer.pinchInProgress
134 UbuntuNumberAnimation {duration: UbuntuAnimation.FastDuration}
135 }
136 Behavior on scaleCenterX {
137 UbuntuNumberAnimation {duration: UbuntuAnimation.FastDuration}
138 }
139 Behavior on scaleCenterY {
140 UbuntuNumberAnimation {duration: UbuntuAnimation.FastDuration}
141 }
142
143 Item {
144 id: media
145
146 width: flickable.width * flickable.sizeScale
147 height: flickable.height * flickable.sizeScale
148
149 Image {
150 id: image
151 anchors.fill: parent
152 asynchronous: true
153 cache: false
154 source: "image://thumbnailer/" + mediaFileURL.toString()
155 sourceSize {
156 width: viewer.maxDimension
157 height: viewer.maxDimension
158 }
159 fillMode: Image.PreserveAspectFit
160 opacity: status == Image.Ready ? 1.0 : 0.0
161 Behavior on opacity { UbuntuNumberAnimation {duration: UbuntuAnimation.FastDuration} }
162
163 }
164
165 Image {
166 id: highResolutionImage
167 anchors.fill: parent
168 asynchronous: true
169 cache: false
170 source: flickable.sizeScale > 1.0 ? mediaFileURL : ""
171 sourceSize {
172 width: width
173 height: height
174 }
175 fillMode: Image.PreserveAspectFit
176 }
177 }
178
179 Loader {
180 id: video
181 anchors.fill: parent
182 visible: viewer.isVideo && video.status == Loader.Ready &&
183 video.item.playbackState !== MediaPlayer.StoppedState
184 onLoaded: {
185 item.source = mediaFileURL;
186 item.play()
187 }
188
189 property bool isPlaying: item && item.playbackState === MediaPlayer.PlayingState
190 function play() {
191 if (item) item.play();
192 else sourceComponent = component_video;
193 }
194 function pause() {
195 if (item) item.pause();
196 }
197 }
198
199 Icon {
200 width: units.gu(5)
201 height: units.gu(5)
202 anchors.centerIn: parent
203 name: "media-playback-start"
204 color: "white"
205 opacity: 0.8
206 visible: viewer.isVideo &&
207 (!video.item || item.playbackState === MediaPlayer.StoppedState)
208 }
209
210 MouseArea {
211 anchors.fill: parent
212 onDoubleClicked: {
213 clickTimer.stop();
214 if (viewer.isVideo) return;
215
216 if (flickable.sizeScale < zoomPinchArea.maximumZoom) {
217 zoomIn(mouse.x, mouse.y, zoomPinchArea.maximumZoom);
218 } else {
219 zoomOut();
220 }
221 }
222 onClicked: clickTimer.start()
223
224 Timer {
225 id: clickTimer
226 interval: 20
227 onTriggered: viewer.clicked()
228 }
229 }
230
231 MouseArea {
232 anchors.centerIn: parent
233 width: units.gu(10)
234 height: units.gu(10)
235 enabled: viewer.isVideo
236 onClicked: viewer.togglePlayPause()
237 }
238 }
239
240 Component {
241 id: component_video
242 Video { }
243 }
244 }
245}
246
0247
=== removed file 'rc/qml/MediaViewer/VideoViewerDelegate.qml'
--- rc/qml/MediaViewer/VideoViewerDelegate.qml 2014-03-21 22:11:44 +0000
+++ rc/qml/MediaViewer/VideoViewerDelegate.qml 1970-01-01 00:00:00 +0000
@@ -1,125 +0,0 @@
1/*
2 * Copyright (C) 2013 Canonical Ltd
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.0
18import QtMultimedia 5.0
19import Gallery 1.0
20
21/*!
22VideoViewerDelegate is an item to show a vide thumbnail, and play the video
23if requrested
24*/
25Item {
26 id: videoViewerDelegate
27
28 /// The video item that to be shown by this component
29 property MediaSource mediaSource
30 /// Is true, once this component is fully usable
31 property bool isLoaded: thumbnail.status === Image.Ready
32
33 /// Stops the video playback if running
34 function reset() {
35 state = "stopped";
36 }
37
38 /// Starts playing the video
39 function playVideo() {
40 if (!loader_video.item)
41 loader_video.sourceComponent = component_video;
42
43 if (loader_video.item.source !== mediaSource.path)
44 loader_video.item.source = mediaSource.path;
45 loader_video.item.play();
46 }
47
48 /// Toggles between playing and pausing the video playback
49 function togglePlayPause() {
50 if (!loader_video.item)
51 loader_video.sourceComponent = component_video;
52
53 if (videoViewerDelegate.state === "playing") {
54 loader_video.item.pause();
55 } else {
56 videoViewerDelegate.playVideo();
57 }
58 }
59
60 Image {
61 id: thumbnail
62
63 anchors.fill: parent
64 fillMode: Image.PreserveAspectFit
65 source: mediaSource.galleryPreviewPath
66 asynchronous: true
67 }
68
69 Image {
70 // Display a play icon if the media is a video
71 source: "../../img/icon_play.png"
72 anchors.centerIn: parent
73 }
74
75 MouseArea {
76 anchors.fill: parent
77 onClicked: {
78 videoViewerDelegate.togglePlayPause();
79 }
80 }
81
82 Component {
83 id: component_video
84 Video {
85 id: video
86 onStopped: {
87 videoViewerDelegate.state = "stopped";
88 }
89 onPaused: {
90 videoViewerDelegate.state = "paused"
91 }
92 onPlaying: {
93 videoViewerDelegate.state = "playing"
94 }
95 }
96 }
97 Loader {
98 id: loader_video
99 anchors.fill: parent
100 }
101
102
103 state: "stopped"
104 states: [
105 State {
106 name: "playing"
107 PropertyChanges { target: thumbnail; visible: false }
108 },
109 State {
110 name: "paused"
111 PropertyChanges { target: thumbnail; visible: false }
112 },
113 State {
114 name: "stopped"
115 PropertyChanges { target: thumbnail; visible: true }
116 }
117 ]
118 onStateChanged: {
119 if (state === "stopped") {
120 if (loader_video.item)
121 loader_video.item.stop()
122 loader_video.sourceComponent = null
123 }
124 }
125}
1260
=== removed file 'rc/qml/MediaViewer/ZoomablePhotoComponent.qml'
--- rc/qml/MediaViewer/ZoomablePhotoComponent.qml 2014-04-04 13:16:49 +0000
+++ rc/qml/MediaViewer/ZoomablePhotoComponent.qml 1970-01-01 00:00:00 +0000
@@ -1,409 +0,0 @@
1/*
2 * Copyright (C) 2012 Canonical Ltd
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Charles Lindsay <chaz@yorba.org>
18 * Lucas Beeler <lucas@yorba.org>
19 */
20
21import QtQuick 2.0
22import "../../js/Gallery.js" as Gallery
23import "../../js/GalleryUtility.js" as GalleryUtility
24import "../../js/GraphicsRoutines.js" as GraphicsRoutines
25import "../Components"
26
27// PhotoComponent that allows you to zoom in on the photo.
28Rectangle {
29 id: zoomablePhotoComponent
30
31 /*!
32 */
33 signal loaded()
34 /*!
35 */
36 signal clicked()
37 /*!
38 */
39 signal zoomed()
40 /*!
41 */
42 signal unzoomed()
43
44 /*!
45 */
46 property var mediaSource
47 /*!
48 */
49 property bool load: false
50 /*!
51 */
52 property bool isPreview
53 /*!
54 */
55 property string ownerName
56
57 // read-only
58 /*!
59 */
60 property alias paintedWidth: unzoomedPhoto.paintedWidth
61 /*!
62 */
63 property alias paintedHeight: unzoomedPhoto.paintedHeight
64 /*!
65 */
66 property alias isLoaded: unzoomedPhoto.isLoaded
67 /*!
68 */
69 property int zoomFocusX: 0 // Relative to zoomablePhotoComponent.
70 /*!
71 */
72 property int zoomFocusY: 0
73 /*!
74 */
75 property real zoomFactor: 1
76 /*!
77 */
78 property bool fullyUnzoomed: (state === "unzoomed" && zoomFactor === 1)
79 /*!
80 */
81 property bool fullyZoomed: (state === "full_zoom" && zoomFactor === maxZoomFactor)
82
83 // Though little documented, Qt has a dedicated background thread, separate
84 // from the main GUI thread, in which it renders on-screen objects (see
85 // http://blog.qt.digia.com/blog/2012/08/20/render-thread-animations-in-qt-quick-2-0/
86 // for a discussion of this topic). Unfortunately, animation ticks are timed
87 // by the main GUI thread, but actual drawing in response to these ticks
88 // is done in the separate rendering thread. Because of this, you can get
89 // into a situation in which an animation reports that it has completed but
90 // the separate rendering thread still has a frame to draw. In all of my
91 // testing, I've never seen this timing mismatch exceed 1/30th of a second,
92 // which makes sense because the QML animation clock ticks every 1/60th of a
93 // second, according to the docs (see http://qt-project.org/doc/qt-5.0/qtqml/qml-qtquick2-timer.html),
94 // though implementations appear to be free to drop to half this rate
95 // (see https://bugreports.qt-project.org/browse/QTBUG-28487). So we define
96 // an animation frame as 1/30th of a second and wait this long before doing
97 // more drawing in response to the completion of an animation to prevent
98 // stuttering.
99 property int oneFrame: Math.ceil(1000 / 30);
100
101 // internal
102 /*!
103 */
104 property real maxZoomFactor: 2.5
105 /*!
106 */
107 property real photoFocusX: zoomFocusX - unzoomedPhoto.leftEdge
108 /*!
109 */
110 property real photoFocusY: zoomFocusY - unzoomedPhoto.topEdge
111 /*!
112 */
113 property bool isZoomAnimationInProgress: false
114
115 clip: true
116
117 /*!
118 */
119 function zoom(x, y) {
120 zoomFocusX = x;
121 zoomFocusY = y;
122 state = "full_zoom";
123 }
124
125 /*!
126 */
127 function unzoom() {
128 state = "unzoomed";
129 }
130
131 /*!
132 */
133 function toggleZoom(x, y) {
134 if (state === "unzoomed")
135 zoom(x, y);
136 else
137 unzoom();
138 }
139
140 states: [
141 State { name: "unzoomed";
142 PropertyChanges { target: zoomablePhotoComponent; zoomFactor: 1; }
143 },
144 State { name: "full_zoom";
145 PropertyChanges { target: zoomablePhotoComponent; zoomFactor: maxZoomFactor; }
146 },
147 State { name: "pinching";
148 // Setting the zoom factor to itself seems odd, but it's necessary to
149 // prevent zoomFactor from jumping when you start pinching.
150 PropertyChanges { target: zoomablePhotoComponent; zoomFactor: zoomFactor;
151 explicit: true; }
152 }
153 ]
154
155 transitions: [
156 // Double-click transitions.
157 Transition { from: "full_zoom"; to: "unzoomed";
158 SequentialAnimation {
159 ScriptAction { script: isZoomAnimationInProgress = true; }
160 NumberAnimation { properties: "zoomFactor"; easing.type: Easing.InQuad;
161 duration: Gallery.FAST_DURATION; }
162 PauseAnimation { duration: oneFrame }
163 ScriptAction { script: isZoomAnimationInProgress = false; }
164 }
165 },
166
167 Transition { from: "unzoomed"; to: "full_zoom";
168 SequentialAnimation {
169 ScriptAction { script: isZoomAnimationInProgress = true; }
170 NumberAnimation { properties: "zoomFactor"; easing.type: Easing.InQuad;
171 duration: Gallery.FAST_DURATION; }
172 PauseAnimation { duration: oneFrame }
173 ScriptAction { script: isZoomAnimationInProgress = false; }
174 }
175 },
176
177 Transition { from: "pinching"; to: "unzoomed";
178 SequentialAnimation {
179 ScriptAction { script: isZoomAnimationInProgress = true; }
180 NumberAnimation { properties: "zoomFactor"; easing.type: Easing.Linear;
181 duration: Gallery.SNAP_DURATION; }
182 PauseAnimation { duration: oneFrame }
183 ScriptAction { script: isZoomAnimationInProgress = false; }
184 }
185 },
186
187 Transition { from: "pinching"; to: "full_zoom";
188 SequentialAnimation {
189 ScriptAction { script: isZoomAnimationInProgress = true; }
190 NumberAnimation { properties: "zoomFactor"; easing.type: Easing.Linear;
191 duration: Gallery.SNAP_DURATION; }
192 PauseAnimation { duration: oneFrame }
193 ScriptAction { script: isZoomAnimationInProgress = false; }
194 }
195 }
196 ]
197
198 state: "unzoomed"
199
200 onStateChanged: {
201 if (state === "full_zoom")
202 zoomed();
203 else if (state === "unzoomed")
204 unzoomed();
205 }
206
207 GalleryPhotoComponent {
208 id: unzoomedPhoto
209
210 property real leftEdge: (parent.width - paintedWidth) / 2
211 property real topEdge: (parent.height - paintedHeight) / 2
212
213 function isInsidePhoto(x, y) {
214 return (x >= leftEdge && x < leftEdge + paintedWidth &&
215 y >= topEdge && y < topEdge + paintedHeight);
216 }
217
218 anchors.fill: parent
219 visible: fullyUnzoomed
220 color: zoomablePhotoComponent.color
221
222 mediaSource: zoomablePhotoComponent.mediaSource
223 load: zoomablePhotoComponent.load && zoomablePhotoComponent.fullyUnzoomed
224 isPreview: zoomablePhotoComponent.isPreview
225 ownerName: zoomablePhotoComponent.ownerName + "unzoomedPhoto"
226 }
227
228 PinchArea {
229 id: pinchArea
230
231 property bool zoomingIn // Splaying to zoom in, vs. pinching to zoom out.
232 property real initialZoomFactor
233
234 anchors.fill: parent
235
236 // QML seems to ignore these, so we have to manually keep scale in check
237 // inside onPinchUpdated. The 0.9 and 1.1 are just fudge factors to give
238 // us a little bounce when you go past the zoom limit.
239 pinch.minimumScale: 1 / initialZoomFactor * 0.9
240 pinch.maximumScale: maxZoomFactor / initialZoomFactor * 1.1
241
242 onPinchStarted: {
243 zoomingIn = false;
244 initialZoomFactor = zoomFactor;
245
246 if (fullyUnzoomed) {
247 if (unzoomedPhoto.isInsidePhoto(pinch.center.x, pinch.center.y)) {
248 zoomFocusX = pinch.center.x;
249 zoomFocusY = pinch.center.y;
250 } else {
251 zoomFocusX = parent.width / 2;
252 zoomFocusY = parent.height / 2;
253 }
254 }
255
256 zoomablePhotoComponent.state = "pinching";
257 }
258
259 onPinchUpdated: {
260 // Determine if we're still zooming in or out. Allow for a small
261 // variance to account for touch noise.
262 if (Math.abs(pinch.scale - pinch.previousScale) > 0.001)
263 zoomingIn = (pinch.scale > pinch.previousScale);
264
265 // For some reason, the PinchArea ignores these settings.
266 var scale = GraphicsRoutines.clamp(pinch.scale,
267 pinchArea.pinch.minimumScale, pinchArea.pinch.maximumScale);
268
269 zoomFactor = initialZoomFactor * scale;
270 }
271
272 onPinchFinished: zoomablePhotoComponent.state = (zoomingIn ? "full_zoom" : "unzoomed")
273
274 MouseAreaWithMultipoint {
275 desktop: APP.desktopMode
276 anchors.fill: parent
277 enabled: fullyUnzoomed
278
279 onClicked: zoomablePhotoComponent.clicked()
280 onDoubleClicked: {
281 if (unzoomedPhoto.isInsidePhoto(mouse.x, mouse.y))
282 zoom(mouse.x, mouse.y);
283 else
284 zoomablePhotoComponent.clicked();
285 }
286 }
287 }
288
289 Loader {
290 id: zoomAssemblyLoader
291
292 anchors.fill: parent
293
294 sourceComponent: (fullyUnzoomed ? undefined : zoomAssemblyComponent)
295
296 Component {
297 id: zoomAssemblyComponent
298
299 Item {
300 anchors.fill: parent
301
302 Flickable {
303 id: zoomArea
304
305 property real zoomAreaZoomFactor: maxZoomFactor
306 property real minContentFocusX: (contentWidth < parent.width
307 ? contentWidth : parent.width) / 2
308 property real maxContentFocusX: contentWidth - minContentFocusX
309 property real minContentFocusY: (contentHeight < parent.height
310 ? contentHeight : parent.height) / 2
311 property real maxContentFocusY: contentHeight - minContentFocusY
312 property real contentFocusX: GraphicsRoutines.clamp(
313 photoFocusX * zoomAreaZoomFactor,
314 minContentFocusX, maxContentFocusX)
315 property real contentFocusY: GraphicsRoutines.clamp(
316 photoFocusY * zoomAreaZoomFactor,
317 minContentFocusY, maxContentFocusY)
318 // Translate between focus point and top/left point. Note: you might think
319 // that this should take into account the left and top margins, but
320 // apparently not.
321 property real contentFocusLeft: contentFocusX - parent.width / 2
322 property real contentFocusTop: contentFocusY - parent.height / 2
323
324 anchors.fill: parent
325 visible: fullyZoomed && !isZoomAnimationInProgress
326
327 onVisibleChanged: {
328 if (visible) {
329 contentX = contentFocusLeft;
330 contentY = contentFocusTop;
331 }
332 }
333
334 onContentXChanged: {
335 var contentFocusX = contentX + width / 2;
336 var photoFocusX = contentFocusX / zoomAreaZoomFactor;
337 zoomFocusX = photoFocusX + unzoomedPhoto.leftEdge;
338 }
339
340 onContentYChanged: {
341 var contentFocusY = contentY + height / 2;
342 var photoFocusY = contentFocusY / zoomAreaZoomFactor;
343 zoomFocusY = photoFocusY + unzoomedPhoto.topEdge;
344 }
345
346 flickableDirection: Flickable.HorizontalAndVerticalFlick
347 contentWidth: unzoomedPhoto.paintedWidth * zoomAreaZoomFactor
348 contentHeight: unzoomedPhoto.paintedHeight * zoomAreaZoomFactor
349
350 leftMargin: Math.max(0, (parent.width - contentWidth) / 2)
351 rightMargin: leftMargin
352 topMargin: Math.max(0, (parent.height - contentHeight) / 2)
353 bottomMargin: topMargin
354
355 GalleryPhotoComponent {
356 id: zoomedPhoto
357
358 anchors.fill: parent
359 color: zoomablePhotoComponent.color
360
361 mediaSource: zoomablePhotoComponent.mediaSource
362 load: zoomablePhotoComponent.load && fullyZoomed
363
364 isPreview: zoomablePhotoComponent.isPreview
365 ownerName: zoomablePhotoComponent.ownerName + "zoomedPhoto"
366
367 MouseAreaWithMultipoint {
368 desktop: APP.desktopMode
369 anchors.fill: parent
370
371 onClicked: zoomablePhotoComponent.clicked()
372 onDoubleClicked: unzoom()
373 }
374 }
375 }
376
377 GalleryPhotoComponent {
378 id: transitionPhoto
379
380 property real unzoomedX: unzoomedPhoto.leftEdge
381 property real unzoomedY: unzoomedPhoto.topEdge
382 property real zoomedX: -zoomArea.contentFocusLeft
383 property real zoomedY: -zoomArea.contentFocusTop
384
385 property real zoomFraction: (zoomFactor - 1) / (maxZoomFactor - 1)
386
387 x: GalleryUtility.interpolate(unzoomedX, zoomedX, zoomFraction)
388 y: GalleryUtility.interpolate(unzoomedY, zoomedY, zoomFraction)
389 width: unzoomedPhoto.paintedWidth
390 height: unzoomedPhoto.paintedHeight
391 scale: zoomFactor
392 transformOrigin: Item.TopLeft
393
394 visible: zoomablePhotoComponent.isZoomAnimationInProgress ||
395 zoomablePhotoComponent.state == "pinching" ||
396 !zoomedPhoto.isLoaded
397
398 color: zoomablePhotoComponent.color
399
400 mediaSource: zoomablePhotoComponent.mediaSource
401 load: zoomablePhotoComponent.load
402 isPreview: zoomablePhotoComponent.isPreview
403 isAnimate: true
404 ownerName: zoomablePhotoComponent.ownerName + "transitionPhoto"
405 }
406 }
407 }
408 }
409}
4100
=== modified file 'rc/qml/OrganicView/OrganicView.qml'
--- rc/qml/OrganicView/OrganicView.qml 2014-03-10 17:20:03 +0000
+++ rc/qml/OrganicView/OrganicView.qml 2014-09-03 23:54:36 +0000
@@ -18,7 +18,7 @@
18 */18 */
1919
20import QtQuick 2.020import QtQuick 2.0
21import Ubuntu.Components 0.121import Ubuntu.Components 1.1
22import "../Utility"22import "../Utility"
23import "../../js/Gallery.js" as Gallery23import "../../js/Gallery.js" as Gallery
2424
2525
=== modified file 'rc/qml/PhotosOverview.qml'
--- rc/qml/PhotosOverview.qml 2013-09-30 17:01:38 +0000
+++ rc/qml/PhotosOverview.qml 2014-09-03 23:54:36 +0000
@@ -111,7 +111,7 @@
111 }111 }
112 onAddClicked: {112 onAddClicked: {
113 __albumPicker = PopupUtils.open(Qt.resolvedUrl("Components/PopupAlbumPicker.qml"),113 __albumPicker = PopupUtils.open(Qt.resolvedUrl("Components/PopupAlbumPicker.qml"),
114 caller,114 null,
115 {contentHeight: photosOverview.__pickerContentHeight});115 {contentHeight: photosOverview.__pickerContentHeight});
116 }116 }
117 onDeleteClicked: {117 onDeleteClicked: {
118118
=== modified file 'rc/qml/PickerScreen.qml'
--- rc/qml/PickerScreen.qml 2014-08-14 10:59:38 +0000
+++ rc/qml/PickerScreen.qml 2014-09-03 23:54:36 +0000
@@ -15,7 +15,7 @@
15 */15 */
1616
17import QtQuick 2.017import QtQuick 2.0
18import Ubuntu.Components 0.118import Ubuntu.Components 1.1
19import Gallery 1.019import Gallery 1.0
20import "Components"20import "Components"
21import "OrganicView"21import "OrganicView"
@@ -29,6 +29,8 @@
29 id: pickerMainView29 id: pickerMainView
30 objectName: "pickerMainView"30 objectName: "pickerMainView"
3131
32 useDeprecatedToolbar: false
33
32 /// Model of all media34 /// Model of all media
33 property MediaCollectionModel mediaLibrary: MediaCollectionModel {35 property MediaCollectionModel mediaLibrary: MediaCollectionModel {
34 monitored: true36 monitored: true
@@ -58,7 +60,8 @@
58 id: eventSelectView60 id: eventSelectView
59 objectName: "eventSelectView"61 objectName: "eventSelectView"
6062
61 tools: pickTools63 head.actions: pickActions
64
62 selection: pickerMainView.selection65 selection: pickerMainView.selection
63 model: EventCollectionModel {66 model: EventCollectionModel {
64 mediaTypeFilter: APP.mediaTypeFilter67 mediaTypeFilter: APP.mediaTypeFilter
@@ -80,7 +83,7 @@
80 id: photosOverview83 id: photosOverview
81 objectName: "photosPage"84 objectName: "photosPage"
8285
83 tools: pickTools86 head.actions: pickActions
8487
85 Image {88 Image {
86 anchors.fill: parent89 anchors.fill: parent
@@ -97,32 +100,24 @@
97 }100 }
98 }101 }
99102
100 property ToolbarItems pickTools: ToolbarItems {103 property list<Action> pickActions: [
101 Button {104 Action {
102 anchors.verticalCenter: parent.verticalCenter
103 text: i18n.tr("Pick")105 text: i18n.tr("Pick")
104 objectName: "pickButton"106 objectName: "pickButton"
105 color: Gallery.HIGHLIGHT_BUTTON_COLOR
106 width: units.gu(16)
107 enabled: pickerMainView.selection.selectedCount > 0107 enabled: pickerMainView.selection.selectedCount > 0
108 onClicked: {108 iconName: "ok"
109 onTriggered: {
109 if (!enabled)110 if (!enabled)
110 return;111 return;
111112
112 APP.returnPickedContent(mediaLibrary.selectedMedias);113 APP.returnPickedContent(mediaLibrary.selectedMedias);
113 }114 }
114 }115 },
115116 Action {
116 back: Button {
117 anchors.verticalCenter: parent.verticalCenter
118 text: i18n.tr("Cancel")117 text: i18n.tr("Cancel")
119 objectName: "cancelButton"118 objectName: "cancelButton"
120 width: units.gu(10)119 iconName: "close"
121 onClicked: {120 onTriggered: APP.contentPickingCanceled()
122 APP.contentPickingCanceled()
123 }
124 }121 }
125 opened: true122 ]
126 locked: true
127 }
128}123}
129124
=== modified file 'rc/qml/Utility/PhotosToolbarActions.qml'
--- rc/qml/Utility/PhotosToolbarActions.qml 2014-03-19 20:19:57 +0000
+++ rc/qml/Utility/PhotosToolbarActions.qml 2014-09-03 23:54:36 +0000
@@ -29,23 +29,29 @@
29 signal startCamera()29 signal startCamera()
3030
31 ToolbarButton {31 ToolbarButton {
32 objectName: "selectButton"32 action: Action {
33 text: i18n.tr("Select")33 objectName: "selectButton"
34 iconSource: Qt.resolvedUrl("../../img/select.png")34 text: i18n.tr("Select")
35 enabled: root.selection !== null35 iconSource: Qt.resolvedUrl("../../img/select.png")
36 onTriggered: root.selection.inSelectionMode = true;36 enabled: root.selection !== null
37 onTriggered: root.selection.inSelectionMode = true;
38 }
37 }39 }
38 ToolbarButton {40 ToolbarButton {
39 objectName: "importButton"41 objectName: "importButton"
40 text: i18n.tr("Import")42 action: Action {
41 iconSource: Qt.resolvedUrl("../../img/import-image.png")43 text: i18n.tr("Import")
42 enabled: false44 iconSource: Qt.resolvedUrl("../../img/import-image.png")
45 visible: false
46 }
43 }47 }
44 ToolbarButton {48 ToolbarButton {
45 objectName: "cameraButton"49 action: Action {
46 text: i18n.tr("Camera")50 objectName: "cameraButton"
47 visible: !APP.desktopMode51 text: i18n.tr("Camera")
48 iconSource: Qt.resolvedUrl("../../img/camera.png")52 visible: !APP.desktopMode
49 onTriggered: Qt.openUrlExternally("appid://com.ubuntu.camera/camera/current-user-version")53 iconSource: Qt.resolvedUrl("../../img/camera.png")
54 onTriggered: Qt.openUrlExternally("appid://com.ubuntu.camera/camera/current-user-version")
55 }
50 }56 }
51}57}
5258
=== modified file 'rc/qml/Utility/SelectionToolbarAction.qml'
--- rc/qml/Utility/SelectionToolbarAction.qml 2013-09-19 14:53:09 +0000
+++ rc/qml/Utility/SelectionToolbarAction.qml 2014-09-03 23:54:36 +0000
@@ -33,6 +33,8 @@
33 signal addClicked(var caller)33 signal addClicked(var caller)
34 ///Emitted when delete was clicked34 ///Emitted when delete was clicked
35 signal deleteClicked()35 signal deleteClicked()
36 ///Emitted when share was clicked
37 signal shareClicked()
3638
37 // in selection mode, never hide the toolbar:39 // in selection mode, never hide the toolbar:
38 opened: true40 opened: true
@@ -41,32 +43,40 @@
41 ToolbarButton {43 ToolbarButton {
42 id: addButton44 id: addButton
43 objectName: "addButton"45 objectName: "addButton"
44 text: i18n.tr("Add")46 action: Action {
45 iconSource: Qt.resolvedUrl("../../img/add.png")47 text: i18n.tr("Add")
46 enabled: root.selection.selectedCount > 048 iconName: "add"
47 onTriggered: root.addClicked(addButton);49 enabled: root.selection.selectedCount > 0
48 }50 onTriggered: root.addClicked(addButton);
49 ToolbarButton {51 }
50 objectName: "deleteButton"52 }
51 text: i18n.tr("Delete")53 ToolbarButton {
52 iconSource: Qt.resolvedUrl("../../img/delete.png")54 action: Action {
53 enabled: root.selection.selectedCount > 055 objectName: "deleteButton"
54 onTriggered:root.deleteClicked();56 text: i18n.tr("Delete")
55 }57 iconName: "delete"
56 ToolbarButton {58 enabled: root.selection.selectedCount > 0
57 objectName: "shareButton"59 onTriggered:root.deleteClicked();
58 text: i18n.tr("Share")60 }
59 iconSource: Qt.resolvedUrl("../../img/share.png")61 }
60 enabled: false62 ToolbarButton {
63 action: Action {
64 objectName: "shareButton"
65 text: i18n.tr("Share")
66 iconName: "share"
67 enabled: root.selection.selectedCount > 0
68 onTriggered: root.shareClicked();
69 }
61 }70 }
6271
63 back: Button {72 back: Button {
64 objectName: "cancelButton"73 objectName: "cancelButton"
65 anchors.verticalCenter: parent.verticalCenter74 action: Action {
66 text: i18n.tr("Cancel")75 text: i18n.tr("Cancel")
67 width: units.gu(10)76 iconName: "back"
68 onClicked: {77 onTriggered: {
69 root.cancelClicked();78 root.cancelClicked();
79 }
70 }80 }
71 }81 }
72}82}
7383
=== modified file 'tests/autopilot/gallery_app/emulators/album_view.py'
--- tests/autopilot/gallery_app/emulators/album_view.py 2014-06-12 16:42:04 +0000
+++ tests/autopilot/gallery_app/emulators/album_view.py 2014-09-03 23:54:36 +0000
@@ -38,10 +38,6 @@
38 return self.app.wait_select_single("AlbumViewer",38 return self.app.wait_select_single("AlbumViewer",
39 objectName="albumViewer")39 objectName="albumViewer")
4040
41 def get_toolbar_add_button(self):
42 """Returns the add button of the tollbar in the events view."""
43 return self.get_toolbar_named_toolbarbutton("addButton")
44
45 def get_first_photo(self):41 def get_first_photo(self):
46 """Returns the first photo in a newly opened album"""42 """Returns the first photo in a newly opened album"""
47 return self.app.select_many(43 return self.app.select_many(
@@ -103,14 +99,16 @@
103 matcher = LessThan99 matcher = LessThan
104 self.pointing_device.drag(100 self.pointing_device.drag(
105 mid_x, mid_y, # Start101 mid_x, mid_y, # Start
106 x + w, mid_y # Finish102 x + w, mid_y, # Finish
103 rate=3
107 )104 )
108105
109 elif 'right' == direction:106 elif 'right' == direction:
110 matcher = GreaterThan107 matcher = GreaterThan
111 self.pointing_device.drag(108 self.pointing_device.drag(
112 mid_x, mid_y, # Start109 mid_x, mid_y, # Start
113 x, mid_y # Finish110 x, mid_y, # Finish
111 rate=3
114 )112 )
115 else:113 else:
116 raise GalleryAppException(114 raise GalleryAppException(
117115
=== modified file 'tests/autopilot/gallery_app/emulators/gallery_utils.py'
--- tests/autopilot/gallery_app/emulators/gallery_utils.py 2014-06-13 13:57:20 +0000
+++ tests/autopilot/gallery_app/emulators/gallery_utils.py 2014-09-03 23:54:36 +0000
@@ -85,14 +85,14 @@
8585
86 def get_first_album(self):86 def get_first_album(self):
87 """Returns the first album in the albums view."""87 """Returns the first album in the albums view."""
88 # For some reasons the albums are returned in inverse order, so88 return self.get_album_at(0)
89 # the first album is acutally the last in the array
90 return self.get_album_at(-1)
9189
92 def get_album_at(self, position):90 def get_album_at(self, position):
93 """Returns the albums at this position in the albums view"""91 """Returns the albums at this position in the albums view"""
94 albums = self.select_many_retry("CheckerboardDelegate",92 albums = self.select_many_retry("CheckerboardDelegate",
95 objectName="checkerboardDelegate")93 objectName="checkerboardDelegate")
94 albums = sorted(
95 albums, key=lambda album: (album.globalRect.y, album.globalRect.x))
96 return albums[position]96 return albums[position]
9797
98 def get_edit_album_button(self):98 def get_edit_album_button(self):
9999
=== modified file 'tests/autopilot/gallery_app/emulators/main_screen.py'
--- tests/autopilot/gallery_app/emulators/main_screen.py 2014-04-01 19:18:50 +0000
+++ tests/autopilot/gallery_app/emulators/main_screen.py 2014-09-03 23:54:36 +0000
@@ -5,17 +5,32 @@
5# under the terms of the GNU General Public License version 3, as published5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.6# by the Free Software Foundation.
77
8from ubuntuuitoolkit import emulators as toolkit_emulators8import ubuntuuitoolkit
9from gallery_app.emulators import toolbar9
1010
1111class MainScreen(ubuntuuitoolkit.MainView):
12class MainScreen(toolkit_emulators.MainView):
13 """An emulator class that makes it easy to interact with the gallery app"""12 """An emulator class that makes it easy to interact with the gallery app"""
1413
15 def get_toolbar(self):14 def get_header(self):
16 """Return the Toolbar emulator of the MainView.15 """Return the Header emulator of the MainView."""
1716 return self.select_single(AppHeader, objectName='MainView_Header')
18 Overriden because the gallery app has custom buttons.17
1918
20 """19class AppHeader(ubuntuuitoolkit.Header):
21 return self.select_single(toolbar.Toolbar)20 """Header Autopilot helper.
21
22 We override this helper because on the gallery the gesture to show the
23 header when it's hidden it's not the default.
24
25 """
26
27 # XXX We are overriding internal methods that may change on the toolkit.
28 # The helper on the toolkit needs a public method that will be safe to
29 # override. Reported as bug http://pad.lv/1363591 --elopio - 2014-31-08
30
31 def _is_visible(self):
32 return self.visible
33
34 def _show(self):
35 self.pointing_device.click_object(self._get_top_container())
36 self.visible.wait_for(True)
2237
=== modified file 'tests/autopilot/gallery_app/emulators/photo_viewer.py'
--- tests/autopilot/gallery_app/emulators/photo_viewer.py 2014-08-27 20:28:51 +0000
+++ tests/autopilot/gallery_app/emulators/photo_viewer.py 2014-09-03 23:54:36 +0000
@@ -48,9 +48,8 @@
48 # Was using a list index (lp:1247711). Still needs fixing, I'm not48 # Was using a list index (lp:1247711). Still needs fixing, I'm not
49 # convinced this is a suitable way to select the correct item.49 # convinced this is a suitable way to select the correct item.
50 return self.app.wait_select_single(50 return self.app.wait_select_single(
51 "ZoomablePhotoComponent",51 "SingleMediaViewer",
52 ownerName="photoViewerDelegate",52 objectName="openedMedia0"
53 objectName="openedPhoto0"
54 )53 )
5554
56 def get_photos_list(self):55 def get_photos_list(self):
@@ -94,8 +93,8 @@
9493
95 def get_opened_photo(self):94 def get_opened_photo(self):
96 """Returns the first opened photo."""95 """Returns the first opened photo."""
97 return self.app.wait_select_single("ZoomablePhotoComponent",96 return self.app.wait_select_single("SingleMediaViewer",
98 objectName="openedPhoto0")97 objectName="openedMedia0")
9998
100 def get_crop_interactor(self):99 def get_crop_interactor(self):
101 """Returns the crop interactor."""100 """Returns the crop interactor."""
102101
=== modified file 'tests/autopilot/gallery_app/emulators/picker_screen.py'
--- tests/autopilot/gallery_app/emulators/picker_screen.py 2014-07-10 09:07:34 +0000
+++ tests/autopilot/gallery_app/emulators/picker_screen.py 2014-09-03 23:54:36 +0000
@@ -11,7 +11,7 @@
11class PickerScreen(toolkit_emulators.MainView):11class PickerScreen(toolkit_emulators.MainView):
1212
13 def pick_button(self):13 def pick_button(self):
14 return self.select_single("Button", objectName="pickButton")14 return self.select_single(objectName="pickButton_header_button")
1515
16 def get_photos_tab_button(self):16 def get_photos_tab_button(self):
17 """Returns the photos tab."""17 """Returns the photos tab."""
@@ -38,7 +38,7 @@
38 Return the Page object representing the photos38 Return the Page object representing the photos
39 """39 """
40 self.switch_to_tab('photosTab')40 self.switch_to_tab('photosTab')
41 return self.select_single(Page10, objectName='photosPage')41 return self.select_single(Page11, objectName='photosPage')
4242
43 def click_pick_button(self):43 def click_pick_button(self):
44 """Click on the pick button"""44 """Click on the pick button"""
@@ -51,7 +51,7 @@
51 self.click_pick_button()51 self.click_pick_button()
5252
5353
54class Page10(PickerScreen):54class Page11(PickerScreen):
55 """Class to represent photos page view from picker screen"""55 """Class to represent photos page view from picker screen"""
5656
57 def _get_named_photo_element(self, photo_name):57 def _get_named_photo_element(self, photo_name):
5858
=== modified file 'tests/autopilot/gallery_app/tests/__init__.py'
--- tests/autopilot/gallery_app/tests/__init__.py 2014-07-14 15:29:11 +0000
+++ tests/autopilot/gallery_app/tests/__init__.py 2014-09-03 23:54:36 +0000
@@ -162,8 +162,11 @@
162162
163 """ This is needed to wait for the application to start.163 """ This is needed to wait for the application to start.
164 In the testfarm, the application may take some time to show up."""164 In the testfarm, the application may take some time to show up."""
165 self.assertThat(self.gallery_utils.get_qml_view().visible,165 qml_view = self.gallery_utils.get_qml_view()
166 Eventually(Equals(True)))166 self.assertThat(qml_view.visible, Eventually(Equals(True)))
167 loading_screen = qml_view.select_single(
168 'QQuickLoader', objectName='loadingScreen')
169 loading_screen.visible.wait_for(False)
167 """FIXME somehow on the server gallery sometimes is not fully started170 """FIXME somehow on the server gallery sometimes is not fully started
168 for switching to the albums view. Therefore this hack of sleeping"""171 for switching to the albums view. Therefore this hack of sleeping"""
169 sleep(2)172 sleep(2)
@@ -262,13 +265,11 @@
262265
263 def open_album_at(self, position):266 def open_album_at(self, position):
264 album = self.album_view.get_album_at(position)267 album = self.album_view.get_album_at(position)
265 # workaround lp:1247698
266 self.main_view.close_toolbar()
267 self.click_item(album)268 self.click_item(album)
268 self.ensure_view_is_fully_open()269 self.ensure_view_is_fully_open()
269270
270 def open_first_album(self):271 def open_first_album(self):
271 self.open_album_at(-1)272 self.open_album_at(0)
272273
273 def ensure_view_is_fully_open(self):274 def ensure_view_is_fully_open(self):
274 view = self.album_view.get_album_view()275 view = self.album_view.get_album_view()
275276
=== modified file 'tests/autopilot/gallery_app/tests/test_album_editor.py'
--- tests/autopilot/gallery_app/tests/test_album_editor.py 2014-06-10 19:00:23 +0000
+++ tests/autopilot/gallery_app/tests/test_album_editor.py 2014-09-03 23:54:36 +0000
@@ -33,13 +33,10 @@
33 self.ARGS = []33 self.ARGS = []
34 super(TestAlbumEditor, self).setUp()34 super(TestAlbumEditor, self).setUp()
35 self.switch_to_albums_tab()35 self.switch_to_albums_tab()
36 self.main_view.close_toolbar()
37 self.edit_first_album()36 self.edit_first_album()
3837
39 def edit_first_album(self):38 def edit_first_album(self):
40 first_album = self.gallery_utils.get_first_album()39 first_album = self.gallery_utils.get_first_album()
41 # workaround lp:1247698
42 self.main_view.close_toolbar()
43 self.tap_item(first_album)40 self.tap_item(first_album)
44 edit_button = self.gallery_utils.get_edit_album_button()41 edit_button = self.gallery_utils.get_edit_album_button()
45 self.click_item(edit_button)42 self.click_item(edit_button)
@@ -58,8 +55,7 @@
58 text = "Ubuntu"55 text = "Ubuntu"
59 self.assertThat(subtitle_field.text, Eventually(Equals(text)))56 self.assertThat(subtitle_field.text, Eventually(Equals(text)))
6057
61 # workaround lp:124769858 sleep(5)
62 self.main_view.close_toolbar()
63 editor.click_title_field()59 editor.click_title_field()
64 self.assertThat(title_field.activeFocus, Eventually(Equals(True)))60 self.assertThat(title_field.activeFocus, Eventually(Equals(True)))
65 self.keyboard.press_and_release("Ctrl+a")61 self.keyboard.press_and_release("Ctrl+a")
@@ -81,38 +77,41 @@
81 """Tests adding a photo using the media selector"""77 """Tests adding a photo using the media selector"""
82 # first open, but cancel before adding a photo78 # first open, but cancel before adding a photo
83 editor = self.app.select_single(album_editor.AlbumEditor)79 editor = self.app.select_single(album_editor.AlbumEditor)
84 # workaround lp:1247698
85 self.main_view.close_toolbar()
86 editor.add_photos()80 editor.add_photos()
87 self.media_selector.ensure_fully_open()81 self.media_selector.ensure_fully_open()
8882
89 sleep(5)83 sleep(5)
90 self.main_view.get_toolbar().click_custom_button("cancelButton")84 self.main_view.get_header().click_custom_back_button()
85
91 editor.ensure_fully_closed()86 editor.ensure_fully_closed()
9287
93 self.main_view.close_toolbar()88 sleep(5)
94 self.open_first_album()89 self.open_first_album()
95 num_photos_start = self.album_view.number_of_photos()90 num_photos_start = self.album_view.number_of_photos()
96 self.assertThat(num_photos_start, Equals(1))91 self.assertThat(num_photos_start, Equals(1))
97 self.main_view.open_toolbar().click_button("backButton")92
93 # should click away of any photo to toggle header
94 photo = self.album_view.get_first_photo()
95 x, y, w, h = photo.globalRect
96 self.pointing_device.move(x + 40 , y + h + 40)
97 self.pointing_device.click()
98
99 self.main_view.get_header().click_custom_back_button()
98 self.album_view.ensure_album_view_fully_closed()100 self.album_view.ensure_album_view_fully_closed()
99101
100 # now open to add a photo102 # now open to add a photo
101 self.main_view.close_toolbar()
102 self.edit_first_album()103 self.edit_first_album()
103 editor = self.app.select_single(album_editor.AlbumEditor)104 editor = self.app.select_single(album_editor.AlbumEditor)
104 # workaround lp:1247698
105 self.main_view.close_toolbar()
106 editor.add_photos()105 editor.add_photos()
107 self.media_selector.ensure_fully_open()106 self.media_selector.ensure_fully_open()
108107
109 photo = self.media_selector.get_second_photo()108 photo = self.media_selector.get_second_photo()
110 self.click_item(photo)109 self.click_item(photo)
111 self.main_view.get_toolbar().click_custom_button("addButton")110 self.main_view.get_header().click_action_button("addButton")
112 editor = self.app.select_single(album_editor.AlbumEditor)111 editor = self.app.select_single(album_editor.AlbumEditor)
113 editor.ensure_fully_closed()112 editor.ensure_fully_closed()
114113
115 self.main_view.close_toolbar()114 self.album_view.ensure_album_view_fully_closed()
116 self.open_first_album()115 self.open_first_album()
117 num_photos = self.album_view.number_of_photos()116 num_photos = self.album_view.number_of_photos()
118 self.assertThat(num_photos, Equals(num_photos_start + 1))117 self.assertThat(num_photos, Equals(num_photos_start + 1))
@@ -124,11 +123,8 @@
124 self.assertThat(123 self.assertThat(
125 cover_image.source.endswith("album-cover-default-large.png"),124 cover_image.source.endswith("album-cover-default-large.png"),
126 Equals(True))125 Equals(True))
127 self.main_view.close_toolbar()
128126
129 # click somewhere rather at the bottom of the cover127 # click somewhere rather at the bottom of the cover
130 # workaround lp:1247698
131 self.main_view.close_toolbar()
132 x, y, w, h = cover_image.globalRect128 x, y, w, h = cover_image.globalRect
133 self.pointing_device.move(x + int(w / 2), y + h - int(h / 10))129 self.pointing_device.move(x + int(w / 2), y + h - int(h / 10))
134 self.pointing_device.click()130 self.pointing_device.click()
135131
=== modified file 'tests/autopilot/gallery_app/tests/test_album_view.py'
--- tests/autopilot/gallery_app/tests/test_album_view.py 2014-06-12 16:42:04 +0000
+++ tests/autopilot/gallery_app/tests/test_album_view.py 2014-09-03 23:54:36 +0000
@@ -48,24 +48,17 @@
48 self.switch_to_albums_tab()48 self.switch_to_albums_tab()
4949
50 def test_album_view_open_photo(self):50 def test_album_view_open_photo(self):
51 self.main_view.close_toolbar()
52 self.open_first_album()51 self.open_first_album()
53 self.main_view.close_toolbar()
54 photo = self.album_view.get_first_photo()52 photo = self.album_view.get_first_photo()
55 # workaround lp:1247698
56 self.main_view.close_toolbar()
57 self.click_item(photo)53 self.click_item(photo)
58 sleep(5)54 sleep(5)
59 photo_view = self.main_view.wait_select_single("PopupPhotoViewer")55 photo_view = self.main_view.wait_select_single("PopupPhotoViewer")
60 self.assertThat(photo_view.visible, Eventually(Equals(True)))56 self.assertThat(photo_view.visible, Eventually(Equals(True)))
6157
62 def test_album_view_flipping(self):58 def test_album_view_flipping(self):
63 self.main_view.close_toolbar()
64
65 # For some reason here the album at position 0 in the autopilot list is59 # For some reason here the album at position 0 in the autopilot list is
66 # actually the second album, they seem to be returned in reverse order.60 # actually the second album, they seem to be returned in reverse order.
67 self.open_album_at(0)61 self.open_album_at(1)
68 self.main_view.close_toolbar()
6962
70 spread = self.album_view.get_spread_view()63 spread = self.album_view.get_spread_view()
7164
@@ -84,35 +77,39 @@
84 self.assertThat(spread.viewingPage, Eventually(GreaterThan(1)))77 self.assertThat(spread.viewingPage, Eventually(GreaterThan(1)))
8578
86 def test_add_photo(self):79 def test_add_photo(self):
87 self.main_view.close_toolbar()
88 self.open_first_album()80 self.open_first_album()
89 num_photos_start = self.album_view.number_of_photos()81 num_photos_start = self.album_view.number_of_photos()
90 self.assertThat(num_photos_start, Equals(1))82 self.assertThat(num_photos_start, Equals(1))
9183
84 # should click away of any photo to toggle header
85 photo = self.album_view.get_first_photo()
86 x, y, w, h = photo.globalRect
87 self.pointing_device.move(x + 40 , y + h + 40)
88 self.pointing_device.click()
89
92 # open media selector but cancel90 # open media selector but cancel
93 self.main_view.open_toolbar().click_button("addButton")91 self.main_view.get_header().click_action_button("addButton")
94 self.media_selector.ensure_fully_open()92 self.media_selector.ensure_fully_open()
9593
96 self.main_view.get_toolbar().click_custom_button("cancelButton")94 self.main_view.get_header().click_custom_back_button()
97 sleep(1)95 sleep(1)
9896
99 num_photos = self.album_view.number_of_photos()97 num_photos = self.album_view.number_of_photos()
100 self.assertThat(num_photos, Equals(num_photos_start))98 self.assertThat(num_photos, Equals(num_photos_start))
10199
102 # open media selector and add a photo100 # open media selector and add a photo
103 self.main_view.open_toolbar().click_button("addButton")101 self.main_view.get_header().click_action_button("addButton")
104 self.media_selector.ensure_fully_open()102 self.media_selector.ensure_fully_open()
105103
106 photo = self.media_selector.get_second_photo()104 photo = self.media_selector.get_second_photo()
107 self.click_item(photo)105 self.click_item(photo)
108 self.main_view.get_toolbar().click_custom_button("addButton")106 self.main_view.get_header().click_action_button("addButton")
109107
110 self.assertThat(108 self.assertThat(
111 lambda: self.album_view.number_of_photos(),109 lambda: self.album_view.number_of_photos(),
112 Eventually(Equals(num_photos_start + 1)))110 Eventually(Equals(num_photos_start + 1)))
113111
114 def test_remove_photo_from_album(self):112 def test_remove_photo_from_album(self):
115 self.main_view.close_toolbar()
116 self.open_first_album()113 self.open_first_album()
117 num_photos_start = self.album_view.number_of_photos()114 num_photos_start = self.album_view.number_of_photos()
118 self.assertThat(num_photos_start, Equals(1))115 self.assertThat(num_photos_start, Equals(1))
@@ -125,7 +122,7 @@
125 photo_view = self.album_view.get_album_photo_view()122 photo_view = self.album_view.get_album_photo_view()
126 self.assertThat(photo_view.visible, Eventually(Equals(True)))123 self.assertThat(photo_view.visible, Eventually(Equals(True)))
127124
128 self.main_view.open_toolbar().click_button("deleteButton")125 self.main_view.get_header().click_action_button("deleteButton")
129 self.album_view.click_remove_from_album_remove_button()126 self.album_view.click_remove_from_album_remove_button()
130127
131 self.assertThat(lambda: self.album_view.number_of_photos(),128 self.assertThat(lambda: self.album_view.number_of_photos(),
@@ -135,7 +132,6 @@
135 Eventually(Equals(True)))132 Eventually(Equals(True)))
136133
137 def test_remove_photo_from_album_and_delete(self):134 def test_remove_photo_from_album_and_delete(self):
138 self.main_view.close_toolbar()
139 self.open_first_album()135 self.open_first_album()
140 num_photos_start = self.album_view.number_of_photos()136 num_photos_start = self.album_view.number_of_photos()
141 self.assertThat(num_photos_start, Equals(1))137 self.assertThat(num_photos_start, Equals(1))
@@ -148,7 +144,7 @@
148 photo_view = self.album_view.get_album_photo_view()144 photo_view = self.album_view.get_album_photo_view()
149 self.assertThat(photo_view.visible, Eventually(Equals(True)))145 self.assertThat(photo_view.visible, Eventually(Equals(True)))
150146
151 self.main_view.open_toolbar().click_button("deleteButton")147 self.main_view.get_header().click_action_button("deleteButton")
152 self.album_view.click_remove_from_album_delete_button()148 self.album_view.click_remove_from_album_delete_button()
153149
154 self.assertThat(lambda: self.album_view.number_of_photos(),150 self.assertThat(lambda: self.album_view.number_of_photos(),
@@ -158,7 +154,6 @@
158 Eventually(Equals(False)))154 Eventually(Equals(False)))
159155
160 def test_cancel_remove_photo_from_album(self):156 def test_cancel_remove_photo_from_album(self):
161 self.main_view.close_toolbar()
162 self.open_first_album()157 self.open_first_album()
163 num_photos_start = self.album_view.number_of_photos()158 num_photos_start = self.album_view.number_of_photos()
164 self.assertThat(num_photos_start, Equals(1))159 self.assertThat(num_photos_start, Equals(1))
@@ -171,10 +166,10 @@
171 photo_view = self.album_view.get_album_photo_view()166 photo_view = self.album_view.get_album_photo_view()
172 self.assertThat(photo_view.visible, Eventually(Equals(True)))167 self.assertThat(photo_view.visible, Eventually(Equals(True)))
173168
174 self.main_view.open_toolbar().click_button("deleteButton")169 self.main_view.get_header().click_action_button("deleteButton")
175 self.album_view.click_remove_from_album_cancel_button()170 self.album_view.click_remove_from_album_cancel_button()
176171
177 self.main_view.open_toolbar().click_button("backButton")172 self.main_view.get_header().click_custom_back_button()
178173
179 self.assertThat(lambda: self.album_view.number_of_photos(),174 self.assertThat(lambda: self.album_view.number_of_photos(),
180 Eventually(Equals(num_photos_start)))175 Eventually(Equals(num_photos_start)))
@@ -183,28 +178,24 @@
183 Eventually(Equals(True)))178 Eventually(Equals(True)))
184179
185 def test_add_photo_to_new_album(self):180 def test_add_photo_to_new_album(self):
186 self.main_view.open_toolbar().click_button("addButton")181 self.main_view.get_header().click_action_button("addButton")
187 self.ui_update()182 self.ui_update()
188183
189 editor = self.app.select_single(album_editor.AlbumEditor)184 editor = self.app.select_single(album_editor.AlbumEditor)
190 editor.ensure_fully_open()185 editor.ensure_fully_open()
191 self.main_view.close_toolbar()
192 editor.close()186 editor.close()
193187
194 self.open_first_album()188 self.open_first_album()
195 self.main_view.close_toolbar()
196 num_photos_start = self.album_view.number_of_photos()189 num_photos_start = self.album_view.number_of_photos()
197 self.assertThat(num_photos_start, Equals(0))190 self.assertThat(num_photos_start, Equals(0))
198191
199 plus = self.album_view.get_plus_icon_empty_album()192 plus = self.album_view.get_plus_icon_empty_album()
200 # workaround lp:1247698
201 self.main_view.close_toolbar()
202 self.click_item(plus)193 self.click_item(plus)
203 self.media_selector.ensure_fully_open()194 self.media_selector.ensure_fully_open()
204195
205 photo = self.media_selector.get_second_photo()196 photo = self.media_selector.get_second_photo()
206 self.click_item(photo)197 self.click_item(photo)
207 self.main_view.get_toolbar().click_custom_button("addButton")198 self.main_view.get_header().click_action_button("addButton")
208199
209 self.assertThat(200 self.assertThat(
210 lambda: self.album_view.number_of_photos(),201 lambda: self.album_view.number_of_photos(),
211202
=== modified file 'tests/autopilot/gallery_app/tests/test_albums_view.py'
--- tests/autopilot/gallery_app/tests/test_albums_view.py 2014-05-20 15:19:35 +0000
+++ tests/autopilot/gallery_app/tests/test_albums_view.py 2014-09-03 23:54:36 +0000
@@ -11,6 +11,7 @@
11from testtools.matchers import Equals11from testtools.matchers import Equals
12from autopilot.matchers import Eventually12from autopilot.matchers import Eventually
13from autopilot.platform import model13from autopilot.platform import model
14from autopilot.introspection.dbus import StateNotFoundError
1415
15from gallery_app.tests import GalleryTestCase16from gallery_app.tests import GalleryTestCase
16from gallery_app.emulators.albums_view import AlbumsView17from gallery_app.emulators.albums_view import AlbumsView
@@ -47,10 +48,19 @@
4748
48 super(TestAlbumsView, self).tearDown()49 super(TestAlbumsView, self).tearDown()
4950
51 def check_header_button_exist(self, button):
52 header = self.main_view.get_header()
53 buttonName = button + "_header_button"
54 try:
55 header.select_single(objectName=buttonName)
56 except StateNotFoundError:
57 return False
58 return True
59
50 def test_add_album(self):60 def test_add_album(self):
51 """Add one album, and checks if the number of albums went up by one"""61 """Add one album, and checks if the number of albums went up by one"""
52 albums = self.albums_view.number_of_albums_in_albums_view()62 albums = self.albums_view.number_of_albums_in_albums_view()
53 self.main_view.open_toolbar().click_button("addButton")63 self.main_view.get_header().click_action_button("addButton")
54 self.assertThat(64 self.assertThat(
55 lambda: self.albums_view.number_of_albums_in_albums_view(),65 lambda: self.albums_view.number_of_albums_in_albums_view(),
56 Eventually(Equals(albums+1))66 Eventually(Equals(albums+1))
@@ -61,10 +71,10 @@
61 not change71 not change
62 """72 """
63 albums = self.albums_view.number_of_albums_in_albums_view()73 albums = self.albums_view.number_of_albums_in_albums_view()
64 self.main_view.open_toolbar().click_button("addButton")74 self.main_view.get_header().click_action_button("addButton")
65 editor = self.app.select_single(album_editor.AlbumEditor)75 editor = self.app.select_single(album_editor.AlbumEditor)
66 editor.ensure_fully_open()76 editor.ensure_fully_open()
67 self.main_view.get_toolbar().click_custom_button("cancelButton")77 self.main_view.get_header().click_custom_back_button()
68 self.assertThat(78 self.assertThat(
69 lambda: self.albums_view.number_of_albums_in_albums_view(),79 lambda: self.albums_view.number_of_albums_in_albums_view(),
70 Eventually(Equals(albums))80 Eventually(Equals(albums))
@@ -72,13 +82,8 @@
7282
73 # Check if Camera Button is not visible at Desktop mode83 # Check if Camera Button is not visible at Desktop mode
74 def test_camera_button_visible(self):84 def test_camera_button_visible(self):
75 self.main_view.open_toolbar()85 cameraButtonVisible = self.check_header_button_exist("cameraButton")
76 toolbar = self.main_view.get_toolbar()
77 cameraButton = toolbar.select_single(
78 "ActionItem",
79 objectName="cameraButton"
80 )
81 if model() == "Desktop":86 if model() == "Desktop":
82 self.assertThat(cameraButton.visible, Equals(False))87 self.assertThat(cameraButtonVisible, Equals(False))
83 else:88 else:
84 self.assertThat(cameraButton.visible, Equals(True))89 self.assertThat(cameraButtonVisible, Equals(True))
8590
=== modified file 'tests/autopilot/gallery_app/tests/test_events_view.py'
--- tests/autopilot/gallery_app/tests/test_events_view.py 2014-06-16 13:46:21 +0000
+++ tests/autopilot/gallery_app/tests/test_events_view.py 2014-09-03 23:54:36 +0000
@@ -11,6 +11,7 @@
11from testtools.matchers import Equals, NotEquals, Is, GreaterThan11from testtools.matchers import Equals, NotEquals, Is, GreaterThan
12from autopilot.matchers import Eventually12from autopilot.matchers import Eventually
13from autopilot.platform import model13from autopilot.platform import model
14from autopilot.introspection.dbus import StateNotFoundError
1415
15from gallery_app.tests import GalleryTestCase16from gallery_app.tests import GalleryTestCase
16from gallery_app.emulators.events_view import EventsView17from gallery_app.emulators.events_view import EventsView
@@ -59,7 +60,16 @@
59 objectName="organicEventView")60 objectName="organicEventView")
6061
61 def enable_select_mode(self):62 def enable_select_mode(self):
62 self.main_view.open_toolbar().click_button("selectButton")63 self.main_view.get_header().click_action_button("selectButton")
64
65 def check_header_button_exist(self, button):
66 header = self.main_view.get_header()
67 buttonName = button + "_header_button"
68 try:
69 header.select_single(objectName=buttonName)
70 except StateNotFoundError:
71 return False
72 return True
6373
64 def test_select_button_cancel(self):74 def test_select_button_cancel(self):
65 """Clicking the cancel button after clicking the select button must75 """Clicking the cancel button after clicking the select button must
@@ -70,10 +80,8 @@
70 self.enable_select_mode()80 self.enable_select_mode()
71 self.assertTrue(events_view.inSelectionMode)81 self.assertTrue(events_view.inSelectionMode)
7282
73 self.main_view.get_toolbar().click_custom_button("cancelButton")83 self.main_view.get_header().click_custom_back_button()
7484
75 toolbar = self.main_view.get_toolbar()
76 self.assertThat(toolbar.opened, Eventually(Equals(False)))
77 self.assertFalse(events_view.inSelectionMode)85 self.assertFalse(events_view.inSelectionMode)
7886
79 def test_delete_a_photo(self):87 def test_delete_a_photo(self):
@@ -83,7 +91,7 @@
8391
84 self.enable_select_mode()92 self.enable_select_mode()
85 self.events_view.click_photo(self.sample_file)93 self.events_view.click_photo(self.sample_file)
86 self.main_view.open_toolbar().click_button("deleteButton")94 self.main_view.get_header().click_action_button("deleteButton")
87 self.assertThat(self.gallery_utils.delete_dialog_shown,95 self.assertThat(self.gallery_utils.delete_dialog_shown,
88 Eventually(Is(True)))96 Eventually(Is(True)))
8997
@@ -94,7 +102,7 @@
94 self.assertThat(lambda: exists(self.sample_file),102 self.assertThat(lambda: exists(self.sample_file),
95 Eventually(Equals(True)))103 Eventually(Equals(True)))
96104
97 self.main_view.open_toolbar().click_button("deleteButton")105 self.main_view.get_header().click_action_button("deleteButton")
98 self.assertThat(self.gallery_utils.delete_dialog_shown,106 self.assertThat(self.gallery_utils.delete_dialog_shown,
99 Eventually(Is(True)))107 Eventually(Is(True)))
100108
@@ -123,13 +131,8 @@
123131
124 # Check if Camera Button is not visible at Desktop mode132 # Check if Camera Button is not visible at Desktop mode
125 def test_camera_button_visible(self):133 def test_camera_button_visible(self):
126 self.main_view.open_toolbar()134 cameraButtonVisible = self.check_header_button_exist("cameraButton")
127 toolbar = self.main_view.get_toolbar()
128 cameraButton = toolbar.select_single(
129 "ActionItem",
130 objectName="cameraButton"
131 )
132 if model() == "Desktop":135 if model() == "Desktop":
133 self.assertThat(cameraButton.visible, Equals(False))136 self.assertThat(cameraButtonVisible, Equals(False))
134 else:137 else:
135 self.assertThat(cameraButton.visible, Equals(True))138 self.assertThat(cameraButtonVisible, Equals(True))
136139
=== modified file 'tests/autopilot/gallery_app/tests/test_photo_viewer.py'
--- tests/autopilot/gallery_app/tests/test_photo_viewer.py 2014-07-02 22:11:12 +0000
+++ tests/autopilot/gallery_app/tests/test_photo_viewer.py 2014-09-03 23:54:36 +0000
@@ -41,7 +41,8 @@
41 super(TestPhotoViewerBase, self).setUp()41 super(TestPhotoViewerBase, self).setUp()
42 self.main_view.switch_to_tab("eventsTab")42 self.main_view.switch_to_tab("eventsTab")
43 self.open_first_photo()43 self.open_first_photo()
44 self.main_view.open_toolbar()44 # Need to click on the photo to toggle header
45 self.pointing_device.click()
4546
46 def open_first_photo(self):47 def open_first_photo(self):
47 self.assertThat(48 self.assertThat(
@@ -49,10 +50,6 @@
49 Eventually(GreaterThan(0))50 Eventually(GreaterThan(0))
50 )51 )
5152
52 # workaround lp:1247698
53 # toolbar needs to be gone to click on an image.
54 self.main_view.close_toolbar()
55
56 self.events_view.click_photo(self.sample_file)53 self.events_view.click_photo(self.sample_file)
5754
58 photo_viewer_loader = self.photo_viewer.get_main_photo_viewer_loader()55 photo_viewer_loader = self.photo_viewer.get_main_photo_viewer_loader()
@@ -107,7 +104,7 @@
107104
108 def test_nav_bar_back_button(self):105 def test_nav_bar_back_button(self):
109 """Clicking the back button must close the photo."""106 """Clicking the back button must close the photo."""
110 self.main_view.open_toolbar().click_button("backButton")107 self.main_view.get_header().click_custom_back_button()
111 photo_viewer = self.photo_viewer.get_main_photo_viewer()108 photo_viewer = self.photo_viewer.get_main_photo_viewer()
112 self.assertThat(photo_viewer.visible, Eventually(Equals(False)))109 self.assertThat(photo_viewer.visible, Eventually(Equals(False)))
113110
@@ -115,7 +112,7 @@
115 def test_share_button(self):112 def test_share_button(self):
116 """Clicking the share button must show the ContentPeerPicker."""113 """Clicking the share button must show the ContentPeerPicker."""
117 photo_viewer = self.photo_viewer.get_main_photo_viewer()114 photo_viewer = self.photo_viewer.get_main_photo_viewer()
118 self.main_view.open_toolbar().click_button("shareButton")115 self.main_view.get_header().click_action_button("shareButton")
119 share_picker = self.photo_viewer.get_share_peer_picker()116 share_picker = self.photo_viewer.get_share_peer_picker()
120 self.assertThat(share_picker.visible, Eventually(Equals(True)))117 self.assertThat(share_picker.visible, Eventually(Equals(True)))
121 cancel_button = self.photo_viewer.get_content_peer_picker_cancel_button()118 cancel_button = self.photo_viewer.get_content_peer_picker_cancel_button()
@@ -123,7 +120,7 @@
123 self.assertThat(share_picker.visible, Eventually(Equals(False)))120 self.assertThat(share_picker.visible, Eventually(Equals(False)))
124121
125 def delete_one_picture(self):122 def delete_one_picture(self):
126 self.main_view.open_toolbar().click_button("deleteButton")123 self.main_view.get_header().click_action_button("deleteButton")
127 self.get_delete_dialog()124 self.get_delete_dialog()
128 delete_item = self.photo_viewer.get_delete_popover_delete_item()125 delete_item = self.photo_viewer.get_delete_popover_delete_item()
129 self.click_item(delete_item)126 self.click_item(delete_item)
@@ -131,7 +128,7 @@
131128
132 def test_photo_delete_works(self):129 def test_photo_delete_works(self):
133 """Clicking the trash button must show the delete dialog."""130 """Clicking the trash button must show the delete dialog."""
134 self.main_view.open_toolbar().click_button("deleteButton")131 self.main_view.get_header().click_action_button("deleteButton")
135 self.get_delete_dialog()132 self.get_delete_dialog()
136133
137 photo_viewer = self.photo_viewer.get_main_photo_viewer()134 photo_viewer = self.photo_viewer.get_main_photo_viewer()
@@ -157,7 +154,7 @@
157154
158 def test_nav_bar_album_picker_button(self):155 def test_nav_bar_album_picker_button(self):
159 """Clicking the album picker must show the picker dialog."""156 """Clicking the album picker must show the picker dialog."""
160 self.main_view.open_toolbar().click_button("addButton")157 self.main_view.get_header().click_action_button("addButton")
161 album_picker = self.photo_viewer.get_popup_album_picker()158 album_picker = self.photo_viewer.get_popup_album_picker()
162 self.assertThat(album_picker.visible, Eventually(Equals(True)))159 self.assertThat(album_picker.visible, Eventually(Equals(True)))
163160
@@ -169,19 +166,11 @@
169 self.pointing_device.click()166 self.pointing_device.click()
170 self.pointing_device.click()167 self.pointing_device.click()
171168
172 self.assertThat(
173 opened_photo.isZoomAnimationInProgress,
174 Eventually(Equals(False))
175 )
176 self.assertThat(opened_photo.fullyZoomed, Eventually(Equals(True)))169 self.assertThat(opened_photo.fullyZoomed, Eventually(Equals(True)))
177170
178 self.pointing_device.click()171 self.pointing_device.click()
179 self.pointing_device.click()172 self.pointing_device.click()
180173
181 self.assertThat(
182 opened_photo.isZoomAnimationInProgress,
183 Eventually(Equals(False))
184 )
185 self.assertThat(opened_photo.fullyUnzoomed, Eventually(Equals(True)))174 self.assertThat(opened_photo.fullyUnzoomed, Eventually(Equals(True)))
186175
187 def test_swipe_change_image(self):176 def test_swipe_change_image(self):
@@ -219,7 +208,7 @@
219 self.media_view = self.app.select_single(MediaViewer)208 self.media_view = self.app.select_single(MediaViewer)
220209
221 def click_edit_button(self):210 def click_edit_button(self):
222 self.main_view.open_toolbar().click_button("editButton")211 self.main_view.get_header().click_action_button("editButton")
223 edit_dialog = self.photo_viewer.get_photo_edit_dialog()212 edit_dialog = self.photo_viewer.get_photo_edit_dialog()
224 self.assertThat(edit_dialog.visible, (Eventually(Equals(True))))213 self.assertThat(edit_dialog.visible, (Eventually(Equals(True))))
225 self.assertThat(edit_dialog.opacity, (Eventually(Equals(1))))214 self.assertThat(edit_dialog.opacity, (Eventually(Equals(1))))
@@ -281,7 +270,6 @@
281 self.assertThat(lambda: is_landscape(),270 self.assertThat(lambda: is_landscape(),
282 Eventually(Equals(False)))271 Eventually(Equals(False)))
283272
284 self.main_view.open_toolbar()
285 self.click_edit_button()273 self.click_edit_button()
286 self.photo_viewer.click_undo_item()274 self.photo_viewer.click_undo_item()
287 self.media_view.ensure_spinner_not_running()275 self.media_view.ensure_spinner_not_running()
@@ -291,7 +279,6 @@
291 self.assertThat(lambda: is_landscape(),279 self.assertThat(lambda: is_landscape(),
292 Eventually(Equals(True)))280 Eventually(Equals(True)))
293281
294 self.main_view.open_toolbar()
295 self.click_edit_button()282 self.click_edit_button()
296 self.photo_viewer.click_redo_item()283 self.photo_viewer.click_redo_item()
297 self.media_view.ensure_spinner_not_running()284 self.media_view.ensure_spinner_not_running()
@@ -301,10 +288,8 @@
301 is_landscape = opened_photo.paintedWidth > opened_photo.paintedHeight288 is_landscape = opened_photo.paintedWidth > opened_photo.paintedHeight
302 self.assertThat(is_landscape, Equals(False))289 self.assertThat(is_landscape, Equals(False))
303290
304 self.main_view.open_toolbar()
305 self.click_edit_button()291 self.click_edit_button()
306 self.photo_viewer.click_rotate_item()292 self.photo_viewer.click_rotate_item()
307 self.main_view.open_toolbar()
308 self.click_edit_button()293 self.click_edit_button()
309 self.photo_viewer.click_revert_item()294 self.photo_viewer.click_revert_item()
310295
311296
=== modified file 'tests/autopilot/gallery_app/tests/test_photos_view.py'
--- tests/autopilot/gallery_app/tests/test_photos_view.py 2014-05-20 20:59:52 +0000
+++ tests/autopilot/gallery_app/tests/test_photos_view.py 2014-09-03 23:54:36 +0000
@@ -12,6 +12,7 @@
12from testtools import skipUnless12from testtools import skipUnless
13from autopilot.matchers import Eventually13from autopilot.matchers import Eventually
14from autopilot.platform import model14from autopilot.platform import model
15from autopilot.introspection.dbus import StateNotFoundError
1516
16from gallery_app.tests import GalleryTestCase17from gallery_app.tests import GalleryTestCase
17from gallery_app.emulators.photos_view import PhotosView18from gallery_app.emulators.photos_view import PhotosView
@@ -56,8 +57,16 @@
56 photo = self.photos_view.get_first_photo_in_photos_view()57 photo = self.photos_view.get_first_photo_in_photos_view()
57 self.click_item(photo)58 self.click_item(photo)
5859
60 def check_header_button_exist(self, button):
61 header = self.main_view.get_header()
62 buttonName = button + "_header_button"
63 try:
64 header.select_single(objectName=buttonName)
65 except StateNotFoundError:
66 return False
67 return True
68
59 def test_open_photo(self):69 def test_open_photo(self):
60 self.main_view.close_toolbar()
61 self.click_first_photo()70 self.click_first_photo()
62 sleep(5)71 sleep(5)
63 photo_viewer = self.photos_view.get_main_photo_viewer()72 photo_viewer = self.photos_view.get_main_photo_viewer()
@@ -69,13 +78,11 @@
69 photos_overview = self.app.select_single("PhotosOverview")78 photos_overview = self.app.select_single("PhotosOverview")
70 self.assertFalse(photos_overview.inSelectionMode)79 self.assertFalse(photos_overview.inSelectionMode)
7180
72 self.main_view.open_toolbar().click_button("selectButton")81 self.main_view.get_header().click_action_button("selectButton")
73 self.assertTrue(photos_overview.inSelectionMode)82 self.assertTrue(photos_overview.inSelectionMode)
7483
75 self.main_view.open_toolbar().click_custom_button("cancelButton")84 self.main_view.get_header().click_custom_back_button()
7685
77 toolbar = self.main_view.get_toolbar()
78 self.assertThat(toolbar.opened, Eventually(Equals(False)))
79 self.assertFalse(photos_overview.inSelectionMode)86 self.assertFalse(photos_overview.inSelectionMode)
8087
81 first_photo = self.photos_view.get_first_photo_in_photos_view()88 first_photo = self.photos_view.get_first_photo_in_photos_view()
@@ -84,9 +91,9 @@
8491
85 def test_delete_photo_dialog_appears(self):92 def test_delete_photo_dialog_appears(self):
86 """Selecting a photo must make the delete button clickable."""93 """Selecting a photo must make the delete button clickable."""
87 self.main_view.open_toolbar().click_button("selectButton")94 self.main_view.get_header().click_action_button("selectButton")
88 self.click_first_photo()95 self.click_first_photo()
89 self.main_view.open_toolbar().click_button("deleteButton")96 self.main_view.get_header().click_action_button("deleteButton")
9097
91 self.assertThat(self.gallery_utils.delete_dialog_shown,98 self.assertThat(self.gallery_utils.delete_dialog_shown,
92 Eventually(Is(True)))99 Eventually(Is(True)))
@@ -99,15 +106,13 @@
99 def test_delete_a_photo(self):106 def test_delete_a_photo(self):
100 """Must be able to select a photo and use the dialog to delete it."""107 """Must be able to select a photo and use the dialog to delete it."""
101 number_of_photos = self.photos_view.number_of_photos()108 number_of_photos = self.photos_view.number_of_photos()
102 self.main_view.open_toolbar().click_button("selectButton")109 self.main_view.get_header().click_action_button("selectButton")
103 self.click_first_photo()110 self.click_first_photo()
104 self.main_view.open_toolbar().click_button("deleteButton")111 self.main_view.get_header().click_action_button("deleteButton")
105112
106 self.assertThat(self.gallery_utils.delete_dialog_shown,113 self.assertThat(self.gallery_utils.delete_dialog_shown,
107 Eventually(Is(True)))114 Eventually(Is(True)))
108115
109 self.main_view.open_toolbar().click_button("deleteButton")
110
111 delete_item = self.photos_view.get_delete_dialog_delete_button()116 delete_item = self.photos_view.get_delete_dialog_delete_button()
112 self.click_item(delete_item)117 self.click_item(delete_item)
113 self.assertThat(118 self.assertThat(
@@ -157,13 +162,8 @@
157162
158 # Check if Camera Button is not visible at Desktop mode163 # Check if Camera Button is not visible at Desktop mode
159 def test_camera_button_visible(self):164 def test_camera_button_visible(self):
160 self.main_view.open_toolbar()165 cameraButtonVisible = self.check_header_button_exist("cameraButton")
161 toolbar = self.main_view.get_toolbar()
162 cameraButton = toolbar.select_single(
163 "ActionItem",
164 objectName="cameraButton"
165 )
166 if model() == "Desktop":166 if model() == "Desktop":
167 self.assertThat(cameraButton.visible, Equals(False))167 self.assertThat(cameraButtonVisible, Equals(False))
168 else:168 else:
169 self.assertThat(cameraButton.visible, Equals(True))169 self.assertThat(cameraButtonVisible, Equals(True))

Subscribers

People subscribed via source and target branches