Merge lp:~mzanetti/unity8/appmanager-rework into lp:unity8

Proposed by Michael Zanetti
Status: Rejected
Rejected by: Michael Zanetti
Proposed branch: lp:~mzanetti/unity8/appmanager-rework
Merge into: lp:unity8
Diff against target: 1949 lines (+987/-314)
22 files modified
plugins/Utils/CMakeLists.txt (+2/-1)
plugins/Utils/easingcurve.cpp (+49/-0)
plugins/Utils/easingcurve.h (+42/-0)
plugins/Utils/plugin.cpp (+2/-0)
qml/Components/ResponsiveFlowView.qml (+3/-10)
qml/Dash/Apps/RunningApplicationTile.qml (+13/-24)
qml/Dash/Apps/RunningApplicationsGrid.qml (+5/-20)
qml/Dash/DashApps.qml (+4/-10)
qml/Dash/GenericScopeView.qml (+1/-2)
qml/Shell.qml (+85/-243)
qml/Stages/PhoneStage.qml (+574/-0)
run_on_device (+1/-0)
tests/mocks/Unity/Application/ApplicationInfo.h (+3/-0)
tests/mocks/Unity/Application/ApplicationManager.cpp (+56/-1)
tests/mocks/Unity/Application/ApplicationManager.h (+2/-0)
tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp (+69/-0)
tests/mocks/Unity/Application/ApplicationScreenshotProvider.h (+34/-0)
tests/mocks/Unity/Application/CMakeLists.txt (+1/-0)
tests/mocks/Unity/Application/plugin.cpp (+18/-3)
tests/mocks/Unity/Application/plugin.h (+1/-0)
tests/plugins/Unity/Launcher/launchermodeltest.cpp (+3/-0)
tests/qmltests/tst_Shell.qml (+19/-0)
To merge this branch: bzr merge lp:~mzanetti/unity8/appmanager-rework
Reviewer Review Type Date Requested Status
Michael Zanetti (community) Disapprove
Review via email: mp+199815@code.launchpad.net

Commit message

rework ApplicationManager handling

Description of the change

This completely reworks how the Shell talks to the ApplicationManager as a preparation for the upcoming Right Edge work.

It drops ApplicationManagerWrapper as that one was mostly a leftover from very early prototypes and was the reason for many workarounds building up around it.

Also it cuts ties between the RunningApplicationGrid and the Stages. Both only talk directly to the ApplicationManager now.

Last but not least it drops the stages code as it is now and starts fresh with a PhoneStage for the upcoming Right Edge work. In the future a TabledStage and DesktopStage should be easily addable.

To post a comment you must log in.
575. By Michael Zanetti

initial try on the right edge animation

576. By Michael Zanetti

make it interactive

577. By Michael Zanetti

added a bit of scaling. not matching spec yet

578. By Michael Zanetti

make it actually switch apps

579. By Michael Zanetti

improve mouse interaction with CoverFlip

580. By Michael Zanetti

update screenshots before starting right edge animation

581. By Michael Zanetti

merge trunk

582. By Michael Zanetti

reworked animation

583. By Michael Zanetti

improved the whole animation a lot

584. By Michael Zanetti

fix glitch with focusing the right app when moving backwards, after having already passed progressmarker1

585. By Michael Zanetti

make it look nicer if there are only 3 running apps

586. By Michael Zanetti

make flicking AND clicking work

587. By Michael Zanetti

cleanup

588. By Michael Zanetti

fix selected animation

589. By Michael Zanetti

drop unused file

590. By Michael Zanetti

merge trunk

591. By Michael Zanetti

add a point of no return

592. By Michael Zanetti

some work on bringing the fake application plugin up to date with the new api

593. By Michael Zanetti

added missing files

594. By Michael Zanetti

more progress on the fake application manager

595. By Michael Zanetti

fix hiding the stage when the app is killed

596. By Michael Zanetti

added a dropshadow

597. By Michael Zanetti

slow down scrolling a bit and fix the flickables contentWidth to roughly reflect the app's positions

598. By Michael Zanetti

shrink app tiles a little to make 3 of them fit into one row again

Revision history for this message
Michael Zanetti (mzanetti) wrote :

superseeded by the right-edge-2 branch

