on xenial help sign in
Make tablet mode work better for tutorial
35b5baaMichael Terry
qml/Stages/AbstractStage.qml+1
@@ -28,6 +28,7 @@ Rectangle {
28 property url background
28 property url background
29 property bool beingResized
29 property bool beingResized
30 property int dragAreaWidth
30 property int dragAreaWidth
31+ property real dragProgress
31 property bool interactive
32 property bool interactive
32 property real inverseProgress // This is the progress for left edge drags, in pixels.
33 property real inverseProgress // This is the progress for left edge drags, in pixels.
33 property bool keepDashRunning: true
34 property bool keepDashRunning: true
qml/Stages/PhoneStage.qml+1−1
@@ -84,7 +84,7 @@ AbstractStage {
84 && spreadView.phase === 0
84 && spreadView.phase === 0
85
85
86 // How far left the stage has been dragged
86 // How far left the stage has been dragged
87− readonly property real dragProgress: spreadRepeater.count > 0 ? spreadRepeater.itemAt(0).progress : 0
87+ dragProgress: spreadRepeater.count > 0 ? spreadRepeater.itemAt(0).animatedProgress : 0
88
88
89 readonly property alias dragging: spreadDragArea.dragging
89 readonly property alias dragging: spreadDragArea.dragging
90
90
qml/Stages/TabletStage.qml+13−11
@@ -27,6 +27,9 @@ AbstractStage {
27 objectName: "stages"
27 objectName: "stages"
28 anchors.fill: parent
28 anchors.fill: parent
29
29
30+ property bool sideStageVisible: priv.sideStageAppId
31+ property real sideStageWidth: units.gu(40)
32+
30 // Functions to be called from outside
33 // Functions to be called from outside
31 function updateFocusedAppOrientation() {
34 function updateFocusedAppOrientation() {
32 var mainStageAppIndex = priv.indexOf(priv.mainStageAppId);
35 var mainStageAppIndex = priv.indexOf(priv.mainStageAppId);
@@ -71,6 +74,7 @@ AbstractStage {
71 }
74 }
72
75
73 orientationChangesEnabled: priv.mainAppOrientationChangesEnabled
76 orientationChangesEnabled: priv.mainAppOrientationChangesEnabled
77+ dragProgress: spreadRepeater.count > 0 ? spreadRepeater.itemAt(0).animatedProgress : 0
74
78
75 onWidthChanged: {
79 onWidthChanged: {
76 spreadView.selectedIndex = -1;
80 spreadView.selectedIndex = -1;
@@ -233,8 +237,6 @@ AbstractStage {
233 contentX: -shift
237 contentX: -shift
234
238
235 property int tileDistance: units.gu(20)
239 property int tileDistance: units.gu(20)
236− property int sideStageWidth: units.gu(40)
237− property bool sideStageVisible: priv.sideStageAppId
238
240
239 // This indicates when the spreadView is active. That means, all the animations
241 // This indicates when the spreadView is active. That means, all the animations
240 // are activated and tiles need to line up for the spread.
242 // are activated and tiles need to line up for the spread.
@@ -254,14 +256,14 @@ AbstractStage {
254 // 2: The list is dragged further and snaps into the spread view when entering phase 2
256 // 2: The list is dragged further and snaps into the spread view when entering phase 2
255 property int phase
257 property int phase
256
258
257− readonly property int phase0Width: sideStageWidth
259+ readonly property int phase0Width: root.sideStageWidth
258− readonly property int phase1Width: sideStageWidth
260+ readonly property int phase1Width: root.sideStageWidth
259
261
260 // Those markers mark the various positions in the spread (ratio to screen width from right to left):
262 // Those markers mark the various positions in the spread (ratio to screen width from right to left):
261 // 0 - 1: following finger, snap back to the beginning on release
263 // 0 - 1: following finger, snap back to the beginning on release
262 readonly property real positionMarker1: 0.2
264 readonly property real positionMarker1: 0.2
263 // 1 - 2: curved snapping movement, snap to nextInStack on release
265 // 1 - 2: curved snapping movement, snap to nextInStack on release
264− readonly property real positionMarker2: sideStageWidth / spreadView.width
266+ readonly property real positionMarker2: root.sideStageWidth / spreadView.width
265 // 2 - 3: movement follows finger, snaps to phase 2 (full spread) on release
267 // 2 - 3: movement follows finger, snaps to phase 2 (full spread) on release
266 readonly property real positionMarker3: 0.6
268 readonly property real positionMarker3: 0.6
267 // passing 3, we detach movement from the finger and snap to phase 2 (full spread)
269 // passing 3, we detach movement from the finger and snap to phase 2 (full spread)
@@ -490,7 +492,7 @@ AbstractStage {
490 Rectangle {
492 Rectangle {
491 id: sideStageBackground
493 id: sideStageBackground
492 color: "black"
494 color: "black"
493− width: spreadView.sideStageWidth * (1 - sideStageDragHandle.progress)
495+ width: root.sideStageWidth * (1 - sideStageDragHandle.progress)
494 height: priv.landscapeHeight
496 height: priv.landscapeHeight
495 x: spreadView.width - width
497 x: spreadView.width - width
496 z: spreadView.indexToZIndex(priv.indexOf(priv.sideStageAppId))
498 z: spreadView.indexToZIndex(priv.indexOf(priv.sideStageAppId))
@@ -505,16 +507,16 @@ AbstractStage {
505 width: units.gu(2)
507 width: units.gu(2)
506 height: priv.landscapeHeight
508 height: priv.landscapeHeight
507 z: sideStageBackground.z
509 z: sideStageBackground.z
508− opacity: spreadView.phase <= 0 && spreadView.sideStageVisible ? 1 : 0
510+ opacity: spreadView.phase <= 0 && root.sideStageVisible ? 1 : 0
509 property real progress: 0
511 property real progress: 0
510 property bool dragging: false
512 property bool dragging: false
511
513
512 Behavior on opacity { UbuntuNumberAnimation {} }
514 Behavior on opacity { UbuntuNumberAnimation {} }
513
515
514 Connections {
516 Connections {
515− target: spreadView
517+ target: root
516 onSideStageVisibleChanged: {
518 onSideStageVisibleChanged: {
517− if (spreadView.sideStageVisible) {
519+ if (root.sideStageVisible) {
518 sideStageDragHandle.progress = 0;
520 sideStageDragHandle.progress = 0;
519 }
521 }
520 }
522 }
@@ -546,7 +548,7 @@ AbstractStage {
546 onMouseXChanged: {
548 onMouseXChanged: {
547 totalDiff += mouseX - startX;
549 totalDiff += mouseX - startX;
548 if (priv.mainStageAppId) {
550 if (priv.mainStageAppId) {
549− sideStageDragHandle.progress = Math.max(0, totalDiff / spreadView.sideStageWidth);
551+ sideStageDragHandle.progress = Math.max(0, totalDiff / root.sideStageWidth);
550 }
552 }
551 gesturePoints.push(mouseX);
553 gesturePoints.push(mouseX);
552 }
554 }
@@ -586,7 +588,7 @@ AbstractStage {
586 if (wantsMainStage) {
588 if (wantsMainStage) {
587 return spreadView.width;
589 return spreadView.width;
588 } else {
590 } else {
589− return spreadView.sideStageWidth;
591+ return root.sideStageWidth;
590 }
592 }
591 }
593 }
592 height: {
594 height: {
qml/Tutorial/TutorialBottom.qml+31−6
@@ -17,10 +17,15 @@
17import QtQuick 2.4
17import QtQuick 2.4
18import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
19import Ubuntu.Gestures 0.1
19import Ubuntu.Gestures 0.1
20+import Unity.Application 0.1
20
21
21TutorialPage {
22TutorialPage {
22 id: root
23 id: root
23
24
25+ property string usageScenario
26+ property var stage
27+ property var application: null
28+
24 // This page is a bit fragile. It relies on knowing how the app beneath
29 // This page is a bit fragile. It relies on knowing how the app beneath
25 // the shell will react to a drag. What we do is put a monitor-only DDA
30 // the shell will react to a drag. What we do is put a monitor-only DDA
26 // at the bottom of the page (so that we know when the drag is finished)
31 // at the bottom of the page (so that we know when the drag is finished)
@@ -46,6 +51,10 @@ TutorialPage {
46 appId === "messaging-app";
51 appId === "messaging-app";
47 }
52 }
48
53
54+ readonly property real mainStageWidth: stage.width - sideStageWidth
55+ readonly property real sideStageWidth: root.usageScenario === "tablet" && stage.sideStageVisible ?
56+ stage.sideStageWidth : 0
57+ readonly property bool isMainStageApp: application.stage === ApplicationInfoInterface.MainStage
49 readonly property real dragAreaHeight: units.gu(3) // based on PageWithBottomEdge.qml
58 readonly property real dragAreaHeight: units.gu(3) // based on PageWithBottomEdge.qml
50 readonly property real targetDistance: height * 0.2 + dragAreaHeight // based on PageWithBottomEdge.qml
59 readonly property real targetDistance: height * 0.2 + dragAreaHeight // based on PageWithBottomEdge.qml
51
60
@@ -65,7 +74,8 @@ TutorialPage {
65 arrow {
74 arrow {
66 anchors.bottom: root.bottom
75 anchors.bottom: root.bottom
67 anchors.bottomMargin: units.gu(4)
76 anchors.bottomMargin: units.gu(4)
68− anchors.horizontalCenter: root.horizontalCenter
77+ anchors.horizontalCenter: label.horizontalCenter
78+ anchors.horizontalCenterOffset: -(label.width - label.contentWidth) / 2
69 rotation: -90
79 rotation: -90
70 }
80 }
71
81
@@ -73,9 +83,12 @@ TutorialPage {
73 text: i18n.tr("Swipe from the bottom edge to manage the app")
83 text: i18n.tr("Swipe from the bottom edge to manage the app")
74 anchors.bottom: arrow.top
84 anchors.bottom: arrow.top
75 anchors.bottomMargin: units.gu(3)
85 anchors.bottomMargin: units.gu(3)
76− anchors.horizontalCenter: root.horizontalCenter
86+ anchors.left: root.left
77− anchors.horizontalCenterOffset: (label.width - label.contentWidth) / 2
87+ anchors.leftMargin: (label.width - label.contentWidth) / 2 + sideMargin +
78− width: root.width - units.gu(8)
88+ (isMainStageApp ? 0 : mainStageWidth)
89+ width: (isMainStageApp ? mainStageWidth : sideStageWidth) - sideMargin * 2
90+
91+ readonly property real sideMargin: units.gu(4)
79 }
92 }
80
93
81 // Watches drag events but does not intercept them, so that the app beneath
94 // Watches drag events but does not intercept them, so that the app beneath
@@ -89,9 +102,21 @@ TutorialPage {
89 anchors.bottom: parent.bottom
102 anchors.bottom: parent.bottom
90 height: root.dragAreaHeight
103 height: root.dragAreaHeight
91
104
92− // Because apps currently don't use DDA, and DDA will stop a gesture if
105+ // Apps currently don't use DDA. DDA will stop a gesture if
93− // horizontal motion is detected. But our apps wont'. So turn off
106+ // horizontal motion is detected. But our apps won't. So turn off
94 // that gesture cleverness on our part, it will only get us out of sync.
107 // that gesture cleverness on our part, it will only get us out of sync.
95 immediateRecognition: true
108 immediateRecognition: true
96 }
109 }
110+
111+ MouseArea {
112+ // A second mouse area because in tablet mode, we only want to let the
113+ // user drag up on one of the stages, not both. So we want to cover
114+ // the second bottom edge with an event eater.
115+ enabled: root.usageScenario === "tablet"
116+ height: root.dragAreaHeight
117+ width: isMainStageApp ? sideStageWidth : mainStageWidth
118+ anchors.bottom: parent.bottom
119+ anchors.left: isMainStageApp ? undefined : parent.left
120+ anchors.right: isMainStageApp ? parent.right : undefined
121+ }
97}
122}
qml/Tutorial/TutorialContent.qml+13−6
@@ -55,6 +55,10 @@ Item {
55 root.usageScenario === "phone" ||
55 root.usageScenario === "phone" ||
56 root.usageScenario === "tablet"
56 root.usageScenario === "tablet"
57
57
58+ property var focusedApp: ApplicationManager.focusedApplicationId
59+ ? ApplicationManager.findApplication(ApplicationManager.focusedApplicationId)
60+ : null
61+
58 property bool endPointsFinished: tutorialRight.skipped && tutorialBottom.skipped
62 property bool endPointsFinished: tutorialRight.skipped && tutorialBottom.skipped
59 onEndPointsFinishedChanged: if (endPointsFinished) root.finish()
63 onEndPointsFinishedChanged: if (endPointsFinished) root.finish()
60 }
64 }
@@ -130,10 +134,10 @@ Item {
130 }
134 }
131
135
132 Connections {
136 Connections {
133− target: stage
137+ target: d
134− onMainAppChanged: {
138+ onFocusedAppChanged: {
135− if (tutorialRight.isReady && !tutorialRight.shown && stage.mainApp
139+ if (tutorialRight.isReady && !tutorialRight.shown && d.focusedApp
136− && stage.mainApp.state === ApplicationInfoInterface.Starting) {
140+ && d.focusedApp.state === ApplicationInfoInterface.Starting) {
137 tutorialRight.show();
141 tutorialRight.show();
138 }
142 }
139 }
143 }
@@ -150,13 +154,16 @@ Item {
150 anchors.fill: parent
154 anchors.fill: parent
151 hides: [launcher, panel.indicators]
155 hides: [launcher, panel.indicators]
152 paused: root.paused
156 paused: root.paused
157+ usageScenario: root.usageScenario
158+ stage: root.stage
159+ application: d.focusedApp
153
160
154 readonly property bool skipped: !d.mobileScenario ||
161 readonly property bool skipped: !d.mobileScenario ||
155 AccountsService.demoEdgesCompleted.indexOf("bottom") != -1
162 AccountsService.demoEdgesCompleted.indexOf("bottom") != -1
156− readonly property bool mightShow: !skipped && stage.mainApp && canShowForApp(stage.mainApp.appId)
163+ readonly property bool mightShow: !skipped && d.focusedApp && canShowForApp(d.focusedApp.appId)
157 isReady: !skipped && !paused && !keyboardVisible &&
164 isReady: !skipped && !paused && !keyboardVisible &&
158 !tutorialTop.shown && !tutorialRight.shown &&
165 !tutorialTop.shown && !tutorialRight.shown &&
159− mightShow && stage.mainApp.state === ApplicationInfoInterface.Running
166+ mightShow && d.focusedApp.state === ApplicationInfoInterface.Running
160
167
161 onSkippedChanged: if (skipped && shown) hide()
168 onSkippedChanged: if (skipped && shown) hide()
162 onIsReadyChanged: if (isReady && !shown) show()
169 onIsReadyChanged: if (isReady && !shown) show()