Changeset View
Changeset View
Standalone View
Standalone View
qmlUiKirigami/ImageViewer.qml
Show All 25 Lines | |||||
26 | import QtQuick.Controls 2.0 as Controls | 26 | import QtQuick.Controls 2.0 as Controls | ||
27 | import org.kde.kirigami 2.0 as Kirigami | 27 | import org.kde.kirigami 2.0 as Kirigami | ||
28 | import org.kde.koko 0.1 as Koko | 28 | import org.kde.koko 0.1 as Koko | ||
29 | import org.kde.kquickcontrolsaddons 2.0 as KQA | 29 | import org.kde.kquickcontrolsaddons 2.0 as KQA | ||
30 | 30 | | |||
31 | Kirigami.Page { | 31 | Kirigami.Page { | ||
32 | id: root | 32 | id: root | ||
33 | 33 | | |||
34 | title: i18n("Details") | ||||
34 | property alias sourceModel: imagesListModel.sourceModel | 35 | property alias sourceModel: imagesListModel.sourceModel | ||
35 | property int indexValue | 36 | property int indexValue | ||
36 | 37 | | |||
37 | property int imageWidth | 38 | property int imageWidth | ||
38 | property int imageHeight | 39 | property int imageHeight | ||
39 | 40 | | |||
40 | leftPadding: 0 | 41 | leftPadding: 0 | ||
41 | rightPadding: 0 | 42 | rightPadding: 0 | ||
42 | 43 | | |||
43 | KQA.MimeDatabase { | 44 | KQA.MimeDatabase { | ||
44 | id: mimeDB | 45 | id: mimeDB | ||
45 | } | 46 | } | ||
46 | 47 | | |||
47 | Kirigami.Action { | 48 | actions { | ||
49 | left: Kirigami.Action { | ||||
48 | id: backAction | 50 | id: backAction | ||
49 | iconName: "view-close" | 51 | iconName: "view-close" | ||
50 | tooltip: i18n("Close Image") | 52 | tooltip: i18n("Close Image") | ||
51 | onTriggered: root.state = "closed" | 53 | onTriggered: root.close(); | ||
52 | } | 54 | } | ||
53 | 55 | main: Kirigami.Action { | |||
54 | Kirigami.Action { | | |||
55 | id: shareAction | 56 | id: shareAction | ||
56 | iconName: "document-share" | 57 | iconName: "document-share" | ||
57 | tooltip: i18n("Share Image") | 58 | tooltip: i18n("Share Image") | ||
58 | onTriggered: { | 59 | onTriggered: { | ||
59 | shareDialog.sheetOpen = true | 60 | shareDialog.open(); | ||
60 | shareDialog.inputData = { | 61 | shareDialog.inputData = { | ||
61 | "urls": [ listView.currentItem.currentImageSource.toString() ], | 62 | "urls": [ listView.currentItem.currentImageSource.toString() ], | ||
62 | "mimeType": mimeDB.mimeTypeForUrl( listView.currentItem.currentImageSource).name | 63 | "mimeType": mimeDB.mimeTypeForUrl( listView.currentItem.currentImageSource).name | ||
63 | } | 64 | } | ||
64 | } | 65 | } | ||
65 | } | 66 | } | ||
66 | 67 | right: Kirigami.Action { | |||
67 | Kirigami.Action { | | |||
68 | id: editAction | 68 | id: editAction | ||
69 | iconName: "editimage" | 69 | iconName: "editimage" | ||
70 | tooltip: i18n("Edit Image") | 70 | tooltip: i18n("Edit Image") | ||
71 | } | 71 | } | ||
72 | | ||||
73 | mainAction: root.state == "open" ? shareAction : null | | |||
74 | leftAction: root.state == "open" ? backAction : null | | |||
75 | rightAction: root.state == "open" ? editAction : null | | |||
76 | | ||||
77 | states: [ | | |||
78 | State { | | |||
79 | name: "open" | | |||
80 | PropertyChanges { | | |||
81 | target: root | | |||
82 | visible: true | | |||
83 | } | | |||
84 | PropertyChanges { | | |||
85 | target: root | | |||
86 | opacity: 1 | | |||
87 | } | | |||
88 | PropertyChanges { | | |||
89 | target: root | | |||
90 | focus: true | | |||
91 | } | | |||
92 | PropertyChanges { | | |||
93 | target: listView | | |||
94 | focus: true | | |||
95 | } | | |||
96 | PropertyChanges { | | |||
97 | target: applicationWindow() | | |||
98 | visibility: Window.Windowed | | |||
99 | } | | |||
100 | }, | | |||
101 | State { | | |||
102 | name: "closed" | | |||
103 | PropertyChanges { | | |||
104 | target: root | | |||
105 | opacity: 0 | | |||
106 | } | | |||
107 | PropertyChanges { | | |||
108 | target: root | | |||
109 | visible: false | | |||
110 | } | | |||
111 | PropertyChanges { | | |||
112 | target: shareDialog | | |||
113 | sheetOpen: false | | |||
114 | } | | |||
115 | }, | | |||
116 | State { | | |||
117 | name: "fullscreen" | | |||
118 | PropertyChanges { | | |||
119 | target: root | | |||
120 | focus: true | | |||
121 | } | | |||
122 | PropertyChanges { | | |||
123 | target: listView | | |||
124 | focus: true | | |||
125 | } | | |||
126 | PropertyChanges { | | |||
127 | target: applicationWindow() | | |||
128 | visibility: Window.FullScreen | | |||
129 | } | | |||
130 | } | | |||
131 | ] | | |||
132 | | ||||
133 | transitions: [ | | |||
134 | Transition { | | |||
135 | from: "*" | | |||
136 | to: "closed" | | |||
137 | SequentialAnimation { | | |||
138 | OpacityAnimator { | | |||
139 | target: root | | |||
140 | duration: Kirigami.Units.longDuration | | |||
141 | easing.type: Easing.InQuad | | |||
142 | } | | |||
143 | PropertyAnimation { | | |||
144 | target: root | | |||
145 | property: "visible" | | |||
146 | duration: Kirigami.Units.longDuration | | |||
147 | } | | |||
148 | ScriptAction { | | |||
149 | script: applicationWindow().pageStack.forceActiveFocus(); | | |||
150 | } | | |||
151 | } | | |||
152 | }, | | |||
153 | Transition { | | |||
154 | from: "closed" | | |||
155 | to: "open" | | |||
156 | OpacityAnimator { | | |||
157 | target: root | | |||
158 | duration: Kirigami.Units.longDuration | | |||
159 | easing.type: Easing.OutQuad | | |||
160 | } | 72 | } | ||
73 | | ||||
74 | //FIXME: HACK | ||||
75 | property bool wasDrawerOpen | ||||
76 | Component.onCompleted: { | ||||
77 | applicationWindow().controlsVisible = false; | ||||
78 | listView.forceActiveFocus(); | ||||
79 | applicationWindow().header.visible = false; | ||||
80 | applicationWindow().footer.visible = false; | ||||
81 | wasDrawerOpen = applicationWindow().globalDrawer.visible; | ||||
82 | applicationWindow().globalDrawer.visible = false; | ||||
83 | applicationWindow().globalDrawer.enabled = false; | ||||
84 | } | ||||
85 | function close() { | ||||
86 | applicationWindow().controlsVisible = true; | ||||
87 | applicationWindow().header.visible = true; | ||||
88 | applicationWindow().footer.visible = true; | ||||
89 | applicationWindow().globalDrawer.visible = wasDrawerOpen; | ||||
90 | applicationWindow().globalDrawer.enabled = true; | ||||
91 | applicationWindow().visibility = Window.Windowed; | ||||
92 | applicationWindow().pageStack.layers.pop(); | ||||
161 | } | 93 | } | ||
162 | ] | 94 | | ||
163 | 95 | | |||
164 | background: Rectangle { | 96 | background: Rectangle { | ||
165 | color: "black" | 97 | color: "black" | ||
166 | } | 98 | } | ||
167 | 99 | | |||
168 | Keys.onPressed: { | 100 | Keys.onPressed: { | ||
169 | switch(event.key) { | 101 | switch(event.key) { | ||
170 | case Qt.Key_Escape: | 102 | case Qt.Key_Escape: | ||
171 | root.state = "closed" | 103 | root.close(); | ||
172 | break; | 104 | break; | ||
173 | case Qt.Key_F: | 105 | case Qt.Key_F: | ||
174 | root.state = root.state == "open" ? "fullscreen" : "open" | 106 | applicationWindow().visibility = applicationWindow().visibility == Window.FullScreen ? Window.Windowed : Window.FullScreen | ||
175 | break; | 107 | break; | ||
176 | default: | 108 | default: | ||
177 | break; | 109 | break; | ||
178 | } | 110 | } | ||
179 | } | 111 | } | ||
180 | 112 | | |||
181 | ListView { | 113 | ListView { | ||
182 | id: listView | 114 | id: listView | ||
183 | anchors.fill: parent | 115 | anchors.fill: parent | ||
184 | orientation: Qt.Horizontal | 116 | orientation: Qt.Horizontal | ||
185 | snapMode: ListView.SnapOneItem | 117 | snapMode: ListView.SnapOneItem | ||
186 | onMovementEnded: currentImage.index = model.sourceIndex(indexAt(contentX+1, 1)) | 118 | onMovementEnded: currentImage.index = model.sourceIndex(indexAt(contentX+1, 1)) | ||
187 | 119 | | |||
188 | model: Koko.SortModel { | 120 | model: Koko.SortModel { | ||
189 | id: imagesListModel | 121 | id: imagesListModel | ||
190 | filterRole: Koko.Roles.MimeTypeRole | 122 | filterRole: Koko.Roles.MimeTypeRole | ||
191 | filterRegExp: /image\// | 123 | filterRegExp: /image\// | ||
192 | } | 124 | } | ||
193 | currentIndex: model.proxyIndex( indexValue) | 125 | currentIndex: model.proxyIndex( indexValue) | ||
194 | 126 | | |||
195 | Timer { | | |||
196 | id: timer | | |||
197 | interval: 2000 | | |||
198 | onTriggered: footerList.opacity = 0 | | |||
199 | } | | |||
200 | | ||||
201 | onCurrentIndexChanged: { | 127 | onCurrentIndexChanged: { | ||
202 | currentImage.index = model.sourceIndex( currentIndex) | 128 | currentImage.index = model.sourceIndex( currentIndex) | ||
203 | listView.positionViewAtIndex(currentIndex, ListView.Beginning) | 129 | listView.positionViewAtIndex(currentIndex, ListView.Beginning) | ||
204 | if( footerList.visible == true) { | 130 | | ||
205 | footerList.opacity = 1.0 | 131 | shareDialog.close(); | ||
206 | } | | |||
207 | timer.restart() | | |||
208 | shareDialog.sheetOpen = false | | |||
209 | } | 132 | } | ||
210 | 133 | | |||
211 | delegate: Flickable { | 134 | delegate: Flickable { | ||
212 | id: flick | 135 | id: flick | ||
213 | property alias currentImageSource: image.source | 136 | property alias currentImageSource: image.source | ||
214 | width: imageWidth | 137 | width: imageWidth | ||
215 | height: imageHeight | 138 | height: imageHeight | ||
216 | contentWidth: imageWidth | 139 | contentWidth: imageWidth | ||
▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Line(s) | 224 | Image { | |||
303 | width: flick.contentWidth | 226 | width: flick.contentWidth | ||
304 | height: flick.contentHeight | 227 | height: flick.contentHeight | ||
305 | source: model.imageurl | 228 | source: model.imageurl | ||
306 | fillMode: Image.PreserveAspectFit | 229 | fillMode: Image.PreserveAspectFit | ||
307 | asynchronous: true | 230 | asynchronous: true | ||
308 | autoTransform: true | 231 | autoTransform: true | ||
309 | sourceSize.width: imageWidth * 2 | 232 | sourceSize.width: imageWidth * 2 | ||
310 | sourceSize.height: imageHeight * 2 | 233 | sourceSize.height: imageHeight * 2 | ||
234 | Timer { | ||||
235 | id: doubleClickTimer | ||||
236 | interval: 150 | ||||
237 | onTriggered: applicationWindow().controlsVisible = !applicationWindow().controlsVisible | ||||
238 | } | ||||
311 | MouseArea { | 239 | MouseArea { | ||
312 | anchors.fill: parent | 240 | anchors.fill: parent | ||
241 | onClicked: { | ||||
242 | doubleClickTimer.restart(); | ||||
243 | } | ||||
313 | onDoubleClicked: { | 244 | onDoubleClicked: { | ||
245 | doubleClickTimer.running = false; | ||||
246 | applicationWindow().controlsVisible = false; | ||||
314 | if (flick.interactive) { | 247 | if (flick.interactive) { | ||
315 | zoomAnim.x = 0; | 248 | zoomAnim.x = 0; | ||
316 | zoomAnim.y = 0; | 249 | zoomAnim.y = 0; | ||
317 | zoomAnim.width = root.imageWidth; | 250 | zoomAnim.width = root.imageWidth; | ||
318 | zoomAnim.height = root.imageHeight; | 251 | zoomAnim.height = root.imageHeight; | ||
319 | zoomAnim.running = true; | 252 | zoomAnim.running = true; | ||
320 | } else { | 253 | } else { | ||
321 | zoomAnim.x = mouse.x * 2; | 254 | zoomAnim.x = mouse.x * 2; | ||
Show All 28 Lines | 261 | onWheel: { | |||
350 | } | 283 | } | ||
351 | } | 284 | } | ||
352 | } | 285 | } | ||
353 | } | 286 | } | ||
354 | } | 287 | } | ||
355 | } | 288 | } | ||
356 | } | 289 | } | ||
357 | 290 | | |||
358 | PathView { | | |||
359 | id: footerList | | |||
360 | visible: root.state == "open" ? true : false | | |||
361 | height: Kirigami.Units.gridUnit * 4 | | |||
362 | model: listView.model | | |||
363 | currentIndex: listView.currentIndex | | |||
364 | pathItemCount: applicationWindow().width / (Kirigami.Units.gridUnit * 5) | | |||
365 | interactive: false | | |||
366 | | ||||
367 | preferredHighlightBegin: 0.5 | | |||
368 | preferredHighlightEnd: 0.5 | | |||
369 | highlightRangeMode: PathView.StrictlyEnforceRange | | |||
370 | | ||||
371 | Behavior on opacity { OpacityAnimator { duration: 500}} | | |||
372 | | ||||
373 | path: Path { | | |||
374 | startX: 0 | | |||
375 | startY: applicationWindow().height - (Kirigami.Units.gridUnit * 5) | | |||
376 | PathAttribute { name: "iconScale"; value: 0.5 } | | |||
377 | PathLine { | | |||
378 | x: applicationWindow().width / 2 | | |||
379 | y: applicationWindow().height - (Kirigami.Units.gridUnit * 5) | | |||
380 | } | | |||
381 | PathAttribute { name: "iconScale"; value: 1.5 } | | |||
382 | PathLine { | | |||
383 | x: applicationWindow().width | | |||
384 | y: applicationWindow().height - (Kirigami.Units.gridUnit * 5) | | |||
385 | } | | |||
386 | PathAttribute { name: "iconScale"; value: 0.5 } | | |||
387 | } | | |||
388 | | ||||
389 | delegate: Item { | | |||
390 | scale: PathView.iconScale | | |||
391 | height: Kirigami.Units.gridUnit * 4 | | |||
392 | width: height | | |||
393 | KQA.QImageItem { | | |||
394 | height: Kirigami.Units.gridUnit * 3.8 | | |||
395 | width: height | | |||
396 | anchors.centerIn: parent | | |||
397 | image: model.thumbnail | | |||
398 | } | | |||
399 | } | | |||
400 | } | | |||
401 | | ||||
402 | ShareDialog { | 291 | ShareDialog { | ||
403 | id: shareDialog | 292 | id: shareDialog | ||
293 | x: (root.width - width) / 2 | ||||
294 | y: root.height - height - Kirigami.Units.gridUnit * 3 | ||||
404 | inputData: { urls: [] } | 295 | inputData: { urls: [] } | ||
405 | sheetOpen: false | | |||
406 | onFinished: { | 296 | onFinished: { | ||
407 | if (error==0 && output.url !== "") { | 297 | if (error==0 && output.url !== "") { | ||
408 | console.assert(output.url !== undefined); | 298 | console.assert(output.url !== undefined); | ||
409 | var resultUrl = output.url; | 299 | var resultUrl = output.url; | ||
410 | console.log("Received", resultUrl) | 300 | console.log("Received", resultUrl) | ||
411 | notificationManager.showNotification( true, resultUrl); | 301 | notificationManager.showNotification( true, resultUrl); | ||
412 | } else { | 302 | } else { | ||
413 | notificationManager.showNotification( false); | 303 | notificationManager.showNotification( false); | ||
414 | } | 304 | } | ||
415 | } | 305 | } | ||
416 | } | 306 | } | ||
417 | 307 | | |||
418 | Koko.NotificationManager { | 308 | Koko.NotificationManager { | ||
419 | id: notificationManager | 309 | id: notificationManager | ||
420 | } | 310 | } | ||
421 | } | 311 | } |