on xenial help sign in
make right edge animation work, dropping all the screenshot crazyness
80737c6Michael Zanetti
plugins/Unity/Launcher/launchermodel.cpp+6
@@ -23,6 +23,8 @@
23
23
24#include <unity/shell/application/ApplicationInfoInterface.h>
24#include <unity/shell/application/ApplicationInfoInterface.h>
25
25
26+#include <QDebug>
27+
26using namespace unity::shell::application;
28using namespace unity::shell::application;
27
29
28LauncherModel::LauncherModel(QObject *parent):
30LauncherModel::LauncherModel(QObject *parent):
@@ -291,6 +293,10 @@ void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
291 Q_UNUSED(parent);
293 Q_UNUSED(parent);
292
294
293 ApplicationInfoInterface *app = m_appManager->get(row);
295 ApplicationInfoInterface *app = m_appManager->get(row);
296+ if (!app) {
297+ qDebug() << "Huh? Can't get newly added Application from ApplicationManager... Ignoring this app...";
298+ return;
299+ }
294
300
295 bool found = false;
301 bool found = false;
296 Q_FOREACH(LauncherItem *item, m_list) {
302 Q_FOREACH(LauncherItem *item, m_list) {
qml/Stages/PhoneStage.qml+90−221
@@ -17,45 +17,28 @@
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19import Ubuntu.Gestures 0.1
19import Ubuntu.Gestures 0.1
20−import Unity.Application 0.1
20+import Mir.Application 0.1
21import Utils 0.1
21import Utils 0.1
22import "../Components"
22import "../Components"
23
23
24−Item {
24+Rectangle {
25 id: root
25 id: root
26+ color: "green"
26
27
27 // Controls to be set from outside
28 // Controls to be set from outside
28− property bool shown: false
29− property bool moving: false
30 property int dragAreaWidth
29 property int dragAreaWidth
31
30
31+ // FIXME: Should be registerd singleton type QAbstractItemModel.
32+ property var surfaces
33+
32 // State information propagated to the outside
34 // State information propagated to the outside
33− readonly property bool painting: mainScreenshotImage.visible || fadeInScreenshotImage.visible || appSplash.visible || spreadView.visible
34 property bool fullscreen: priv.focusedApplication ? priv.focusedApplication.fullscreen : false
35 property bool fullscreen: priv.focusedApplication ? priv.focusedApplication.fullscreen : false
35 property bool locked: spreadView.visible
36 property bool locked: spreadView.visible
36
37
37− // Not used for PhoneStage, only useful for SideStage and similar
38− property bool overlayMode: false
39− property int overlayWidth: 0
40−
41 function select(appId) {
38 function select(appId) {
42 spreadView.snapTo(priv.indexOf(appId))
39 spreadView.snapTo(priv.indexOf(appId))
43 }
40 }
44
41
45− onMovingChanged: {
46− if (moving) {
47− if (ApplicationManager.focusedApplicationId) {
48− priv.requestNewScreenshot();
49− } else {
50− mainScreenshotImage.anchors.leftMargin = 0;
51− mainScreenshotImage.source = ApplicationManager.get(0).screenshot;
52− mainScreenshotImage.visible = true;
53− }
54− } else {
55− mainScreenshotImage.visible = false;
56− }
57− }
58−
59 Connections {
42 Connections {
60 target: ApplicationManager
43 target: ApplicationManager
61
44
@@ -74,7 +57,6 @@ Item {
74 } else {
57 } else {
75 var application = priv.focusedApplication;
58 var application = priv.focusedApplication;
76 root.fullscreen = application.fullscreen;
59 root.fullscreen = application.fullscreen;
77− mainScreenshotImage.source = application.screenshot;
78 }
60 }
79 } else {
61 } else {
80 spreadView.selectedIndex = -1;
62 spreadView.selectedIndex = -1;
@@ -84,29 +66,7 @@ Item {
84 }
66 }
85
67
86 onApplicationAdded: {
68 onApplicationAdded: {
87− if (!priv.focusedApplication) {
88− mainScreenshotImage.source = "";
89− mainScreenshotImage.visible = false;
90− priv.applicationStarting = true;
91− } else {
92− mainScreenshotImage.source = "";
93− priv.newFocusedAppId = appId;
94− priv.secondApplicationStarting = true;
95− priv.requestNewScreenshot();
96− }
97−
98− if (spreadView.visible) {
99− spreadView.snapTo(0);
69+ spreadView.snapTo(0);
100− }
101− }
102−
103− onApplicationRemoved: {
104− if (ApplicationManager.count == 0) {
105− mainScreenshotImage.source = ""
106− mainScreenshotImage.visible = false;
107− } else {
108− mainScreenshotImage.source = ApplicationManager.get(0).screenshot;
109− }
110 }
70 }
111 }
71 }
112
72
@@ -115,31 +75,12 @@ Item {
115
75
116 property string focusedAppId: ApplicationManager.focusedApplicationId
76 property string focusedAppId: ApplicationManager.focusedApplicationId
117 property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
77 property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
118− property url focusedScreenshot: focusedApplication ? focusedApplication.screenshot : ""
119−
120− property bool waitingForScreenshot: false
121
78
122 property bool applicationStarting: false
79 property bool applicationStarting: false
123 property bool secondApplicationStarting: false
80 property bool secondApplicationStarting: false
124
81
125 property string newFocusedAppId
82 property string newFocusedAppId
126
83
127− onFocusedScreenshotChanged: {
128− if (root.moving && priv.waitingForScreenshot) {
129− mainScreenshotImage.anchors.leftMargin = 0;
130− mainScreenshotImage.source = priv.focusedScreenshot
131− mainScreenshotImage.visible = true;
132− } else if (priv.secondApplicationStarting && priv.waitingForScreenshot) {
133− applicationSwitchingAnimation.start();
134− }
135− waitingForScreenshot = false;
136− }
137−
138− function requestNewScreenshot() {
139− waitingForScreenshot = true;
140− ApplicationManager.updateScreenshot(focusedAppId);
141− }
142−
143 function switchToApp(appId) {
84 function switchToApp(appId) {
144 if (priv.focusedAppId) {
85 if (priv.focusedAppId) {
145 priv.newFocusedAppId = appId;
86 priv.newFocusedAppId = appId;
@@ -147,6 +88,8 @@ Item {
147 applicationSwitchingAnimation.start();
88 applicationSwitchingAnimation.start();
148 } else {
89 } else {
149 ApplicationManager.focusApplication(appId);
90 ApplicationManager.focusApplication(appId);
91+ // TODO: Should happen behind the schenes
92+ surfaces.move(surfaces.getIndexOfSurfaceWithAppId(appId), 0);
150 }
93 }
151 }
94 }
152
95
@@ -161,155 +104,6 @@ Item {
161
104
162 }
105 }
163
106
164− // FIXME: the signal connections seems to get lost.
165− Connections {
166− target: priv.focusedApplication
167− onScreenshotChanged: priv.focusedScreenshot = priv.focusedApplication.screenshot
168− }
169− Binding {
170− target: root
171− property: "fullscreen"
172− value: priv.focusedApplication ? priv.focusedApplication.fullscreen : false
173− }
174−
175− Timer {
176− id: appSplashTimer
177− // FIXME: We really need to show something meaningful in the app surface instead of guessing
178− // when it might be ready
179− interval: 500
180− repeat: false
181− onTriggered: {
182− priv.applicationStarting = false;
183− priv.secondApplicationStarting = false;
184− }
185− }
186−
187− SequentialAnimation {
188− id: applicationSwitchingAnimation
189− // setup
190− PropertyAction { target: mainScreenshotImage; property: "anchors.leftMargin"; value: 0 }
191− PropertyAction { target: mainScreenshotImage; property: "source"; value: priv.focusedScreenshot }
192− PropertyAction { targets: [mainScreenshotImage, fadeInScreenshotImage]; property: "visible"; value: true }
193− PropertyAction { target: fadeInScreenshotImage; property: "source"; value: {
194− var newFocusedApp = ApplicationManager.findApplication(priv.newFocusedAppId);
195− return newFocusedApp ? newFocusedApp.screenshot : "" }
196− }
197− PropertyAction { target: fadeInScreenshotImage; property: "opacity"; value: 0 }
198− PropertyAction { target: fadeInScreenshotImage; property: "scale"; value: .8 }
199−
200−
201− // The actual animation
202− ParallelAnimation {
203− UbuntuNumberAnimation { target: mainScreenshotImage; property: "anchors.leftMargin"; to: root.width; duration: UbuntuAnimation.SlowDuration }
204− UbuntuNumberAnimation { target: fadeInScreenshotImage; properties: "opacity,scale"; to: 1; duration: UbuntuAnimation.SlowDuration }
205− }
206−
207− // restore stuff
208− ScriptAction { script: ApplicationManager.focusApplication(priv.newFocusedAppId); }
209− PropertyAction { target: fadeInScreenshotImage; property: "visible"; value: false }
210− PropertyAction { target: mainScreenshotImage; property: "visible"; value: false }
211− }
212−
213− // FIXME: Drop this and make the imageprovider show a splashscreen instead
214− Rectangle {
215− id: appSplash2
216− anchors.fill: parent
217− color: "white"
218− visible: priv.secondApplicationStarting
219− }
220− Image {
221− id: fadeInScreenshotImage
222− anchors { left: parent.left; bottom: parent.bottom }
223− width: parent.width
224− scale: .7
225− visible: false
226− }
227−
228− Rectangle {
229− id: appSplash
230− anchors.fill: parent
231− color: "white"
232− visible: priv.applicationStarting
233− }
234− Image {
235− id: mainScreenshotImage
236− anchors { left: parent.left; bottom: parent.bottom }
237− width: parent.width
238− visible: false
239− }
240−
241− EdgeDragArea {
242− id: spreadDragArea
243− direction: Direction.Leftwards
244− enabled: ApplicationManager.count > 1 && spreadView.phase != 2
245−
246− anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
247− width: root.dragAreaWidth
248−
249− // Sitting at the right edge of the screen, this EdgeDragArea directly controls the spreadView when
250− // attachedToView is true. When the finger movement passes positionMarker3 we detach it from the
251− // spreadView and make the spreadView snap to positionMarker4.
252− property bool attachedToView: true
253−
254− property var gesturePoints: new Array()
255−
256− onTouchXChanged: {
257− if (!dragging && !priv.waitingForScreenshot) {
258− // Initial touch. Let's update the screenshot and reset the spreadView to the starting position.
259− priv.requestNewScreenshot();
260− spreadView.phase = 0;
261− spreadView.contentX = -spreadView.shift;
262− }
263− if (dragging && attachedToView) {
264− // Gesture recognized. Let's move the spreadView with the finger
265− spreadView.contentX = -touchX - spreadView.shift;
266− }
267− if (attachedToView && spreadView.shiftedContentX >= spreadView.width * spreadView.positionMarker3) {
268− // We passed positionMarker3. Detach from spreadView and snap it.
269− attachedToView = false;
270− spreadView.snap();
271− }
272− gesturePoints.push(touchX);
273− }
274−
275− onStatusChanged: {
276− if (status == DirectionalDragArea.Recognized) {
277− attachedToView = true;
278− }
279− }
280−
281− onDraggingChanged: {
282− if (dragging) {
283− // Gesture recognized. Start recording this gesture
284− gesturePoints = [];
285− return;
286− }
287−
288− // Ok. The user released. Find out if it was a one-way movement.
289− var oneWayFlick = true;
290− var smallestX = spreadDragArea.width;
291− for (var i = 0; i < gesturePoints.length; i++) {
292− if (gesturePoints[i] >= smallestX) {
293− oneWayFlick = false;
294− break;
295− }
296− smallestX = gesturePoints[i];
297− }
298− gesturePoints = [];
299−
300− if (oneWayFlick && spreadView.shiftedContentX > units.gu(2) &&
301− spreadView.shiftedContentX < spreadView.positionMarker1 * spreadView.width) {
302− // If it was a short one-way movement, do the Alt+Tab switch
303− // no matter if we didn't cross positionMarker1 yet.
304− spreadView.snapTo(1);
305− } else if (!dragging && attachedToView) {
306− // otherwise snap to the closest snap position we can find
307− // (might be back to start, to app 1 or to spread)
308− spreadView.snap();
309− }
310− }
311− }
312−
313 Rectangle {
107 Rectangle {
314 id: coverFlipBackground
108 id: coverFlipBackground
315 anchors.fill: parent
109 anchors.fill: parent
@@ -317,16 +111,13 @@ Item {
317 visible: spreadView.visible
111 visible: spreadView.visible
318 }
112 }
319
113
320− InputFilterArea {
321− anchors.fill: root
322− blockInput: spreadView.visible
323− }
324
114
325 Flickable {
115 Flickable {
326 id: spreadView
116 id: spreadView
327 objectName: "spreadView"
117 objectName: "spreadView"
328 anchors.fill: parent
118 anchors.fill: parent
329− visible: spreadDragArea.status == DirectionalDragArea.Recognized || phase > 1 || snapAnimation.running
119+// visible: spreadDragArea.status == DirectionalDragArea.Recognized || phase > 1 || snapAnimation.running
120+ interactive: spreadDragArea.status == DirectionalDragArea.Recognized || phase > 1 || snapAnimation.running
330 contentWidth: spreadRow.width - shift
121 contentWidth: spreadRow.width - shift
331 contentX: -shift
122 contentX: -shift
332
123
@@ -414,6 +205,10 @@ Item {
414 script: {
205 script: {
415 if (spreadView.selectedIndex >= 0) {
206 if (spreadView.selectedIndex >= 0) {
416 ApplicationManager.focusApplication(ApplicationManager.get(spreadView.selectedIndex).appId);
207 ApplicationManager.focusApplication(ApplicationManager.get(spreadView.selectedIndex).appId);
208+
209+ // TODO: Should happen behind the schenes
210+ surfaces.move(spreadView.selectedIndex, 0);
211+
417 spreadView.selectedIndex = -1
212 spreadView.selectedIndex = -1
418 spreadView.phase = 0;
213 spreadView.phase = 0;
419 spreadView.contentX = -spreadView.shift;
214 spreadView.contentX = -spreadView.shift;
@@ -433,7 +228,7 @@ Item {
433
228
434 Repeater {
229 Repeater {
435 id: spreadRepeater
230 id: spreadRepeater
436− model: ApplicationManager
231+ model: root.surfaces
437 delegate: TransformedSpreadDelegate {
232 delegate: TransformedSpreadDelegate {
438 id: appDelegate
233 id: appDelegate
439 objectName: "appDelegate" + index
234 objectName: "appDelegate" + index
@@ -447,6 +242,8 @@ Item {
447 height: spreadView.height
242 height: spreadView.height
448 selected: spreadView.selectedIndex == index
243 selected: spreadView.selectedIndex == index
449 otherSelected: spreadView.selectedIndex >= 0 && !selected
244 otherSelected: spreadView.selectedIndex >= 0 && !selected
245+ surface: model.surface
246+ interactive: !spreadView.interactive
450
247
451 z: index
248 z: index
452 x: index == 0 ? 0 : spreadView.width + (index - 1) * spreadView.tileDistance
249 x: index == 0 ? 0 : spreadView.width + (index - 1) * spreadView.tileDistance
@@ -496,4 +293,76 @@ Item {
496 }
293 }
497 }
294 }
498 }
295 }
296+
297+ EdgeDragArea {
298+ id: spreadDragArea
299+ direction: Direction.Leftwards
300+ enabled: ApplicationManager.count > 1 && spreadView.phase != 2
301+
302+ anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
303+ width: root.dragAreaWidth
304+
305+ // Sitting at the right edge of the screen, this EdgeDragArea directly controls the spreadView when
306+ // attachedToView is true. When the finger movement passes positionMarker3 we detach it from the
307+ // spreadView and make the spreadView snap to positionMarker4.
308+ property bool attachedToView: true
309+
310+ property var gesturePoints: new Array()
311+
312+ onTouchXChanged: {
313+ if (!dragging) {
314+ // Initial touch. Let's reset the spreadView to the starting position.
315+ spreadView.phase = 0;
316+ spreadView.contentX = -spreadView.shift;
317+ }
318+ if (dragging && attachedToView) {
319+ // Gesture recognized. Let's move the spreadView with the finger
320+ spreadView.contentX = -touchX - spreadView.shift;
321+ }
322+ if (attachedToView && spreadView.shiftedContentX >= spreadView.width * spreadView.positionMarker3) {
323+ // We passed positionMarker3. Detach from spreadView and snap it.
324+ attachedToView = false;
325+ spreadView.snap();
326+ }
327+ gesturePoints.push(touchX);
328+ }
329+
330+ onStatusChanged: {
331+ if (status == DirectionalDragArea.Recognized) {
332+ attachedToView = true;
333+ }
334+ }
335+
336+ onDraggingChanged: {
337+ if (dragging) {
338+ // Gesture recognized. Start recording this gesture
339+ gesturePoints = [];
340+ return;
341+ }
342+
343+ // Ok. The user released. Find out if it was a one-way movement.
344+ var oneWayFlick = true;
345+ var smallestX = spreadDragArea.width;
346+ for (var i = 0; i < gesturePoints.length; i++) {
347+ if (gesturePoints[i] >= smallestX) {
348+ oneWayFlick = false;
349+ break;
350+ }
351+ smallestX = gesturePoints[i];
352+ }
353+ gesturePoints = [];
354+
355+ if (oneWayFlick && spreadView.shiftedContentX > units.gu(2) &&
356+ spreadView.shiftedContentX < spreadView.positionMarker1 * spreadView.width) {
357+ // If it was a short one-way movement, do the Alt+Tab switch
358+ // no matter if we didn't cross positionMarker1 yet.
359+ spreadView.snapTo(1);
360+ } else if (!dragging && attachedToView) {
361+ // otherwise snap to the closest snap position we can find
362+ // (might be back to start, to app 1 or to spread)
363+ spreadView.snap();
364+ }
365+ }
366+ }
367+
499}
368}
qml/Stages/SpreadDelegate.qml+31−19
@@ -22,34 +22,46 @@ Item {
22 id: root
22 id: root
23
23
24 signal clicked()
24 signal clicked()
25−
26 property real topMarginProgress
25 property real topMarginProgress
26+ property bool interactive: true
27
27
28− QtObject {
28+ // FIXME: This really should be invisible to QML code.
29− id: priv
29+ // e.g. Create a SurfaceItem {} in C++ which we just use without any imperative hacks.
30+ property var surface
31+ onSurfaceChanged: {
32+ if (surface) {
33+ root.width = surface.implicitWidth;
30− property real heightDifference: root.height - appImage.implicitHeight
34+ root.height = surface.implicitHeight;
35+ surface.parent = root;
36+ surface.anchors.fill = root;
37+ surface.enabled = root.interactive;
38+ surface.z = 1;
39+ }
40+ }
41+
42+ Component.onDestruction: {
43+ if (surface) {
44+ surface.release();
45+ }
31 }
46 }
32
47
33− Image {
48+ BorderImage {
34 id: dropShadow
49 id: dropShadow
35− anchors.fill: appImage
50+ anchors.fill: root
36 anchors.margins: -units.gu(2)
51 anchors.margins: -units.gu(2)
37 source: "graphics/dropshadow.png"
52 source: "graphics/dropshadow.png"
38 opacity: .4
53 opacity: .4
54+ border { left: 50; right: 50; top: 50; bottom: 50 }
39 }
55 }
40− Image {
56+
41− id: appImage
57+ // This is used to get clicked events on the whole app. e.g. when in spreadView.
42− anchors {
58+ // It's only enabled when the surface is !interactive
43− left: parent.left;
44− bottom: parent.bottom;
45− top: parent.top;
46− topMargin: priv.heightDifference * Math.max(0, 1 - root.topMarginProgress)
47− }
48− source: model.screenshot
49− antialiasing: true
50− }
51 MouseArea {
59 MouseArea {
52− anchors.fill: appImage
60+ anchors.fill: parent
61+ z: 2
62+ enabled: !root.interactive
63+ onClicked: {
53− onClicked: root.clicked()
64+ root.clicked()
65+ }
54 }
66 }
55}
67}