review: Disapprove

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'plugins/Utils/CMakeLists.txt'
--- plugins/Utils/CMakeLists.txt 2013-12-10 14:22:43 +0000
+++ plugins/Utils/CMakeLists.txt 2014-01-22 10:43:18 +0000
@@ -18,6 +18,7 @@
18 qsortfilterproxymodelqml.cpp18 qsortfilterproxymodelqml.cpp
19 timeformatter.cpp19 timeformatter.cpp
20 unitymenumodelpaths.cpp20 unitymenumodelpaths.cpp
21 easingcurve.cpp
21 plugin.cpp22 plugin.cpp
22 )23 )
2324
@@ -33,7 +34,7 @@
33# files directly in targets.34# files directly in targets.
34set_target_properties(Utils-qml PROPERTIES COMPILE_FLAGS -fvisibility=default)35set_target_properties(Utils-qml PROPERTIES COMPILE_FLAGS -fvisibility=default)
3536
36qt5_use_modules(Utils-qml Qml Quick DBus Network XmlPatterns)37qt5_use_modules(Utils-qml Qml Quick DBus Network XmlPatterns Gui)
3738
38# export the qmldir qmltypes and plugin files39# export the qmldir qmltypes and plugin files
39export_qmlfiles(Utils Utils)40export_qmlfiles(Utils Utils)
4041
=== added file 'plugins/Utils/easingcurve.cpp'
--- plugins/Utils/easingcurve.cpp 1970-01-01 00:00:00 +0000
+++ plugins/Utils/easingcurve.cpp 2014-01-22 10:43:18 +0000
@@ -0,0 +1,49 @@
1#include "easingcurve.h"
2
3
4EasingCurve::EasingCurve(QObject *parent):
5 QObject(parent)
6{
7
8}
9
10QEasingCurve::Type EasingCurve::type() const
11{
12 return m_easingCurve.type();
13}
14
15void EasingCurve::setType(const QEasingCurve::Type &type)
16{
17 m_easingCurve.setType(type);
18 Q_EMIT typeChanged();
19}
20
21qreal EasingCurve::period() const
22{
23 return m_easingCurve.period();
24}
25
26void EasingCurve::setPeriod(qreal period)
27{
28 m_easingCurve.setPeriod(period);
29 Q_EMIT periodChanged();
30}
31
32qreal EasingCurve::progress() const
33{
34 return m_progress;
35}
36
37void EasingCurve::setProgress(qreal progress)
38{
39 if (m_progress != progress) {
40 m_progress = progress;
41 m_value = m_easingCurve.valueForProgress(m_progress);
42 Q_EMIT progressChanged();
43 }
44}
45
46qreal EasingCurve::value() const
47{
48 return m_value;
49}
050
=== added file 'plugins/Utils/easingcurve.h'
--- plugins/Utils/easingcurve.h 1970-01-01 00:00:00 +0000
+++ plugins/Utils/easingcurve.h 2014-01-22 10:43:18 +0000
@@ -0,0 +1,42 @@
1#ifndef EASINGCURVE_H
2#define EASINGCURVE_H
3
4#include <QObject>
5#include <QEasingCurve>
6
7class EasingCurve: public QObject
8{
9 Q_OBJECT
10 Q_ENUMS(QEasingCurve::Type)
11 Q_PROPERTY(QEasingCurve::Type type READ type WRITE setType NOTIFY typeChanged)
12 Q_PROPERTY(qreal period READ period WRITE setPeriod NOTIFY periodChanged)
13 Q_PROPERTY(qreal progress READ progress WRITE setProgress NOTIFY progressChanged)
14 Q_PROPERTY(qreal value READ value NOTIFY progressChanged)
15
16public:
17 EasingCurve(QObject *parent = 0);
18
19 QEasingCurve::Type type() const;
20 void setType(const QEasingCurve::Type &type);
21
22 qreal period() const;
23 void setPeriod(qreal period);
24
25 qreal progress() const;
26 void setProgress(qreal progress);
27
28 qreal value() const;
29
30Q_SIGNALS:
31 void typeChanged();
32 void periodChanged();
33 void progressChanged();
34
35private:
36 QEasingCurve m_easingCurve;
37 qreal m_progress;
38 qreal m_value;
39};
40
41#endif
42
043
=== modified file 'plugins/Utils/plugin.cpp'
--- plugins/Utils/plugin.cpp 2013-12-10 14:22:43 +0000
+++ plugins/Utils/plugin.cpp 2014-01-22 10:43:18 +0000
@@ -32,6 +32,7 @@
32#include "qsortfilterproxymodelqml.h"32#include "qsortfilterproxymodelqml.h"
33#include "timeformatter.h"33#include "timeformatter.h"
34#include "unitymenumodelpaths.h"34#include "unitymenumodelpaths.h"
35#include "easingcurve.h"
3536
36static const char* BOTTOM_BAR_VISIBILITY_COMMUNICATOR_DBUS_PATH = "/BottomBarVisibilityCommunicator";37static const char* BOTTOM_BAR_VISIBILITY_COMMUNICATOR_DBUS_PATH = "/BottomBarVisibilityCommunicator";
37static const char* DBUS_SERVICE = "com.canonical.Shell.BottomBarVisibilityCommunicator";38static const char* DBUS_SERVICE = "com.canonical.Shell.BottomBarVisibilityCommunicator";
@@ -46,6 +47,7 @@
46 qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter");47 qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter");
47 qmlRegisterType<GDateTimeFormatter>(uri, 0, 1, "GDateTimeFormatter");48 qmlRegisterType<GDateTimeFormatter>(uri, 0, 1, "GDateTimeFormatter");
48 qmlRegisterUncreatableType<BottomBarVisibilityCommunicatorShell>(uri, 0, 1, "BottomBarVisibilityCommunicatorShell", "Can't create BottomBarVisibilityCommunicatorShell");49 qmlRegisterUncreatableType<BottomBarVisibilityCommunicatorShell>(uri, 0, 1, "BottomBarVisibilityCommunicatorShell", "Can't create BottomBarVisibilityCommunicatorShell");
50 qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
49}51}
5052
51void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)53void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
5254
=== modified file 'qml/Components/ResponsiveFlowView.qml'
--- qml/Components/ResponsiveFlowView.qml 2013-06-05 22:03:08 +0000
+++ qml/Components/ResponsiveFlowView.qml 2014-01-22 10:43:18 +0000
@@ -27,9 +27,8 @@
27 property alias verticalSpacing: flow.verticalSpacing27 property alias verticalSpacing: flow.verticalSpacing
28 property alias horizontalSpacing: flow.horizontalSpacing28 property alias horizontalSpacing: flow.horizontalSpacing
29 property int referenceDelegateWidth29 property int referenceDelegateWidth
30 property alias firstModel: repeater1.model30 property alias model: repeater.model
31 property alias secondModel: repeater2.model31 property alias delegate: repeater.delegate
32 property alias delegate: repeater1.delegate
33 readonly property int cellWidth: referenceDelegateWidth + horizontalSpacing32 readonly property int cellWidth: referenceDelegateWidth + horizontalSpacing
34 readonly property int cellHeight: referenceDelegateWidth + verticalSpacing33 readonly property int cellHeight: referenceDelegateWidth + verticalSpacing
35 property alias move: flow.move34 property alias move: flow.move
@@ -69,13 +68,7 @@
69 property int margin: allocatableVerticalSpace - columns * horizontalSpacing68 property int margin: allocatableVerticalSpace - columns * horizontalSpacing
7069
71 Repeater {70 Repeater {
72 id: repeater171 id: repeater
73 model: (root.model) ? root.model[0] : null
74 }
75 Repeater {
76 id: repeater2
77 model: (root.model) ? root.model[1] : null
78 delegate: repeater1.delegate
79 }72 }
80 }73 }
81}74}
8275
=== modified file 'qml/Dash/Apps/RunningApplicationTile.qml'
--- qml/Dash/Apps/RunningApplicationTile.qml 2013-10-28 14:12:24 +0000
+++ qml/Dash/Apps/RunningApplicationTile.qml 2014-01-22 10:43:18 +0000
@@ -23,7 +23,6 @@
23AbstractButton {23AbstractButton {
24 id: root24 id: root
25 property var application25 property var application
26 property bool __sideStageEnabled: shell.applicationManager.sideStageEnabled
2726
28 signal requestedApplicationActivation(var application)27 signal requestedApplicationActivation(var application)
29 signal requestedApplicationTermination(var application)28 signal requestedApplicationTermination(var application)
@@ -51,32 +50,22 @@
51 }50 }
52 }51 }
5352
54 function updateScreenshotFromCache() {53 UbuntuShape {
55 applicationImage.updateFromCache();
56 }
57
58 // FIXME: should use UbuntuShape from SDK
59 UbuntuShapeForItem {
60 id: shapedApplicationImage54 id: shapedApplicationImage
61 anchors {55 anchors { top: parent.top; horizontalCenter: parent.horizontalCenter }
62 top: parent.top56
63 horizontalCenter: parent.horizontalCenter57 height: units.gu(17)
58 width: applicationImage.width
59 radius: "medium"
60
61 image: Image {
62 id: applicationImage
63 source: application.screenshot
64 // height : width = ss.height : ss.width
65 height: shapedApplicationImage.height
66 width: height * sourceSize.width / sourceSize.height
64 }67 }
6568
66 // FIXME: width and height should be defined according to the
67 // application window's aspect ratio.
68 width: (application.stage === ApplicationInfo.MainStage && __sideStageEnabled) ?
69 units.gu(22) : units.gu(11)
70 height: (__sideStageEnabled) ? units.gu(22) : units.gu(19)
71 radius: "medium"
72 image: applicationImage
73 }
74
75 ApplicationImage {
76 id: applicationImage
77 source: ApplicationManager.findApplication((application) ? application.appId : "")
78 width: shapedApplicationImage.width
79 height: shapedApplicationImage.height
80 }69 }
8170
82 UbuntuShape {71 UbuntuShape {
8372
=== modified file 'qml/Dash/Apps/RunningApplicationsGrid.qml'
--- qml/Dash/Apps/RunningApplicationsGrid.qml 2013-11-29 08:57:13 +0000
+++ qml/Dash/Apps/RunningApplicationsGrid.qml 2014-01-22 10:43:18 +0000
@@ -18,6 +18,7 @@
18import "../../Components"18import "../../Components"
1919
20import Ubuntu.Gestures 0.120import Ubuntu.Gestures 0.1
21import Unity.Application 0.1
2122
22ResponsiveFlowView {23ResponsiveFlowView {
23 id: root24 id: root
@@ -25,13 +26,7 @@
2526
26 signal updateScreenshots27 signal updateScreenshots
27 property alias enableHeightBehavior: heightBehaviour.enabled28 property alias enableHeightBehavior: heightBehaviour.enabled
28 property bool enableHeightBehaviorOnNextCreation: firstModel.count + secondModel.count == 029 property bool enableHeightBehaviorOnNextCreation: model.count === 0
29
30 Connections {
31 target: shell
32 onDashShownChanged: if (shell.dashShown && shell.stageScreenshotsReady) updateScreenshots();
33 onStageScreenshotsReadyChanged: if (shell.dashShown && shell.stageScreenshotsReady) updateScreenshots();
34 }
3530
36 Behavior on height {31 Behavior on height {
37 id: heightBehaviour32 id: heightBehaviour
@@ -40,13 +35,7 @@
40 }35 }
4136
42 Connections {37 Connections {
43 target: root.firstModel38 target: root.model
44 onCountChanged: {
45 heightBehaviour.enabled = true;
46 }
47 }
48 Connections {
49 target: root.secondModel
50 onCountChanged: {39 onCountChanged: {
51 heightBehaviour.enabled = true;40 heightBehaviour.enabled = true;
52 }41 }
@@ -85,17 +74,13 @@
85 root.terminationModeEnabled = true74 root.terminationModeEnabled = true
86 }75 }
87 onRequestedApplicationTermination: {76 onRequestedApplicationTermination: {
88 shell.applicationManager.stopApplication(model.appId)77 ApplicationManager.stopApplication(model.appId)
89 }78 }
90 onRequestedApplicationActivation: {79 onRequestedApplicationActivation: {
91 shell.activateApplication(model.appId)80 ApplicationManager.focusApplication(model.appId)
92 }81 }
9382
94 terminationModeEnabled: root.terminationModeEnabled83 terminationModeEnabled: root.terminationModeEnabled
95
96 Component.onCompleted: {
97 root.updateScreenshots.connect(updateScreenshotFromCache);
98 }
99 }84 }
100 }85 }
10186
10287
=== modified file 'qml/Dash/DashApps.qml'
--- qml/Dash/DashApps.qml 2013-12-02 13:23:28 +0000
+++ qml/Dash/DashApps.qml 2014-01-22 10:43:18 +0000
@@ -17,6 +17,7 @@
17import QtQuick 2.017import QtQuick 2.0
18import Ubuntu.Components 0.118import Ubuntu.Components 0.1
19import Utils 0.119import Utils 0.1
20import Unity.Application 0.1
20import "../Components"21import "../Components"
21import "../Components/ListItems"22import "../Components/ListItems"
22import "Apps"23import "Apps"
@@ -25,10 +26,6 @@
25 id: scopeView26 id: scopeView
26 objectName: "DashApps"27 objectName: "DashApps"
2728
28 // FIXME: a way to aggregate these models would be ideal
29 property var mainStageApplicationsModel: shell.applicationManager.mainStageApplications
30 property var sideStageApplicationModel: shell.applicationManager.sideStageApplications
31
32 ListModel {29 ListModel {
33 id: dummyVisibilityModifier30 id: dummyVisibilityModifier
3431
@@ -38,19 +35,16 @@
38 SortFilterProxyModel {35 SortFilterProxyModel {
39 id: runningApplicationsModel36 id: runningApplicationsModel
4037
41 property var firstModel: mainStageApplicationsModel
42 property var secondModel: sideStageApplicationModel
43 property bool canEnableTerminationMode: scopeView.isCurrent38 property bool canEnableTerminationMode: scopeView.isCurrent
4439
45 model: dummyVisibilityModifier40 model: ApplicationManager
46 filterRole: 041 filterRole: 0
47 filterRegExp: invertMatch ? ((mainStageApplicationsModel.count === 0 &&42 filterRegExp: invertMatch ? (ApplicationManager.count === 0 ? RegExp("running-apps") : RegExp("")) : RegExp("disabled")
48 sideStageApplicationModel.count === 0) ? RegExp("running-apps") : RegExp("")) : RegExp("disabled")
49 invertMatch: scopeView.scope.searchQuery.length == 043 invertMatch: scopeView.scope.searchQuery.length == 0
50 }44 }
5145
52 onScopeChanged: {46 onScopeChanged: {
53 scopeView.scope.categories.overrideResults("recent", runningApplicationsModel);47 scopeView.scope.categories.overrideResults("recent", runningApplicationsModel);
54 enableHeightBehaviorOnNextCreation = (mainStageApplicationsModel.count + sideStageApplicationModel.count == 0)48 enableHeightBehaviorOnNextCreation = ApplicationManager.count === 0
55 }49 }
56}50}
5751
=== modified file 'qml/Dash/GenericScopeView.qml'
--- qml/Dash/GenericScopeView.qml 2014-01-07 17:06:01 +0000
+++ qml/Dash/GenericScopeView.qml 2014-01-22 10:43:18 +0000
@@ -159,8 +159,7 @@
159 }159 }
160 if (source.toString().indexOf("Apps/RunningApplicationsGrid.qml") != -1) {160 if (source.toString().indexOf("Apps/RunningApplicationsGrid.qml") != -1) {
161 // TODO: the running apps grid doesn't support standard scope results model yet161 // TODO: the running apps grid doesn't support standard scope results model yet
162 item.firstModel = Qt.binding(function() { return results.firstModel })162 item.model = Qt.binding(function() { return results.model })
163 item.secondModel = Qt.binding(function() { return results.secondModel })
164 item.canEnableTerminationMode = Qt.binding(function() { return scopeView.isCurrent })163 item.canEnableTerminationMode = Qt.binding(function() { return scopeView.isCurrent })
165 } else {164 } else {
166 item.model = Qt.binding(function() { return results })165 item.model = Qt.binding(function() { return results })
167166
=== modified file 'qml/Shell.qml'
--- qml/Shell.qml 2014-01-02 08:21:56 +0000
+++ qml/Shell.qml 2014-01-22 10:43:18 +0000
@@ -49,20 +49,22 @@
49 readonly property real panelHeight: panel.panelHeight49 readonly property real panelHeight: panel.panelHeight
5050
51 property bool dashShown: dash.shown51 property bool dashShown: dash.shown
52 property bool stageScreenshotsReady: {52
53 if (sideStage.shown) {53 function activateApplication(appId) {
54 if (mainStage.applications.count > 0) {54 if (ApplicationManager.findApplication(appId)) {
55 return mainStage.usingScreenshots && sideStage.usingScreenshots;55 print("Shell.qml: activating app", appId);
56 } else {56 ApplicationManager.activateApplication(appId);
57 return sideStage.usingScreenshots;
58 }
59 } else {57 } else {
60 return mainStage.usingScreenshots;58 print("starting app", appId);
59
60 // FIXME:
61// var execFlags = sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
62 var execFlags = ApplicationManager.ForceMainStage;
63
64 ApplicationManager.startApplication(appId, execFlags);
61 }65 }
62 }66 }
6367
64 property var applicationManager: ApplicationManagerWrapper {}
65
66 Binding {68 Binding {
67 target: LauncherModel69 target: LauncherModel
68 property: "applicationManager"70 property: "applicationManager"
@@ -71,49 +73,6 @@
7173
72 Component.onCompleted: {74 Component.onCompleted: {
73 Theme.name = "Ubuntu.Components.Themes.SuruGradient"75 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
74
75 applicationManager.sideStageEnabled = Qt.binding(function() { return sideStage.enabled })
76
77 // FIXME: if application focused before shell starts, shell draws on top of it only.
78 // We should detect already running applications on shell start and bring them to the front.
79 applicationManager.unfocusCurrentApplication();
80 }
81
82 readonly property bool applicationFocused: !!applicationManager.mainStageFocusedApplication
83 || !!applicationManager.sideStageFocusedApplication
84 // Used for autopilot testing.
85 readonly property string currentFocusedAppId: ApplicationManager.focusedApplicationId
86
87 readonly property bool fullscreenMode: {
88 if (greeter.shown || lockscreen.shown) {
89 return false;
90 } else if (mainStage.usingScreenshots) { // Window Manager animating so want to re-evaluate fullscreen mode
91 return mainStage.switchingFromFullscreenToFullscreen;
92 } else if (applicationManager.mainStageFocusedApplication) {
93 return applicationManager.mainStageFocusedApplication.fullscreen;
94 } else {
95 return false;
96 }
97 }
98
99 function activateApplication(appId, argument) {
100 if (applicationManager) {
101 // For newly started applications, as it takes them time to draw their first frame
102 // we add a delay before we hide the animation screenshots to compensate.
103 var addDelay = !applicationManager.getApplicationFromDesktopFile(appId);
104
105 var application;
106 application = applicationManager.activateApplication(appId, argument);
107 if (application == null) {
108 return;
109 }
110 if (application.stage == ApplicationInfo.MainStage || !sideStage.enabled) {
111 mainStage.activateApplication(appId, addDelay);
112 } else {
113 sideStage.activateApplication(appId, addDelay);
114 }
115 stages.show();
116 }
117 }76 }
11877
119 GSettings {78 GSettings {
@@ -161,19 +120,19 @@
161 // Whether the underlay is fully covered by opaque UI elements.120 // Whether the underlay is fully covered by opaque UI elements.
162 property bool fullyCovered: panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth121 property bool fullyCovered: panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth
163122
164 readonly property bool applicationRunning: ((mainStage.applications && mainStage.applications.count > 0)123 readonly property bool applicationRunning: ApplicationManager.focusedApplicationId.length > 0
165 || (sideStage.applications && sideStage.applications.count > 0))124 onApplicationRunningChanged: print("***************+ application running", applicationRunning)
166125
167 // Whether the user should see the topmost application surface (if there's one at all).126 // Whether the user should see the topmost application surface (if there's one at all).
168 readonly property bool applicationSurfaceShouldBeSeen: applicationRunning && !stages.fullyHidden127 readonly property bool applicationSurfaceShouldBeSeen: applicationRunning && !stages.painting
169 && !mainStage.usingScreenshots // but want sideStage animating over app surface128
170129 // NB! Application surfaces are stacked behind the shell one. So they can only be seen by the user
171
172
173 // NB! Application surfaces are stacked behing the shell one. So they can only be seen by the user
174 // through the translucent parts of the shell surface.130 // through the translucent parts of the shell surface.
175 visible: !fullyCovered && !applicationSurfaceShouldBeSeen131 visible: !fullyCovered && !applicationSurfaceShouldBeSeen
176132
133 onVisibleChanged: print("hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", visible, fullyCovered, applicationSurfaceShouldBeSeen,
134 applicationRunning, stages.fullyHidden, stages.painting)
135
177 CrossFadeImage {136 CrossFadeImage {
178 id: backgroundImage137 id: backgroundImage
179 objectName: "backgroundImage"138 objectName: "backgroundImage"
@@ -197,12 +156,6 @@
197 hides: [stages, launcher, panel.indicators]156 hides: [stages, launcher, panel.indicators]
198 shown: disappearingAnimationProgress !== 1.0157 shown: disappearingAnimationProgress !== 1.0
199 enabled: disappearingAnimationProgress === 0.0 && edgeDemo.dashEnabled158 enabled: disappearingAnimationProgress === 0.0 && edgeDemo.dashEnabled
200 // FIXME: unfocus all applications when going back to the dash
201 onEnabledChanged: {
202 if (enabled) {
203 shell.applicationManager.unfocusCurrentApplication()
204 }
205 }
206159
207 anchors {160 anchors {
208 fill: parent161 fill: parent
@@ -233,8 +186,7 @@
233 x: launcher.progress186 x: launcher.progress
234 Behavior on x {SmoothedAnimation{velocity: 600}}187 Behavior on x {SmoothedAnimation{velocity: 600}}
235188
236 property real showProgress:189 property real showProgress: MathUtils.clamp(1 - (x + stages.x) / shell.width, 0, 1)
237 MathUtils.clamp(1 - (x + stages.x) / shell.width, 0, 1)
238190
239 Showable {191 Showable {
240 id: stages192 id: stages
@@ -244,6 +196,9 @@
244196
245 property bool fullyShown: shown && x == 0 && parent.x == 0197 property bool fullyShown: shown && x == 0 && parent.x == 0
246 property bool fullyHidden: !shown && x == width198 property bool fullyHidden: !shown && x == width
199
200 property bool painting: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.painting : false
201
247 available: !greeter.shown202 available: !greeter.shown
248 hides: [panel.indicators]203 hides: [panel.indicators]
249 shown: false204 shown: false
@@ -254,128 +209,57 @@
254 width: parent.width209 width: parent.width
255 height: parent.height210 height: parent.height
256211
257 // close the stages when no focused application remains212 property string lastFocusedAppId
258 Connections {213 onShownChanged: {
259 target: shell.applicationManager214 print("stages shown", shown)
260 onMainStageFocusedApplicationChanged: stages.closeIfNoApplications()215 if (shown) {
261 onSideStageFocusedApplicationChanged: stages.closeIfNoApplications()216 if (!ApplicationManager.focusedApplicationId && lastFocusedAppId) {
262 ignoreUnknownSignals: true217 ApplicationManager.focusApplication(lastFocusedAppId);
263 }218 }
264219 } else {
265 function closeIfNoApplications() {220 lastFocusedAppId = ApplicationManager.focusedApplicationId;
266 if (!shell.applicationManager.mainStageFocusedApplication221 ApplicationManager.unfocusCurrentApplication();
267 && !shell.applicationManager.sideStageFocusedApplication222 }
268 && shell.applicationManager.mainStageApplications.count == 0223 }
269 && shell.applicationManager.sideStageApplications.count == 0) {224
270 stages.hide();225 Connections {
271 }226 target: ApplicationManager
272 }227 onFocusedApplicationIdChanged: {
273228 if (ApplicationManager.focusedApplicationId.length > 0) {
274 // show the stages when an application gets the focus229 print("should show stages")
275 Connections {230 stages.show();
276 target: shell.applicationManager231 } else {
277 onMainStageFocusedApplicationChanged: {232 stages.hide();
278 if (shell.applicationManager.mainStageFocusedApplication) {233 }
279 mainStage.show();234 }
280 stages.show();235
281 }236 onApplicationAdded: {
282 }237 stages.show();
283 onSideStageFocusedApplicationChanged: {238 }
284 if (shell.applicationManager.sideStageFocusedApplication) {239 }
285 sideStage.show();240
286 stages.show();241 Loader {
287 }242 id: applicationsDisplayLoader
288 }
289 ignoreUnknownSignals: true
290 }
291
292 Stage {
293 id: mainStage
294
295 anchors.fill: parent243 anchors.fill: parent
296 fullyShown: stages.fullyShown244
297 fullyHidden: stages.fullyHidden245// source: "Stages/StageWithSideStage.qml"
298 shouldUseScreenshots: !fullyShown246 source: "Stages/PhoneStage.qml"
299 rightEdgeEnabled: !sideStage.enabled247
300248 Binding {
301 applicationManager: shell.applicationManager249 target: applicationsDisplayLoader.item
302 rightEdgeDraggingAreaWidth: shell.edgeSize250 property: "moving"
303 normalApplicationY: shell.panelHeight251 value: !stages.fullyShown
304252 }
305 shown: true253 Binding {
306 function show() {254 target: applicationsDisplayLoader.item
307 stages.show();255 property: "shown"
308 }256 value: stages.shown
309 function hide() {257 }
310 }258 Binding {
311259 target: applicationsDisplayLoader.item
312 // FIXME: workaround the fact that focusing a main stage application260 property: "dragAreaWidth"
313 // raises its surface on top of all other surfaces including the ones261 value: shell.edgeSize
314 // that belong to side stage applications.262 }
315 onFocusedApplicationChanged: {
316 if (focusedApplication && sideStage.focusedApplication && sideStage.fullyShown) {
317 shell.applicationManager.focusApplication(sideStage.focusedApplication);
318 }
319 }
320 }
321
322 SideStage {
323 id: sideStage
324
325 applicationManager: shell.applicationManager
326 rightEdgeDraggingAreaWidth: shell.edgeSize
327 normalApplicationY: shell.panelHeight
328
329 onShownChanged: {
330 if (!shown && mainStage.applications.count == 0) {
331 stages.hide();
332 }
333 }
334 // FIXME: when hiding the side stage, refocus the main stage
335 // application so that it goes in front of the side stage
336 // application and hides it
337 onFullyShownChanged: {
338 if (!fullyShown && stages.fullyShown && sideStage.focusedApplication != null) {
339 shell.applicationManager.focusApplication(mainStage.focusedApplication);
340 }
341 }
342
343 enabled: shell.width >= units.gu(60)
344 visible: enabled
345 fullyShown: stages.fullyShown && shown
346 && sideStage[sideStageRevealer.boundProperty] == sideStageRevealer.openedValue
347 shouldUseScreenshots: !fullyShown || mainStage.usingScreenshots || sideStageRevealer.pressed
348
349 available: !greeter.shown && !lockscreen.shown && enabled
350 hides: [launcher, panel.indicators]
351 shown: false
352 showAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.openedValue; easing.type: Easing.OutQuint }
353 hideAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.closedValue; easing.type: Easing.OutQuint }
354
355 width: units.gu(40)
356 height: stages.height
357 handleExpanded: sideStageRevealer.pressed
358 }
359
360 Revealer {
361 id: sideStageRevealer
362
363 enabled: mainStage.applications.count > 0 && sideStage.applications.count > 0
364 && sideStage.available
365 direction: Qt.RightToLeft
366 openedValue: parent.width - sideStage.width
367 hintDisplacement: units.gu(3)
368 /* The size of the sidestage handle needs to be bigger than the
369 typical size used for edge detection otherwise it is really
370 hard to grab.
371 */
372 handleSize: sideStage.shown ? units.gu(4) : shell.edgeSize
373 closedValue: parent.width + sideStage.handleSizeCollapsed
374 target: sideStage
375 x: parent.width - width
376 width: sideStage.width + handleSize * 0.7
377 height: sideStage.height
378 orientation: Qt.Horizontal
379 }263 }
380264
381 DragHandle {265 DragHandle {
@@ -388,7 +272,7 @@
388 width: shell.edgeSize272 width: shell.edgeSize
389 direction: Direction.Leftwards273 direction: Direction.Leftwards
390 enabled: greeter.showProgress == 0 && edgeDemo.dashEnabled274 enabled: greeter.showProgress == 0 && edgeDemo.dashEnabled
391 property bool haveApps: mainStage.applications.count > 0 || sideStage.applications.count > 0275 property bool haveApps: ApplicationManager.count > 0
392276
393 maxTotalDragDistance: haveApps ? parent.width : parent.width * 0.7277 maxTotalDragDistance: haveApps ? parent.width : parent.width * 0.7
394 // Make autocompletion impossible when !haveApps278 // Make autocompletion impossible when !haveApps
@@ -473,23 +357,6 @@
473 property var previousMainApp: null357 property var previousMainApp: null
474 property var previousSideApp: null358 property var previousSideApp: null
475359
476 function removeApplicationFocus() {
477 greeter.previousMainApp = applicationManager.mainStageFocusedApplication;
478 greeter.previousSideApp = applicationManager.sideStageFocusedApplication;
479 applicationManager.unfocusCurrentApplication();
480 }
481
482 function restoreApplicationFocus() {
483 if (greeter.previousMainApp) {
484 applicationManager.focusApplication(greeter.previousMainApp);
485 greeter.previousMainApp = null;
486 }
487 if (greeter.previousSideApp) {
488 applicationManager.focusApplication(greeter.previousSideApp);
489 greeter.previousSideApp = null;
490 }
491 }
492
493 onShownChanged: {360 onShownChanged: {
494 if (shown) {361 if (shown) {
495 lockscreen.reset();362 lockscreen.reset();
@@ -500,9 +367,6 @@
500 greeter.selected(0);367 greeter.selected(0);
501 }368 }
502 greeter.forceActiveFocus();369 greeter.forceActiveFocus();
503 removeApplicationFocus();
504 } else {
505 restoreApplicationFocus();
506 }370 }
507 }371 }
508372
@@ -519,34 +383,11 @@
519 launcher.tease();383 launcher.tease();
520 }384 }
521 }385 }
522
523 Connections {
524 target: applicationManager
525 ignoreUnknownSignals: true
526 // If any app is focused when greeter is open, it's due to a user action
527 // like a snap decision (say, an incoming call).
528 // TODO: these should be protected to only unlock for certain applications / certain usecases
529 // potentially only in connection with a notification.
530 onMainStageFocusedApplicationChanged: {
531 if (greeter.shown && applicationManager.mainStageFocusedApplication) {
532 greeter.previousMainApp = null // make way for new focused app
533 greeter.previousSideApp = null
534 greeter.hide()
535 }
536 }
537 onSideStageFocusedApplicationChanged: {
538 if (greeter.shown && applicationManager.sideStageFocusedApplication) {
539 greeter.previousMainApp = null // make way for new focused app
540 greeter.previousSideApp = null
541 greeter.hide()
542 }
543 }
544 }
545 }386 }
546387
547 InputFilterArea {388 InputFilterArea {
548 anchors.fill: parent389 anchors.fill: parent
549 blockInput: !applicationFocused || greeter.shown || lockscreen.shown || launcher.shown390 blockInput: ApplicationManager.focusedApplicationId.length === 0 || greeter.shown || lockscreen.shown || launcher.shown
550 || panel.indicators.shown || hud.shown391 || panel.indicators.shown || hud.shown
551 }392 }
552393
@@ -595,7 +436,9 @@
595 available: edgeDemo.panelEnabled436 available: edgeDemo.panelEnabled
596 contentEnabled: edgeDemo.panelContentEnabled437 contentEnabled: edgeDemo.panelContentEnabled
597 }438 }
598 fullscreenMode: shell.fullscreenMode439 property string focusedAppId: ApplicationManager.focusedApplicationId
440 property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
441 fullscreenMode: focusedApplication && focusedApplication.fullscreen && !greeter.shown && !lockscreen.shown
599 searchVisible: !greeter.shown && !lockscreen.shown && dash.shown442 searchVisible: !greeter.shown && !lockscreen.shown && dash.shown
600443
601 InputFilterArea {444 InputFilterArea {
@@ -621,9 +464,8 @@
621 hideAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: hudRevealer.closedValue; easing.type: Easing.Linear }464 hideAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: hudRevealer.closedValue; easing.type: Easing.Linear }
622465
623 Connections {466 Connections {
624 target: shell.applicationManager467 target: ApplicationManager
625 onMainStageFocusedApplicationChanged: hud.hide()468 onFocusedApplicationIdChanged: hud.hide()
626 onSideStageFocusedApplicationChanged: hud.hide()
627 }469 }
628 }470 }
629471
@@ -648,7 +490,7 @@
648 theHud: hud490 theHud: hud
649 anchors.fill: parent491 anchors.fill: parent
650 enabled: hud.available492 enabled: hud.available
651 applicationIsOnForeground: applicationFocused493 applicationIsOnForeground: ApplicationManager.focusedApplicationId
652 }494 }
653495
654 InputFilterArea {496 InputFilterArea {
@@ -774,14 +616,14 @@
774 anchors.bottom: parent.bottom616 anchors.bottom: parent.bottom
775 anchors.left: parent.left617 anchors.left: parent.left
776 anchors.right: parent.right618 anchors.right: parent.right
777 height: shell.applicationManager ? shell.applicationManager.keyboardHeight : 0619 height: ApplicationManager.keyboardVisible ? ApplicationManager.keyboardHeight : 0
778620
779 enabled: shell.applicationManager && shell.applicationManager.keyboardVisible621 enabled: ApplicationManager.keyboardVisible
780 }622 }
781623
782 Label {624 Label {
783 anchors.centerIn: parent625 anchors.centerIn: parent
784 visible: applicationManager.fake626 visible: ApplicationManager.fake ? ApplicationManager.fake : false
785 text: "EARLY ALPHA\nNOT READY FOR USE"627 text: "EARLY ALPHA\nNOT READY FOR USE"
786 color: "lightgrey"628 color: "lightgrey"
787 opacity: 0.2629 opacity: 0.2
788630
=== added directory 'qml/Stages'
=== added file 'qml/Stages/PhoneStage.qml'
--- qml/Stages/PhoneStage.qml 1970-01-01 00:00:00 +0000
+++ qml/Stages/PhoneStage.qml 2014-01-22 10:43:18 +0000
@@ -0,0 +1,574 @@
1import QtQuick 2.0
2import Ubuntu.Components 0.1
3import Ubuntu.Gestures 0.1
4import Unity.Application 0.1
5import Utils 0.1
6import "../Components"
7
8/*
9
10*/
11
12Item {
13 id: root
14
15 // Controls to be set from outside
16 property bool shown: false
17 property bool moving: false
18 property int dragAreaWidth
19
20 // State information propagated to the outside
21 readonly property bool painting: mainScreenshotImage.visible || fadeInScreenshotImage.visible || appSplash.visible
22 onPaintingChanged: print("**********************+ painting changed", painting)
23
24 onMovingChanged: {
25 if (moving) {
26 priv.requestNewScreenshot();
27 } else {
28 mainScreenshotImage.visible = false;
29 }
30 }
31
32 Connections {
33 target: ApplicationManager
34
35 onFocusRequested: {
36 priv.switchToApp(appId);
37 }
38
39 onFocusedApplicationIdChanged: {
40 if (ApplicationManager.focusedApplicationId.length > 0) {
41 if (priv.secondApplicationStarting || priv.applicationStarting) {
42 appSplashTimer.start();
43 } else {
44 mainScreenshotImage.src = ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).screenshot
45 }
46 }
47 }
48
49 onApplicationAdded: {
50 if (!priv.focusedApplication) {
51 mainScreenshotImage.src = "";
52 mainScreenshotImage.visible = false;
53 priv.applicationStarting = true;
54 } else {
55 mainScreenshotImage.src = "foobar";
56 priv.newFocusedAppId = appId;
57 priv.secondApplicationStarting = true;
58 priv.requestNewScreenshot();
59 }
60 }
61 }
62
63 QtObject {
64 id: priv
65
66 property string focusedAppId: ApplicationManager.focusedApplicationId
67 property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
68 property url focusedScreenshot: focusedApplication ? focusedApplication.screenshot : ""
69
70 property bool waitingForScreenshot: false
71
72 property bool applicationStarting: false
73 property bool secondApplicationStarting: false
74
75 property string newFocusedAppId
76
77 onFocusedScreenshotChanged: {
78 if (root.moving && priv.waitingForScreenshot) {
79 mainScreenshotImage.anchors.leftMargin = 0;
80 mainScreenshotImage.src = ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).screenshot;
81 mainScreenshotImage.visible = true;
82 } else if (priv.secondApplicationStarting && priv.waitingForScreenshot) {
83 applicationSwitchingAnimation.start();
84 }
85 waitingForScreenshot = false;
86 }
87
88 function requestNewScreenshot() {
89 waitingForScreenshot = true;
90 ApplicationManager.updateScreenshot(ApplicationManager.focusedApplicationId);
91 }
92
93 function switchToApp(appId) {
94 priv.newFocusedAppId = appId;
95 applicationSwitchingAnimation.start();
96 grantFocusTimer.start();
97 }
98
99 }
100
101 // FIXME: the signal connection seems to get lost with the fake application manager.
102 // Check with Qt 5.2, see if we can remove this Connections object
103 Connections {
104 target: priv.focusedApplication
105 onScreenshotChanged: priv.focusedScreenshot = priv.focusedApplication.screenshot
106 }
107
108 Timer {
109 id: grantFocusTimer
110 // Delay the actual switch to be covered by the animation for sure.
111 // 1) If we switch before starting the animation, the Mir event loop paints before the Qt event loop => flickering
112 // 2) If we do the switch after the animation, the panel wouldn't fade in early enough.
113 interval: UbuntuAnimation.SlowDuration / 4
114 repeat: false
115 onTriggered: {
116 ApplicationManager.focusApplication(priv.newFocusedAppId);
117 }
118 }
119
120 Timer {
121 id: appSplashTimer
122 // This is to show the splash screen a bit longer.
123 // Mir signals us that the newly started app has gotten focus before it paints something on the screen
124 // This would result in the old app surface becoming visible for a bit.
125 // FIXME: change appManager to only change the focusedApplicationId when the surface is ready to be shown.
126 interval: 1500
127 repeat: false
128 onTriggered: {
129 priv.applicationStarting = false;
130 priv.secondApplicationStarting = false;
131 }
132 }
133
134 SequentialAnimation {
135 id: applicationSwitchingAnimation
136 // setup
137 PropertyAction { target: mainScreenshotImage; property: "anchors.leftMargin"; value: 0 }
138 // PropertyAction seems to fail when secondApplicationStarting and we didn't have another screenshot before
139 ScriptAction { script: mainScreenshotImage.src = priv.focusedScreenshot }
140 PropertyAction { target: mainScreenshotImage; property: "visible"; value: true }
141 PropertyAction { target: fadeInScreenshotImage; property: "source"; value: ApplicationManager.findApplication(priv.newFocusedAppId).screenshot }
142 PropertyAction { target: fadeInScreenshotImage; property: "visible"; value: true }
143 PropertyAction { target: fadeInScreenshotImage; property: "opacity"; value: 0 }
144 PropertyAction { target: fadeInScreenshotImage; property: "scale"; value: .8 }
145
146
147 // The actual animation
148 ParallelAnimation {
149 UbuntuNumberAnimation { target: mainScreenshotImage; property: "anchors.leftMargin"; to: root.width; duration: UbuntuAnimation.SlowDuration }
150 UbuntuNumberAnimation { target: fadeInScreenshotImage; property: "opacity"; to: 1; duration: UbuntuAnimation.SlowDuration }
151 UbuntuNumberAnimation { target: fadeInScreenshotImage; property: "scale"; to: 1; duration: UbuntuAnimation.SlowDuration }
152 }
153
154 // restore stuff
155 PropertyAction { target: fadeInScreenshotImage; property: "visible"; value: false }
156 PropertyAction { target: mainScreenshotImage; property: "visible"; value: false }
157 }
158
159 // FIXME: Drop this and make the imageprovider show a splashscreen instead
160 Rectangle {
161 id: appSplash2
162 anchors.fill: parent
163 color: "white"
164 visible: priv.secondApplicationStarting
165 }
166 Image {
167 id: fadeInScreenshotImage
168 anchors { left: parent.left; bottom: parent.bottom }
169 width: parent.width
170 scale: .7
171 visible: false
172 }
173
174 Rectangle {
175 id: appSplash
176 anchors.fill: parent
177 color: "white"
178 visible: priv.applicationStarting
179 }
180 Image {
181 id: mainScreenshotImage
182 anchors { left: parent.left; bottom: parent.bottom }
183 width: parent.width
184
185 property string src
186 source: src
187 visible: false
188 }
189
190 EdgeDragArea {
191 id: coverFlipDragArea
192 direction: Direction.Leftwards
193
194 //enabled: root.available
195 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
196 width: root.dragAreaWidth
197
198 onTouchXChanged: {
199 if (!dragging && !priv.waitingForScreenshot) {
200 priv.requestNewScreenshot();
201 }
202 if (dragging && !priv.waitingForScreenshot) {
203 coverFlickable.contentX = -touchX
204 }
205 }
206
207 onDraggingChanged: {
208 if (!dragging) {
209 coverFlip.snap();
210 }
211 }
212 }
213
214 Rectangle {
215 id: coverFlipBackground
216 anchors.fill: parent
217 color: "black"
218 visible: coverFlip.visible
219 }
220
221 InputFilterArea {
222 anchors.fill: root
223 blockInput: coverFlip.visible
224 }
225
226 Flickable {
227 id: coverFlickable
228 anchors.fill: root
229 contentHeight: height
230 contentWidth: width * 2 + ((ApplicationManager.count - 2) * root.width * coverFlip.tileDistance * 1.5)
231 flickableDirection: Qt.Horizontal
232 enabled: coverFlip.visible
233
234 property bool passedFirstStage: false
235
236 onContentXChanged: {
237 if (coverFlickable.passedFirstStage && contentX < width * coverFlip.progressMarker1) {
238 contentX = width * coverFlip.progressMarker1;
239 return;
240 }
241 var progress = contentX / width
242 if (progress > coverFlip.progressMarker1) {
243 coverFlickable.passedFirstStage = true;
244 }
245 coverFlip.progress = progress;
246 }
247
248 Row {
249 id: coverFlip
250 height: parent.height
251 // The MouseAreas on the AppImages need to be children of the flickable in order to make focus stealing
252 // for flicking vs. clicking work correctly.
253 // However, for the animation calculations to become easier we don't want the row to move so we don't
254 // always have to take contentX into account. So lets just compensate the flickable's movement here.
255 x: coverFlickable.contentX
256 visible: progress > 0
257
258 property real progress: 0
259 property real startAngle: 45
260 property int endAngle: 10
261
262 property real maxScale: 1.4
263 property real minScale: .6
264
265 // Markers: relative screen position from left to right
266 // marks the line where first application is finished moving in from the right
267 property real progressMarker1: 0.5
268
269 property real tileDistance: 0.1
270
271 property bool animatingBack: false
272
273 property real tileWidth: root.width
274
275 property real oldProgress: 0
276 onProgressChanged: {
277 if (coverFlipDragArea.dragging) {
278 if (oldProgress < coverFlip.progressMarker1 && progress >= coverFlip.progressMarker1) {
279 ApplicationManager.move(0, 1)
280 } else if (oldProgress >= coverFlip.progressMarker1 && progress < coverFlip.progressMarker1) {
281 ApplicationManager.move(0, 1)
282 }
283 }
284 oldProgress = progress;
285 }
286
287 function snap() {
288 if (coverFlip.progress < 0.25) {
289 snapAnimation.targetContentX = 0
290 snapAnimation.targetAppId = ApplicationManager.get(0).appId;
291 } else if (coverFlip.progress < coverFlip.progressMarker1) {
292 snapAnimation.targetContentX = root.width * coverFlip.progressMarker1
293 snapAnimation.targetAppId = ApplicationManager.get(1).appId;
294 } else if (coverFlip.progress < 0.6) {
295 snapAnimation.targetContentX = root.width * coverFlip.progressMarker1
296 snapAnimation.targetAppId = ApplicationManager.get(0).appId;
297 } else {
298 if (ApplicationManager.count == 3) {
299 snapAnimation.targetContentX = root.width * 1.1;
300 } else {
301 snapAnimation.targetContentX = root.width * 1.25;
302 }
303 snapAnimation.targetAppId = "";
304 }
305 snapAnimation.start();
306 }
307
308 function selectItem(index) {
309 tileRepeater.itemAt(index).select();
310 }
311
312 SequentialAnimation {
313 id: snapAnimation
314 property int targetContentX: 0
315 property string targetAppId
316
317 UbuntuNumberAnimation {
318 target: coverFlickable
319 properties: "contentX"
320 to: snapAnimation.targetContentX
321 duration: UbuntuAnimation.SnapDuration
322 }
323 ScriptAction {
324 script: {
325 if (snapAnimation.targetAppId) {
326 coverFlickable.passedFirstStage = false;
327 ApplicationManager.focusApplication(snapAnimation.targetAppId);
328 }
329 if (snapAnimation.targetContentX == root.width * coverFlip.progressMarker1) {
330 coverFlickable.contentX = 0;
331 }
332 }
333 }
334 }
335
336 Repeater {
337 id: tileRepeater
338 model: ApplicationManager
339
340 Item {
341 id: appItem
342 height: parent.height
343 width: coverFlip.tileWidth
344
345 // This is the main progress, of the gesture, the same for every tile
346 property real progress: coverFlip.progress
347 // The progress, translated for the second stage of the animation, after the first app switch has happened
348 // Additionally it speeds it up a bit, depending on the distance of the tile
349 property real translatedProgress: appItem.progress - coverFlip.progressMarker1 - (coverFlip.tileDistance * (index-1))
350
351 // Is this tile selected by a click?
352 property bool isSelected: false
353 // We need to remember some values when app is selected to be able to animate it to the foreground
354 property real selectedXTranslation: 0
355 property real selectedTranslatedProgress: 0
356 property real selectedProgress: 0
357 property real selectedAngle: 0
358 property real selectedXScale: 0
359
360 function select() {
361 appItem.selectedXTranslation = appItem.xTranslation;
362 appItem.selectedAngle = appItem.angle;
363 appItem.selectedXScale = appItem.xScale;
364 appItem.selectedTranslatedProgress = appItem.translatedProgress - coverFlip.progressMarker1;
365 appItem.selectedProgress = appItem.progress - coverFlip.progressMarker1;
366 appItem.isSelected = true;
367 switchToAppAnimation.targetContentX = coverFlip.progressMarker1 * root.width
368 switchToAppAnimation.start();
369 }
370
371 property int xTranslation: {
372 var xTranslate = 0;
373 var minXTranslate = -index * root.width + index * units.dp(3);
374 switch (index) {
375 case 0:
376 if (appItem.progress < coverFlip.progressMarker1) {
377 var progress = appItem.progress
378 var progressDiff = coverFlip.progressMarker1
379 var translateDiff = -root.width * 0.25
380 // progress : progressDiff = translate : translateDiff
381 xTranslate = progress * translateDiff / progressDiff
382 }
383 break;
384 case 1:
385 if (appItem.progress < coverFlip.progressMarker1) {
386 var progress = appItem.progress;
387 var progressDiff = coverFlip.progressMarker1;
388 var translateDiff = -root.width;
389 // progress : progressDiff = translate : translateDiff
390 xTranslate = progress * translateDiff / progressDiff;
391 break;
392 }
393 // Intentionally no break here...
394 default:
395 if (appItem.progress > coverFlip.progressMarker1) {
396 xTranslate = xTranslateEasing.value * xTranslateEasing.period;
397 if (appItem.isSelected) {
398 var translateDiff = root.width * index + appItem.selectedXTranslation
399 var progressDiff = appItem.selectedProgress
400 var progress = progressDiff - (appItem.progress - coverFlip.progressMarker1);
401 // progress : progressDiff = translate : translateDiff
402 var newTranslate = progress * translateDiff / progressDiff;
403
404 xTranslate = appItem.selectedXTranslation - newTranslate;
405 }
406 break;
407 }
408 }
409 return xTranslate;
410 }
411
412 property real angle: {
413 var newAngle = 0;
414 switch (index) {
415 case 0:
416 if (appItem.progress < coverFlip.progressMarker1) {
417 var progress = appItem.progress;
418 var angleDiff = coverFlip.endAngle;
419 var progressDiff = coverFlip.progressMarker1;
420 // progress : progressDiff = angle : angleDiff
421 newAngle = progress * angleDiff / progressDiff;
422 } else {
423 var progress = appItem.progress - coverFlip.progressMarker1;
424 var angleDiff = coverFlip.endAngle;
425 var progressDiff = 1 - coverFlip.progressMarker1;
426 // progress : progressDiff = angle : angleDiff
427 newAngle = progress * angleDiff / progressDiff;
428 newAngle = Math.min(coverFlip.endAngle, newAngle);
429 }
430 break;
431 case 1:
432 if (appItem.progress < coverFlip.progressMarker1) {
433 var progress = coverFlip.progress;
434 var angleDiff = coverFlip.startAngle;
435 var progressDiff = coverFlip.progressMarker1;
436 // progress : progressDiff = angle : angleDiff
437 var angle = progress * angleDiff / progressDiff;
438 newAngle = coverFlip.startAngle - angle;
439 break;
440 }
441 // Intentionally no break here...
442 default:
443 newAngle = coverFlip.startAngle - (angleEasing.value * angleEasing.period);
444 // make sure we stop at the left screen edge
445 newAngle = Math.max(newAngle, coverFlip.endAngle);
446
447 if (appItem.isSelected) {
448// var selectedAngleTranslate = selectedAngleEasing.value * selectedAngleEasing.period
449 var angleDiff = appItem.selectedAngle
450 var progressDiff = appItem.selectedProgress
451 var progress = progressDiff - (appItem.progress - coverFlip.progressMarker1);
452 // progress : progressDiff = angle : angleDiff
453 var selectedAngleTranslate = progress * angleDiff / progressDiff;
454
455 newAngle = appItem.selectedAngle - selectedAngleTranslate;
456 }
457 }
458 return newAngle;
459 }
460
461 property real xScale: {
462 var scale = 1;
463
464 switch (index) {
465 case 0:
466 if (appItem.progress > coverFlip.progressMarker1) {
467 var scaleDiff = coverFlip.maxScale - 1;
468 var progressDiff = 1.5 - coverFlip.progressMarker1;
469 // progress : progressDiff = scale : scaleDiff
470 scale = 1 - (appItem.progress - coverFlip.progressMarker1) * scaleDiff / progressDiff;
471 }
472 break;
473 case 1:
474 if (appItem.progress < coverFlip.progressMarker1) {
475 var scaleDiff = coverFlip.maxScale - 1
476 var progressDiff = coverFlip.progressMarker1
477 // progress : progressDiff = scale : scaleDiff
478 scale = coverFlip.maxScale - (appItem.progress * scaleDiff / progressDiff);
479 break;
480 }
481 // Intentionally no break
482 default:
483 scale = coverFlip.maxScale - scaleEasing.value * scaleEasing.period;
484 if (appItem.isSelected) {
485 var scaleDiff = -(1 - appItem.selectedXScale)
486 var progressDiff = appItem.selectedProgress
487 var progress = progressDiff - (appItem.progress - coverFlip.progressMarker1);
488 // progress : progressDiff = angle : angleDiff
489 var selectedScaleTranslate = progress * scaleDiff / progressDiff;
490
491 scale = appItem.selectedXScale - selectedScaleTranslate;
492 }
493 }
494 return Math.min(coverFlip.maxScale, Math.max(coverFlip.minScale, scale));
495 }
496
497 EasingCurve {
498 id: xTranslateEasing
499 type: EasingCurve.OutQuad
500 period: index * -width
501 progress: appItem.translatedProgress
502 }
503 EasingCurve {
504 id: angleEasing
505 type: EasingCurve.InQuad
506 period: coverFlip.startAngle - coverFlip.endAngle
507 progress: appItem.translatedProgress
508 }
509 EasingCurve {
510 id: scaleEasing
511 type: EasingCurve.Linear
512 period: coverFlip.maxScale - coverFlip.minScale
513 progress: appItem.translatedProgress
514 }
515
516 transform: [
517 Rotation {
518 origin { x: 0; y: coverFlip.height / 2 }
519 axis { x: 0; y: 1; z: 0 }
520 angle: appItem.angle
521 },
522 Translate {
523 x: appItem.xTranslation
524 },
525 Scale {
526 origin { x: appItem.xTranslation; y: root.height / 2 - (root.height - appImage.height)}
527 xScale: appItem.xScale
528 yScale: xScale
529 }
530 ]
531
532 Image {
533 id: dropShadow
534 anchors.fill: appImage
535 anchors.margins: -units.gu(2)
536 source: "graphics/dropshadow.png"
537 }
538 Image {
539 id: appImage
540 anchors { left: parent.left; bottom: parent.bottom }
541 width: root.width
542 source: ApplicationManager.get(index).screenshot
543 scale: 1
544 }
545 MouseArea {
546 anchors.fill: parent
547 onClicked: {
548 appItem.select()
549 }
550 }
551
552 SequentialAnimation {
553 id: switchToAppAnimation
554 property int targetContentX
555 UbuntuNumberAnimation {
556 target: coverFlickable;
557 property: "contentX";
558 to: switchToAppAnimation.targetContentX;
559 duration: UbuntuAnimation.SnapDuration
560 }
561 ScriptAction {
562 script: {
563 ApplicationManager.focusApplication(ApplicationManager.get(index).appId);
564 appItem.isSelected = false;
565 coverFlip.progress = 0;
566 coverFlickable.passedFirstStage = false;
567 }
568 }
569 }
570 }
571 }
572 }
573 }
574}
0575
=== added directory 'qml/Stages/graphics'
=== added file 'qml/Stages/graphics/dropshadow.png'
1Binary files qml/Stages/graphics/dropshadow.png 1970-01-01 00:00:00 +0000 and qml/Stages/graphics/dropshadow.png 2014-01-22 10:43:18 +0000 differ576Binary files qml/Stages/graphics/dropshadow.png 1970-01-01 00:00:00 +0000 and qml/Stages/graphics/dropshadow.png 2014-01-22 10:43:18 +0000 differ
=== modified file 'run_on_device'
--- run_on_device 2013-11-27 11:47:14 +0000
+++ run_on_device 2014-01-22 10:43:18 +0000
@@ -103,6 +103,7 @@
103 ARGS="$ARGS -k"103 ARGS="$ARGS -k"
104 fi104 fi
105105
106 exec_with_ssh "killall -9 dialer-app; killall -9 gallery-app; killall -9 messaging-app; killall -9 address-book-app"
106 exec_with_ssh "stop unity8"107 exec_with_ssh "stop unity8"
107 exec_with_ssh "start maliit-server"108 exec_with_ssh "start maliit-server"
108 exec_with_ssh "cd $CODE_DIR/ && ./run $ARGS -- $RUN_OPTIONS"109 exec_with_ssh "cd $CODE_DIR/ && ./run $ARGS -- $RUN_OPTIONS"
109110
=== modified file 'tests/mocks/Unity/Application/ApplicationInfo.h'
--- tests/mocks/Unity/Application/ApplicationInfo.h 2013-10-11 11:37:04 +0000
+++ tests/mocks/Unity/Application/ApplicationInfo.h 2014-01-22 10:43:18 +0000
@@ -19,6 +19,7 @@
1919
20#include <QObject>20#include <QObject>
21#include <QQmlComponent>21#include <QQmlComponent>
22#include <QDebug>
2223
23class QQuickItem;24class QQuickItem;
2425
@@ -56,6 +57,7 @@
56 { \57 { \
57 if (m_##name != value) { \58 if (m_##name != value) { \
58 m_##name = value; \59 m_##name = value; \
60 qDebug() << "emitting changed" << this << Q_FUNC_INFO; \
59 Q_EMIT name##Changed(); \61 Q_EMIT name##Changed(); \
60 } \62 } \
61 } \63 } \
@@ -74,6 +76,7 @@
74 IMPLEMENT_PROPERTY(fullscreen, Fullscreen, bool)76 IMPLEMENT_PROPERTY(fullscreen, Fullscreen, bool)
75 IMPLEMENT_PROPERTY(imageQml, ImageQml, QString)77 IMPLEMENT_PROPERTY(imageQml, ImageQml, QString)
76 IMPLEMENT_PROPERTY(windowQml, WindowQml, QString)78 IMPLEMENT_PROPERTY(windowQml, WindowQml, QString)
79 IMPLEMENT_PROPERTY(screenshot, Screenshot, QUrl)
7780
78 #undef IMPLEMENT_PROPERTY81 #undef IMPLEMENT_PROPERTY
7982
8083
=== modified file 'tests/mocks/Unity/Application/ApplicationManager.cpp'
--- tests/mocks/Unity/Application/ApplicationManager.cpp 2013-12-17 16:04:47 +0000
+++ tests/mocks/Unity/Application/ApplicationManager.cpp 2014-01-22 10:43:18 +0000
@@ -24,6 +24,9 @@
24#include <QQuickItem>24#include <QQuickItem>
25#include <QQuickView>25#include <QQuickView>
26#include <QQmlComponent>26#include <QQmlComponent>
27#include <QTimer>
28#include <QDateTime>
29#include <QDebug>
2730
28ApplicationManager::ApplicationManager(QObject *parent)31ApplicationManager::ApplicationManager(QObject *parent)
29 : ApplicationManagerInterface(parent)32 : ApplicationManagerInterface(parent)
@@ -63,6 +66,8 @@
63 return app->state();66 return app->state();
64 case RoleFocused:67 case RoleFocused:
65 return app->focused();68 return app->focused();
69 case RoleScreenshot:
70 return app->screenshot();
66 default:71 default:
67 return QVariant();72 return QVariant();
68 }73 }
@@ -75,7 +80,9 @@
75}80}
7681
77ApplicationInfo *ApplicationManager::findApplication(const QString &appId) const {82ApplicationInfo *ApplicationManager::findApplication(const QString &appId) const {
83 qDebug() << "findapp called";
78 for (ApplicationInfo *app : m_runningApplications) {84 for (ApplicationInfo *app : m_runningApplications) {
85 qDebug() << "searching app"<< app->appId();
79 if (app->appId() == appId) {86 if (app->appId() == appId) {
80 return app;87 return app;
81 }88 }
@@ -84,8 +91,10 @@
84}91}
8592
86void ApplicationManager::add(ApplicationInfo *application) {93void ApplicationManager::add(ApplicationInfo *application) {
87 if (!application)94 qDebug() << "add() " << application->appId();
95 if (!application) {
88 return;96 return;
97 }
8998
90 beginInsertRows(QModelIndex(), m_runningApplications.size(), m_runningApplications.size());99 beginInsertRows(QModelIndex(), m_runningApplications.size(), m_runningApplications.size());
91 m_runningApplications.append(application);100 m_runningApplications.append(application);
@@ -171,6 +180,8 @@
171 }180 }
172 add(application);181 add(application);
173182
183 QMetaObject::invokeMethod(this, "focusApplication", Qt::QueuedConnection, Q_ARG(QString, appId));
184
174 return application;185 return application;
175}186}
176187
@@ -182,9 +193,33 @@
182193
183 remove(application);194 remove(application);
184 Q_EMIT focusedApplicationIdChanged();195 Q_EMIT focusedApplicationIdChanged();
196 qDebug() << Q_FUNC_INFO << "emitting focusedAppChanged" << focusedApplicationId();
185 return true;197 return true;
186}198}
187199
200void ApplicationManager::updateScreenshot(const QString &appId)
201{
202 int idx = -1;
203 ApplicationInfo *application = nullptr;
204 for (int i = 0; i < m_availableApplications.count(); ++i) {
205 application = m_availableApplications.at(i);
206 if (application->appId() == appId) {
207 idx = i;
208 break;
209 }
210 }
211
212 if (idx == -1) {
213 return;
214 }
215
216 qDebug() << "setting new screenshot" << application->screenshot() << application;
217 application->setScreenshot(QString("image://application/%1/%2").arg(appId).arg(QDateTime::currentMSecsSinceEpoch()));
218 qDebug() << "set new screenshot" << application->screenshot();
219 QModelIndex appIndex = index(idx);
220 Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << RoleScreenshot);
221}
222
188QString ApplicationManager::focusedApplicationId() const {223QString ApplicationManager::focusedApplicationId() const {
189 for (ApplicationInfo *app : m_runningApplications) {224 for (ApplicationInfo *app : m_runningApplications) {
190 if (app->focused()) {225 if (app->focused()) {
@@ -238,10 +273,16 @@
238273
239 // move app to top of stack274 // move app to top of stack
240 move(m_runningApplications.indexOf(application), 0);275 move(m_runningApplications.indexOf(application), 0);
276 qDebug() << Q_FUNC_INFO << "emitting focusedAppChanged" << focusedApplicationId();
241 Q_EMIT focusedApplicationIdChanged();277 Q_EMIT focusedApplicationIdChanged();
242 return true;278 return true;
243}279}
244280
281void ApplicationManager::activateApplication(const QString &appId)
282{
283 QMetaObject::invokeMethod(this, "focusRequested", Qt::QueuedConnection, Q_ARG(QString, appId));
284}
285
245void ApplicationManager::unfocusCurrentApplication()286void ApplicationManager::unfocusCurrentApplication()
246{287{
247 for (ApplicationInfo *app : m_runningApplications) {288 for (ApplicationInfo *app : m_runningApplications) {
@@ -250,6 +291,7 @@
250 app->setFocused(false);291 app->setFocused(false);
251 }292 }
252 }293 }
294 qDebug() << Q_FUNC_INFO << "emitting focusedAppChanged" << focusedApplicationId();
253 Q_EMIT focusedApplicationIdChanged();295 Q_EMIT focusedApplicationIdChanged();
254}296}
255297
@@ -299,6 +341,7 @@
299 application->setName("Phone");341 application->setName("Phone");
300 application->setIcon(QUrl("phone"));342 application->setIcon(QUrl("phone"));
301 application->setStage(ApplicationInfo::SideStage);343 application->setStage(ApplicationInfo::SideStage);
344 application->setScreenshot(QString("image://application/%1/123456789").arg(application->appId()));
302 generateQmlStrings(application);345 generateQmlStrings(application);
303 m_availableApplications.append(application);346 m_availableApplications.append(application);
304347
@@ -307,6 +350,7 @@
307 application->setName("Camera");350 application->setName("Camera");
308 application->setIcon(QUrl("camera"));351 application->setIcon(QUrl("camera"));
309 application->setFullscreen(true);352 application->setFullscreen(true);
353 application->setScreenshot(QUrl("image://application/phone/123456789"));
310 generateQmlStrings(application);354 generateQmlStrings(application);
311 m_availableApplications.append(application);355 m_availableApplications.append(application);
312356
@@ -314,6 +358,7 @@
314 application->setAppId("gallery-app");358 application->setAppId("gallery-app");
315 application->setName("Gallery");359 application->setName("Gallery");
316 application->setIcon(QUrl("gallery"));360 application->setIcon(QUrl("gallery"));
361 application->setScreenshot(QUrl("image://application/phone/123456789"));
317 generateQmlStrings(application);362 generateQmlStrings(application);
318 m_availableApplications.append(application);363 m_availableApplications.append(application);
319364
@@ -322,6 +367,7 @@
322 application->setName("Facebook");367 application->setName("Facebook");
323 application->setIcon(QUrl("facebook"));368 application->setIcon(QUrl("facebook"));
324 application->setStage(ApplicationInfo::SideStage);369 application->setStage(ApplicationInfo::SideStage);
370 application->setScreenshot(QUrl("image://application/phone/123456789"));
325 generateQmlStrings(application);371 generateQmlStrings(application);
326 m_availableApplications.append(application);372 m_availableApplications.append(application);
327373
@@ -329,6 +375,7 @@
329 application->setAppId("webbrowser-app");375 application->setAppId("webbrowser-app");
330 application->setName("Browser");376 application->setName("Browser");
331 application->setIcon(QUrl("browser"));377 application->setIcon(QUrl("browser"));
378 application->setScreenshot(QUrl("image://application/phone/123456789"));
332 generateQmlStrings(application);379 generateQmlStrings(application);
333 m_availableApplications.append(application);380 m_availableApplications.append(application);
334381
@@ -337,6 +384,7 @@
337 application->setName("Twitter");384 application->setName("Twitter");
338 application->setIcon(QUrl("twitter"));385 application->setIcon(QUrl("twitter"));
339 application->setStage(ApplicationInfo::SideStage);386 application->setStage(ApplicationInfo::SideStage);
387 application->setScreenshot(QUrl("image://application/phone/123456789"));
340 generateQmlStrings(application);388 generateQmlStrings(application);
341 m_availableApplications.append(application);389 m_availableApplications.append(application);
342390
@@ -344,6 +392,7 @@
344 application->setAppId("gmail-webapp");392 application->setAppId("gmail-webapp");
345 application->setName("GMail");393 application->setName("GMail");
346 application->setIcon(QUrl("gmail"));394 application->setIcon(QUrl("gmail"));
395 application->setScreenshot(QUrl("image://application/phone/123456789"));
347 m_availableApplications.append(application);396 m_availableApplications.append(application);
348397
349 application = new ApplicationInfo(this);398 application = new ApplicationInfo(this);
@@ -351,6 +400,7 @@
351 application->setName("Weather");400 application->setName("Weather");
352 application->setIcon(QUrl("weather"));401 application->setIcon(QUrl("weather"));
353 application->setStage(ApplicationInfo::SideStage);402 application->setStage(ApplicationInfo::SideStage);
403 application->setScreenshot(QUrl("image://application/phone/123456789"));
354 generateQmlStrings(application);404 generateQmlStrings(application);
355 m_availableApplications.append(application);405 m_availableApplications.append(application);
356406
@@ -359,6 +409,7 @@
359 application->setName("Notepad");409 application->setName("Notepad");
360 application->setIcon(QUrl("notepad"));410 application->setIcon(QUrl("notepad"));
361 application->setStage(ApplicationInfo::SideStage);411 application->setStage(ApplicationInfo::SideStage);
412 application->setScreenshot(QUrl("image://application/phone/123456789"));
362 m_availableApplications.append(application);413 m_availableApplications.append(application);
363414
364 application = new ApplicationInfo(this);415 application = new ApplicationInfo(this);
@@ -366,6 +417,7 @@
366 application->setName("Calendar");417 application->setName("Calendar");
367 application->setIcon(QUrl("calendar"));418 application->setIcon(QUrl("calendar"));
368 application->setStage(ApplicationInfo::SideStage);419 application->setStage(ApplicationInfo::SideStage);
420 application->setScreenshot(QUrl("image://application/phone/123456789"));
369 m_availableApplications.append(application);421 m_availableApplications.append(application);
370422
371 application = new ApplicationInfo(this);423 application = new ApplicationInfo(this);
@@ -373,18 +425,21 @@
373 application->setName("Media Player");425 application->setName("Media Player");
374 application->setIcon(QUrl("mediaplayer-app"));426 application->setIcon(QUrl("mediaplayer-app"));
375 application->setFullscreen(true);427 application->setFullscreen(true);
428 application->setScreenshot(QUrl("image://application/phone/123456789"));
376 m_availableApplications.append(application);429 m_availableApplications.append(application);
377430
378 application = new ApplicationInfo(this);431 application = new ApplicationInfo(this);
379 application->setAppId("evernote");432 application->setAppId("evernote");
380 application->setName("Evernote");433 application->setName("Evernote");
381 application->setIcon(QUrl("evernote"));434 application->setIcon(QUrl("evernote"));
435 application->setScreenshot(QUrl("image://application/phone/123456789"));
382 m_availableApplications.append(application);436 m_availableApplications.append(application);
383437
384 application = new ApplicationInfo(this);438 application = new ApplicationInfo(this);
385 application->setAppId("map");439 application->setAppId("map");
386 application->setName("Map");440 application->setName("Map");
387 application->setIcon(QUrl("map"));441 application->setIcon(QUrl("map"));
442 application->setScreenshot(QUrl("image://application/phone/123456789"));
388 generateQmlStrings(application);443 generateQmlStrings(application);
389 m_availableApplications.append(application);444 m_availableApplications.append(application);
390445
391446
=== modified file 'tests/mocks/Unity/Application/ApplicationManager.h'
--- tests/mocks/Unity/Application/ApplicationManager.h 2013-10-11 11:37:04 +0000
+++ tests/mocks/Unity/Application/ApplicationManager.h 2014-01-22 10:43:18 +0000
@@ -88,10 +88,12 @@
8888
89 // Application control methods89 // Application control methods
90 Q_INVOKABLE bool focusApplication(const QString &appId) override;90 Q_INVOKABLE bool focusApplication(const QString &appId) override;
91 Q_INVOKABLE void activateApplication(const QString &appId) override;
91 Q_INVOKABLE void unfocusCurrentApplication() override;92 Q_INVOKABLE void unfocusCurrentApplication() override;
92 Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, const QStringList &arguments = QStringList()) override;93 Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, const QStringList &arguments = QStringList()) override;
93 Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, ExecFlags flags, const QStringList &arguments = QStringList());94 Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, ExecFlags flags, const QStringList &arguments = QStringList());
94 Q_INVOKABLE bool stopApplication(const QString &appId) override;95 Q_INVOKABLE bool stopApplication(const QString &appId) override;
96 Q_INVOKABLE void updateScreenshot(const QString &appId) override;
9597
96 QString focusedApplicationId() const override;98 QString focusedApplicationId() const override;
9799
98100
=== added file 'tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp'
--- tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp 1970-01-01 00:00:00 +0000
+++ tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp 2014-01-22 10:43:18 +0000
@@ -0,0 +1,69 @@
1/*
2 * Copyright (C) 2013 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "ApplicationScreenshotProvider.h"
18#include "ApplicationManager.h"
19#include "ApplicationInfo.h"
20
21#include "paths.h"
22
23#include <QDebug>
24#include <QGuiApplication>
25#include <QWindow>
26#include <QQuickWindow>
27
28ApplicationScreenshotProvider::ApplicationScreenshotProvider(ApplicationManager *appManager)
29 : QQuickImageProvider(QQuickImageProvider::Image)
30 , m_appManager(appManager)
31{
32}
33
34QImage ApplicationScreenshotProvider::requestImage(const QString &imageId, QSize * size,
35 const QSize &requestedSize)
36{
37 // We ignore requestedSize here intentionally to avoid keeping scaled copies around
38 Q_UNUSED(requestedSize)
39
40 QString appId = imageId.split('/').first();
41
42 ApplicationInfo* app = static_cast<ApplicationInfo*>(m_appManager->findApplication(appId));
43 if (app == NULL) {
44 qDebug() << "ApplicationScreenshotProvider - app not found:" << appId;
45 return QImage();
46 }
47
48 QString filePath = QString("%1/Dash/graphics/phone/screenshots/%2@12.png").arg(qmlDirectory()).arg(app->icon().toString());
49
50 QImage image;
51 if (!image.load(filePath)) {
52 qDebug() << "failed loading app image" << filePath;
53 }
54
55 QGuiApplication *unity = qobject_cast<QGuiApplication*>(qApp);
56
57 Q_FOREACH (QWindow *win, unity->allWindows()) {
58 QQuickWindow *quickWin = qobject_cast<QQuickWindow*>(win);
59 if (quickWin) {
60 image = image.scaledToWidth(quickWin->width());
61 }
62 }
63
64 size->setWidth(image.width());
65 size->setHeight(image.height());
66 qDebug() << "got image of size" << size->width() << size->height() << requestedSize;
67
68 return image;
69}
070
=== added file 'tests/mocks/Unity/Application/ApplicationScreenshotProvider.h'
--- tests/mocks/Unity/Application/ApplicationScreenshotProvider.h 1970-01-01 00:00:00 +0000
+++ tests/mocks/Unity/Application/ApplicationScreenshotProvider.h 2014-01-22 10:43:18 +0000
@@ -0,0 +1,34 @@
1/*
2 * Copyright (C) 2013 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef APPLICATIONSCREENSHOTPROVIDER_H
18#define APPLICATIONSCREENSHOTPROVIDER_H
19
20#include <QQuickImageProvider>
21
22class ApplicationManager;
23class ApplicationScreenshotProvider : public QQuickImageProvider
24{
25public:
26 explicit ApplicationScreenshotProvider(ApplicationManager *appManager);
27
28 QImage requestImage(const QString &appId, QSize *size, const QSize &requestedSize) override;
29
30private:
31 ApplicationManager* m_appManager;
32};
33
34#endif // APPLICATIONSCREENSHOTPROVIDER_H
035
=== modified file 'tests/mocks/Unity/Application/CMakeLists.txt'
--- tests/mocks/Unity/Application/CMakeLists.txt 2013-12-13 01:02:53 +0000
+++ tests/mocks/Unity/Application/CMakeLists.txt 2014-01-22 10:43:18 +0000
@@ -5,6 +5,7 @@
5 ApplicationInfo.cpp5 ApplicationInfo.cpp
6 ApplicationImage.cpp6 ApplicationImage.cpp
7 ApplicationManager.cpp7 ApplicationManager.cpp
8 ApplicationScreenshotProvider.cpp
8 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h9 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
9 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h10 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
10)11)
1112
=== modified file 'tests/mocks/Unity/Application/plugin.cpp'
--- tests/mocks/Unity/Application/plugin.cpp 2013-09-11 15:33:02 +0000
+++ tests/mocks/Unity/Application/plugin.cpp 2014-01-22 10:43:18 +0000
@@ -18,13 +18,20 @@
18#include "ApplicationInfo.h"18#include "ApplicationInfo.h"
19#include "ApplicationImage.h"19#include "ApplicationImage.h"
20#include "ApplicationManager.h"20#include "ApplicationManager.h"
21#include "ApplicationScreenshotProvider.h"
2122
22#include <qqml.h>23#include <qqml.h>
24#include <QQmlEngine>
25
26ApplicationManager *s_appManager = 0;
2327
24static QObject* applicationManagerSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) {28static QObject* applicationManagerSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) {
25 Q_UNUSED(engine);29 Q_UNUSED(engine);
26 Q_UNUSED(scriptEngine);30 Q_UNUSED(scriptEngine);
27 return new ApplicationManager();31 if (!s_appManager) {
32 s_appManager = new ApplicationManager();
33 }
34 return s_appManager;
28}35}
2936
30void FakeUnityApplicationQmlPlugin::registerTypes(const char *uri)37void FakeUnityApplicationQmlPlugin::registerTypes(const char *uri)
@@ -37,3 +44,11 @@
3744
38 qmlRegisterType<ApplicationImage>(uri, 0, 1, "ApplicationImage");45 qmlRegisterType<ApplicationImage>(uri, 0, 1, "ApplicationImage");
39}46}
47
48void FakeUnityApplicationQmlPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
49{
50 QQmlExtensionPlugin::initializeEngine(engine, uri);
51
52 ApplicationManager* appManager = static_cast<ApplicationManager*>(applicationManagerSingleton(engine, NULL));
53 engine->addImageProvider(QLatin1String("application"), new ApplicationScreenshotProvider(appManager));
54}
4055
=== modified file 'tests/mocks/Unity/Application/plugin.h'
--- tests/mocks/Unity/Application/plugin.h 2013-09-04 13:42:27 +0000
+++ tests/mocks/Unity/Application/plugin.h 2014-01-22 10:43:18 +0000
@@ -25,6 +25,7 @@
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26public:26public:
27 void registerTypes(const char *uri);27 void registerTypes(const char *uri);
28 void initializeEngine(QQmlEngine *engine, const char *uri);
28};29};
2930
30#endif31#endif
3132
=== modified file 'tests/plugins/Unity/Launcher/launchermodeltest.cpp'
--- tests/plugins/Unity/Launcher/launchermodeltest.cpp 2013-09-16 17:59:13 +0000
+++ tests/plugins/Unity/Launcher/launchermodeltest.cpp 2014-01-22 10:43:18 +0000
@@ -39,6 +39,7 @@
39 ApplicationInfoInterface::Stage stage() const { return ApplicationInfoInterface::MainStage; }39 ApplicationInfoInterface::Stage stage() const { return ApplicationInfoInterface::MainStage; }
40 ApplicationInfoInterface::State state() const { return ApplicationInfoInterface::Running; }40 ApplicationInfoInterface::State state() const { return ApplicationInfoInterface::Running; }
41 bool focused() const { return m_focused; }41 bool focused() const { return m_focused; }
42 QUrl screenshot() const { return QUrl(); }
4243
43 // Methods used for mocking (not in the interface)44 // Methods used for mocking (not in the interface)
44 void setFocused(bool focused) { m_focused = focused; Q_EMIT focusedChanged(focused); }45 void setFocused(bool focused) { m_focused = focused; Q_EMIT focusedChanged(focused); }
@@ -92,6 +93,8 @@
92 m_list.takeAt(index)->deleteLater();93 m_list.takeAt(index)->deleteLater();
93 endRemoveRows();94 endRemoveRows();
94 }95 }
96 void updateScreenshot(const QString &appId) { Q_UNUSED(appId); }
97 void activateApplication(const QString &appId) { Q_UNUSED(appId); }
9598
96private:99private:
97 QList<MockApp*> m_list;100 QList<MockApp*> m_list;
98101
=== modified file 'tests/qmltests/tst_Shell.qml'
--- tests/qmltests/tst_Shell.qml 2014-01-16 12:37:57 +0000
+++ tests/qmltests/tst_Shell.qml 2014-01-22 10:43:18 +0000
@@ -117,6 +117,7 @@
117 while (apps.count > 0) {117 while (apps.count > 0) {
118 ApplicationManager.stopApplication(apps.get(0).appId);118 ApplicationManager.stopApplication(apps.get(0).appId);
119 }119 }
120 compare(ApplicationManager.count, 0)
120 }121 }
121122
122 /*123 /*
@@ -182,28 +183,34 @@
182 function test_suspend() {183 function test_suspend() {
183 var greeter = findChild(shell, "greeter");184 var greeter = findChild(shell, "greeter");
184185
186 print("step1")
185 // Launch an app from the launcher187 // Launch an app from the launcher
186 dragLauncherIntoView();188 dragLauncherIntoView();
187 tapOnAppIconInLauncher();189 tapOnAppIconInLauncher();
188 waitUntilApplicationWindowIsFullyVisible();190 waitUntilApplicationWindowIsFullyVisible();
189191
192 print("step2")
190 var mainApp = ApplicationManager.focusedApplicationId;193 var mainApp = ApplicationManager.focusedApplicationId;
191 verify(mainApp != "");194 verify(mainApp != "");
192195
196 print("step3")
193 // Try to suspend while proximity is engaged...197 // Try to suspend while proximity is engaged...
194 Powerd.displayPowerStateChange(Powerd.Off, Powerd.UseProximity);198 Powerd.displayPowerStateChange(Powerd.Off, Powerd.UseProximity);
195 tryCompare(greeter, "showProgress", 0);199 tryCompare(greeter, "showProgress", 0);
196200
201 print("step4")
197 // Now really suspend202 // Now really suspend
198 Powerd.displayPowerStateChange(Powerd.Off, 0);203 Powerd.displayPowerStateChange(Powerd.Off, 0);
199 tryCompare(greeter, "showProgress", 1);204 tryCompare(greeter, "showProgress", 1);
200 tryCompare(ApplicationManager, "focusedApplicationId", "");205 tryCompare(ApplicationManager, "focusedApplicationId", "");
201206
207 print("step5")
202 // And wake up208 // And wake up
203 Powerd.displayPowerStateChange(Powerd.On, 0);209 Powerd.displayPowerStateChange(Powerd.On, 0);
204 tryCompare(ApplicationManager, "focusedApplicationId", "");210 tryCompare(ApplicationManager, "focusedApplicationId", "");
205 tryCompare(greeter, "showProgress", 1);211 tryCompare(greeter, "showProgress", 1);
206212
213 print("step6")
207 // Swipe away greeter to focus app214 // Swipe away greeter to focus app
208 swipeAwayGreeter();215 swipeAwayGreeter();
209 tryCompare(ApplicationManager, "focusedApplicationId", mainApp);216 tryCompare(ApplicationManager, "focusedApplicationId", mainApp);
@@ -503,6 +510,8 @@
503510
504 function test_DashShown(data) {511 function test_DashShown(data) {
505512
513 print("step1")
514 // greeter: false,
506 if (data.greeter) {515 if (data.greeter) {
507 // Swipe the greeter in516 // Swipe the greeter in
508 var greeter = findChild(shell, "greeter");517 var greeter = findChild(shell, "greeter");
@@ -510,21 +519,31 @@
510 tryCompare(greeter, "showProgress", 1);519 tryCompare(greeter, "showProgress", 1);
511 }520 }
512521
522 print("step2")
523 //app: false,
513 if (data.app) {524 if (data.app) {
514 dragLauncherIntoView();525 dragLauncherIntoView();
515 tapOnAppIconInLauncher();526 tapOnAppIconInLauncher();
516 }527 }
517528
529 print("step3")
530 // launcher: true,
518 if (data.launcher) {531 if (data.launcher) {
519 dragLauncherIntoView();532 dragLauncherIntoView();
520 }533 }
521534
535 print("step4")
536 // indicators: false,
522 if (data.indicators) {537 if (data.indicators) {
523 showIndicators();538 showIndicators();
524 }539 }
525540
541 print("step5")
542 //expectedShown: true},
526 var dash = findChild(shell, "dash");543 var dash = findChild(shell, "dash");
544 print("step6", dash, dash.shown, data.expectedShown)
527 tryCompare(dash, "shown", data.expectedShown);545 tryCompare(dash, "shown", data.expectedShown);
546 print("step7")
528 }547 }
529548
530 function test_searchIndicatorHidesOnAppFocus() {549 function test_searchIndicatorHidesOnAppFocus() {

Subscribers

People subscribed via source and target branches