@@ -18,39 +18,41 @@
1818
1919import QtQuick 2.0
2020import Mir.Application 0.1
21−import Ubuntu.Components 1.0
21+import Ubuntu.Components 1.1
2222import "../Components"
2323
2424Item {
2525 id: root
2626
27− signal clicked()
2827 property bool interactive: true
29− property real maximizedAppTopMargin
30− property bool isFullscreen: surface !== null && surface.anchors.topMargin == 0
3128 property bool dropShadow: true
29+ property real maximizedAppTopMargin
3230
33− // FIXME: This really should be invisible to QML code.
34− // e.g. Create a SurfaceItem {} in C++ which we just use without any imperative hacks.
35− readonly property var surface: model.surface
36− onSurfaceChanged: { print("SURFACE!!", model.surface)
37− if (surface) {
38− if (!priv.appHasCreatedASurface) {
39− surface.visible = false; // hide until splash screen removed
40− priv.appHasCreatedASurface = true;
41− }
31+ readonly property bool isFullscreen: surface !== null && surfaceContainer.surface.anchors.topMargin == 0
4232
43− surface.parent = root;
44− surface.anchors.fill = root;
45− priv.checkFullscreen(surface);
46− surface.z = 1;
47− }
48− }
33+ signal clicked()
34+ signal closed()
4935
50− QtObject {
51− id: priv
36+ Item {
37+ id: surfaceContainer
38+ anchors.fill: parent
39+ readonly property var surface: model.surface
5240 property bool appHasCreatedASurface: false
5341
42+ onSurfaceChanged: { print("SURFACE!!", model.surface)
43+ if (surface) {
44+ if (!appHasCreatedASurface) {
45+ surface.visible = false; // hide until splash screen removed
46+ appHasCreatedASurface = true;
47+ }
48+
49+ surface.parent = surfaceContainer;
50+ surface.anchors.fill = surfaceContainer;
51+ checkFullscreen(surface);
52+ surface.z = 1;
53+ }
54+ }
55+
5456 function checkFullscreen(surface) {
5557 if (surface.state === MirSurfaceItem.Fullscreen) {
5658 surface.anchors.topMargin = 0;
@@ -63,43 +65,58 @@ Item {
6365 surface.visible = true;
6466 splashLoader.source = "";
6567 }
66− }
6768
68− Timer { //FIXME - need to delay removing splash screen to allow surface resize to complete
69− id: surfaceRevealDelay
70− interval: 100
71− onTriggered: priv.revealSurface()
72− }
69+ Binding {
70+ target: surface
71+ property: "enabled"
72+ value: root.interactive
73+ }
7374
74− Binding {
75− target: surface
76− property: "enabled"
77− value: root.interactive
78− }
75+ Timer { //FIXME - need to delay removing splash screen to allow surface resize to complete
76+ id: surfaceRevealDelay
77+ interval: 100
78+ onTriggered: surfaceContainer.revealSurface()
79+ }
7980
80− Connections {
81− target: surface
82− onStateChanged: priv.checkFullscreen(surface);
81+ Connections {
82+ target: surface
83+ onStateChanged: checkFullscreen(surface);
84+ }
85+
86+ BorderImage {
87+ id: dropShadowImage
88+ anchors.fill: parent
89+ anchors.margins: -units.gu(2)
90+ source: "graphics/dropshadow.png"
91+ border { left: 50; right: 50; top: 50; bottom: 50 }
92+ opacity: root.dropShadow ? .4 : 0
93+ Behavior on opacity { UbuntuNumberAnimation {} }
94+ }
95+
96+ transform: Translate {
97+ y: dragArea.distance
98+ }
8399 }
84100
101+
85102 StateGroup {
86103 id: appSurfaceState
87104 states: [
88105 State {
89106 name: "noSurfaceYet"
90− when: !priv.appHasCreatedASurface
107+ when: !surfaceContainer.appHasCreatedASurface
91108 StateChangeScript {
92− script: {splashLoader.setSource("Splash.qml", { "name": model.name, "image": model.icon }); }
109+ script: { splashLoader.setSource("Splash.qml", { "name": model.name, "image": model.icon }); }
93110 }
94111 },
95112 State {
96113 name: "hasSurface"
97− when: priv.appHasCreatedASurface && (root.surface !== null)
114+ when: surfaceContainer.appHasCreatedASurface && (surfaceContainer.surface !== null)
98115 StateChangeScript { script: { surfaceRevealDelay.start(); } }
99116 },
100117 State {
101118 name: "surfaceLostButAppStillAlive"
102− when: priv.appHasCreatedASurface && (root.surface === null)
119+ when: surfaceContainer.appHasCreatedASurface && (surfaceContainer.surface === null)
103120 // TODO - use app snapshot
104121 }
105122 ]
@@ -108,25 +125,76 @@ Item {
108125
109126 Loader {
110127 id: splashLoader
111− anchors.fill: parent
112− }
113−
114− BorderImage {
115− id: dropShadowImage
116− anchors.fill: surface
117− anchors.margins: -units.gu(2)
118− source: "graphics/dropshadow.png"
119− border { left: 50; right: 50; top: 50; bottom: 50 }
120− opacity: root.dropShadow ? .4 : 0
121− Behavior on opacity { UbuntuNumberAnimation {} }
128+ anchors.fill: surfaceContainer
122129 }
123130
124− MouseArea {
131+ DraggingArea {
132+ id: dragArea
125133 anchors.fill: parent
126− z: 2
127134 enabled: !root.interactive
128− onClicked: {
129− root.clicked()
135+
136+ property bool moving: false
137+ property real distance: 0
138+
139+ onMovingChanged: {
140+ spreadView.draggedIndex = moving ? index : -1
141+ }
142+
143+ onDragValueChanged: {
144+ moving = moving || Math.abs(dragValue) > units.gu(1)
145+ if (moving && dragging) {
146+ distance = dragValue;
147+ }
148+ }
149+
150+ onDragEnd: {
151+ if (!moving) {
152+ root.clicked();
153+ return;
154+ }
155+
156+ if ((dragVelocity < -600 && distance < -units.gu(4)) || distance < -root.height / 2) {
157+ animation.animate("up")
158+ } else if ((dragVelocity > 600 && distance > units.gu(4)) || distance > root.height / 2) {
159+ animation.animate("down")
160+ } else {
161+ animation.animate("center")
162+ }
163+ }
164+
165+ UbuntuNumberAnimation {
166+ id: animation
167+ target: dragArea
168+ property: "distance"
169+ property bool requestClose: false
170+
171+ function animate(direction) {
172+ animation.from = dragArea.distance
173+ switch (direction) {
174+ case "up":
175+ animation.to = -root.height
176+ requestClose = true;
177+ break;
178+ case "down":
179+ animation.to = root.height
180+ requestClose = true;
181+ break;
182+ default:
183+ animation.to = 0
184+ }
185+ animation.start();
186+ }
187+
188+ onRunningChanged: {
189+ if (!running) {
190+ dragArea.moving = false;
191+ dragArea.distance = 0;
192+ if (requestClose) {
193+ root.closed()
194+ }
195+ }
196+ }
130197 }
131198 }
199+
132200}